aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThierry Strudel <tstrudel@google.com>2016-06-21 16:14:16 -0700
committerThierry Strudel <tstrudel@google.com>2016-06-21 23:27:56 +0000
commit02be3a1bdda108fbb98239504c839755a9fff8b2 (patch)
treec60f580acf87903e975109911a31621e02819f1d
parent8451c8e5da81409d6aad453dfb313734a130e512 (diff)
parentcbe2c07d79668a2b53a43270bb0e8bd52cad0910 (diff)
Merge branch 'android-msm-shamu-3.10-security-next' into android-msm-shamu-3.10android-n-preview-5_r0.5
Merge security-next into master @ 8451c8e for August 2016.2
-rw-r--r--Documentation/sysctl/kernel.txt42
-rw-r--r--android/configs/android-base.cfg6
-rw-r--r--arch/arm/configs/shamu_defconfig1
-rw-r--r--drivers/gpu/msm/adreno.c2
-rw-r--r--drivers/gpu/msm/kgsl.c60
-rw-r--r--drivers/net/usb/usbnet.c7
-rw-r--r--drivers/net/wireless/bcmdhd/bcmevent.c120
-rw-r--r--drivers/net/wireless/bcmdhd/dhd.h1
-rw-r--r--drivers/net/wireless/bcmdhd/dhd_common.c89
-rw-r--r--drivers/net/wireless/bcmdhd/dhd_linux.c26
-rw-r--r--drivers/net/wireless/bcmdhd/include/proto/bcmevent.h15
-rw-r--r--drivers/usb/core/devio.c9
-rw-r--r--include/linux/ipv6.h2
-rw-r--r--include/linux/perf_event.h5
-rw-r--r--include/net/ipv6.h21
-rw-r--r--kernel/events/core.c8
-rw-r--r--net/core/rtnetlink.c16
-rw-r--r--net/dccp/ipv6.c33
-rw-r--r--net/ipv6/af_inet6.c13
-rw-r--r--net/ipv6/datagram.c4
-rw-r--r--net/ipv6/exthdrs.c3
-rw-r--r--net/ipv6/inet6_connection_sock.c11
-rw-r--r--net/ipv6/ipv6_sockglue.c36
-rw-r--r--net/ipv6/raw.c8
-rw-r--r--net/ipv6/syncookies.c2
-rw-r--r--net/ipv6/tcp_ipv6.c28
-rw-r--r--net/ipv6/udp.c8
-rw-r--r--net/l2tp/l2tp_ip6.c8
-rw-r--r--net/socket.c4
-rw-r--r--security/Kconfig9
-rw-r--r--sound/core/compress_offload.c2
-rw-r--r--sound/core/timer.c35
-rw-r--r--tools/perf/util/evsel.c17
33 files changed, 481 insertions, 170 deletions
diff --git a/Documentation/sysctl/kernel.txt b/Documentation/sysctl/kernel.txt
index a7b1d7643839..2b0234beeee1 100644
--- a/Documentation/sysctl/kernel.txt
+++ b/Documentation/sysctl/kernel.txt
@@ -51,8 +51,9 @@ show up in /proc/sys/kernel:
- overflowuid
- panic
- panic_on_oops
-- panic_on_unrecovered_nmi
- panic_on_stackoverflow
+- panic_on_unrecovered_nmi
+- perf_event_paranoid
- pid_max
- powersave-nap [ PPC only ]
- printk
@@ -427,19 +428,6 @@ the recommended setting is 60.
==============================================================
-panic_on_unrecovered_nmi:
-
-The default Linux behaviour on an NMI of either memory or unknown is
-to continue operation. For many environments such as scientific
-computing it is preferable that the box is taken out and the error
-dealt with than an uncorrected parity/ECC error get propagated.
-
-A small number of systems do generate NMI's for bizarre random reasons
-such as power management so the default is off. That sysctl works like
-the existing panic controls already in that directory.
-
-==============================================================
-
panic_on_oops:
Controls the kernel's behaviour when an oops or BUG is encountered.
@@ -463,6 +451,32 @@ This file shows up if CONFIG_DEBUG_STACKOVERFLOW is enabled.
==============================================================
+panic_on_unrecovered_nmi:
+
+The default Linux behaviour on an NMI of either memory or unknown is
+to continue operation. For many environments such as scientific
+computing it is preferable that the box is taken out and the error
+dealt with than an uncorrected parity/ECC error get propagated.
+
+A small number of systems do generate NMI's for bizarre random reasons
+such as power management so the default is off. That sysctl works like
+the existing panic controls already in that directory.
+
+==============================================================
+
+perf_event_paranoid:
+
+Controls use of the performance events system by unprivileged
+users (without CAP_SYS_ADMIN). The default value is 3 if
+CONFIG_SECURITY_PERF_EVENTS_RESTRICT is set, or 1 otherwise.
+
+ -1: Allow use of (almost) all events by all users
+>=0: Disallow raw tracepoint access by users without CAP_IOC_LOCK
+>=1: Disallow CPU event access by users without CAP_SYS_ADMIN
+>=2: Disallow kernel profiling by users without CAP_SYS_ADMIN
+>=3: Disallow all event access by users without CAP_SYS_ADMIN
+
+==============================================================
pid_max:
diff --git a/android/configs/android-base.cfg b/android/configs/android-base.cfg
index 6d5e2f4b2abc..f20b6a9aa90d 100644
--- a/android/configs/android-base.cfg
+++ b/android/configs/android-base.cfg
@@ -123,6 +123,12 @@ CONFIG_PREEMPT=y
CONFIG_RESOURCE_COUNTERS=y
CONFIG_RTC_CLASS=y
CONFIG_RT_GROUP_SCHED=y
+CONFIG_SECURITY=y
+CONFIG_SECURITY_NETWORK=y
+CONFIG_SECURITY_PERF_EVENTS_RESTRICT=y
+CONFIG_SECURITY_SELINUX=y
+CONFIG_SND=y
+CONFIG_SOUND=y
CONFIG_STAGING=y
CONFIG_SWITCH=y
CONFIG_SYNC=y
diff --git a/arch/arm/configs/shamu_defconfig b/arch/arm/configs/shamu_defconfig
index 059982182e33..558714ebd51f 100644
--- a/arch/arm/configs/shamu_defconfig
+++ b/arch/arm/configs/shamu_defconfig
@@ -600,6 +600,7 @@ CONFIG_DYNAMIC_DEBUG=y
CONFIG_DEBUG_USER=y
CONFIG_PID_IN_CONTEXTIDR=y
CONFIG_KEYS=y
+CONFIG_SECURITY_PERF_EVENTS_RESTRICT=y
CONFIG_SECURITY=y
CONFIG_SECURITY_NETWORK=y
CONFIG_SECURITY_SELINUX=y
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index 628eeaf847dc..e457be0fa95e 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -536,7 +536,7 @@ int adreno_perfcounter_query_group(struct adreno_device *adreno_dev,
return 0;
}
- t = min_t(int, group->reg_count, count);
+ t = min_t(unsigned int, group->reg_count, count);
buf = kmalloc(t * sizeof(unsigned int), GFP_KERNEL);
if (buf == NULL) {
diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c
index 863782a430bc..67d264431dc1 100644
--- a/drivers/gpu/msm/kgsl.c
+++ b/drivers/gpu/msm/kgsl.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008-2014, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2008-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
@@ -254,18 +254,13 @@ kgsl_mem_entry_destroy(struct kref *kref)
EXPORT_SYMBOL(kgsl_mem_entry_destroy);
/**
- * kgsl_mem_entry_track_gpuaddr - Insert a mem_entry in the address tree and
- * assign it with a gpu address space before insertion
+ * kgsl_mem_entry_track_gpuaddr - Get the entry gpu address space before
+ * insertion to the process
* @process: the process that owns the memory
* @entry: the memory entry
*
- * @returns - 0 on succcess else error code
+ * @returns - 0 on success else error code
*
- * Insert the kgsl_mem_entry in to the rb_tree for searching by GPU address.
- * The assignment of gpu address and insertion into list needs to
- * happen with the memory lock held to avoid race conditions between
- * gpu address being selected and some other thread looking through the
- * rb list in search of memory based on gpuaddr
* This function should be called with processes memory spinlock held
*/
static int
@@ -273,8 +268,6 @@ kgsl_mem_entry_track_gpuaddr(struct kgsl_process_private *process,
struct kgsl_mem_entry *entry)
{
int ret = 0;
- struct rb_node **node;
- struct rb_node *parent = NULL;
struct kgsl_pagetable *pagetable = process->pagetable;
size_t size = entry->memdesc.size;
@@ -295,11 +288,22 @@ kgsl_mem_entry_track_gpuaddr(struct kgsl_process_private *process,
goto done;
}
ret = kgsl_mmu_get_gpuaddr(pagetable, &entry->memdesc);
- if (ret)
- goto done;
- node = &process->mem_rb.rb_node;
+done:
+ return ret;
+}
+static void kgsl_mem_entry_commit_mem_list(struct kgsl_process_private *process,
+ struct kgsl_mem_entry *entry)
+{
+ struct rb_node **node;
+ struct rb_node *parent = NULL;
+
+ if (!entry->memdesc.gpuaddr)
+ return;
+
+ /* Insert mem entry in mem_rb tree */
+ node = &process->mem_rb.rb_node;
while (*node) {
struct kgsl_mem_entry *cur;
@@ -314,9 +318,20 @@ kgsl_mem_entry_track_gpuaddr(struct kgsl_process_private *process,
rb_link_node(&entry->node, parent, node);
rb_insert_color(&entry->node, &process->mem_rb);
+}
-done:
- return ret;
+static void kgsl_mem_entry_commit_process(struct kgsl_process_private *process,
+ struct kgsl_mem_entry *entry)
+{
+ if (!entry)
+ return;
+
+ spin_lock(&entry->priv->mem_lock);
+ /* Insert mem entry in mem_rb tree */
+ kgsl_mem_entry_commit_mem_list(process, entry);
+ /* Replace mem entry in mem_idr using id */
+ idr_replace(&entry->priv->mem_idr, entry, entry->id);
+ spin_unlock(&entry->priv->mem_lock);
}
/**
@@ -364,7 +379,8 @@ kgsl_mem_entry_attach_process(struct kgsl_mem_entry *entry,
return -EBADF;
idr_preload(GFP_KERNEL);
spin_lock(&process->mem_lock);
- id = idr_alloc(&process->mem_idr, entry, 1, 0, GFP_NOWAIT);
+ /* Allocate the ID but don't attach the pointer just yet */
+ id = idr_alloc(&process->mem_idr, NULL, 1, 0, GFP_NOWAIT);
spin_unlock(&process->mem_lock);
idr_preload_end();
@@ -2994,6 +3010,7 @@ long kgsl_ioctl_map_user_mem(struct kgsl_device_private *dev_priv,
trace_kgsl_mem_map(entry, param->fd);
+ kgsl_mem_entry_commit_process(private, entry);
return result;
error_attach:
@@ -3316,6 +3333,8 @@ long kgsl_ioctl_gpumem_alloc(struct kgsl_device_private *dev_priv,
param->gpuaddr = entry->memdesc.gpuaddr;
param->size = entry->memdesc.size;
param->flags = entry->memdesc.flags;
+
+ kgsl_mem_entry_commit_process(private, entry);
return result;
err:
kgsl_sharedmem_free(&entry->memdesc);
@@ -3353,6 +3372,8 @@ long kgsl_ioctl_gpumem_alloc_id(struct kgsl_device_private *dev_priv,
param->size = entry->memdesc.size;
param->mmapsize = kgsl_memdesc_mmapsize(&entry->memdesc);
param->gpuaddr = entry->memdesc.gpuaddr;
+
+ kgsl_mem_entry_commit_process(private, entry);
return result;
err:
if (entry)
@@ -3871,6 +3892,11 @@ static int kgsl_check_gpu_addr_collision(
spin_lock(&private->mem_lock);
kgsl_mem_entry_untrack_gpuaddr(private, entry);
spin_unlock(&private->mem_lock);
+ } else {
+ /* Insert mem entry in mem_rb tree */
+ spin_lock(&private->mem_lock);
+ kgsl_mem_entry_commit_mem_list(private, entry);
+ spin_unlock(&private->mem_lock);
}
} else {
trace_kgsl_mem_unmapped_area_collision(entry, addr, len,
diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c
index 24b8a8568bcb..54e83993e759 100644
--- a/drivers/net/usb/usbnet.c
+++ b/drivers/net/usb/usbnet.c
@@ -1639,6 +1639,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;
diff --git a/drivers/net/wireless/bcmdhd/bcmevent.c b/drivers/net/wireless/bcmdhd/bcmevent.c
index c7a902d7c60e..b85f111bce18 100644
--- a/drivers/net/wireless/bcmdhd/bcmevent.c
+++ b/drivers/net/wireless/bcmdhd/bcmevent.c
@@ -25,9 +25,12 @@
#include <typedefs.h>
#include <bcmutils.h>
+#include <bcmendian.h>
#include <proto/ethernet.h>
#include <proto/bcmeth.h>
#include <proto/bcmevent.h>
+#include <proto/dnglevent.h>
+#include <proto/802.11.h>
/* Table of event name strings for UIs and debugging dumps */
@@ -192,3 +195,120 @@ const char *bcmevent_get_name(uint event_type)
*/
return ((event_name) ? event_name : "Unknown Event");
}
+
+/*
+ * Validate if the event is proper and if valid copy event header to event.
+ * If proper event pointer is passed, to just validate, pass NULL to event.
+ *
+ * Return values are
+ * BCME_OK - It is a BRCM event or BRCM dongle event
+ * BCME_NOTFOUND - Not BRCM, not an event, may be okay
+ * BCME_BADLEN - Bad length, should not process, just drop
+ */
+int
+is_wlc_event_frame(void *pktdata, uint pktlen, uint16 exp_usr_subtype,
+ bcm_event_msg_u_t *out_event)
+{
+ uint16 len;
+ uint16 subtype;
+ uint16 usr_subtype;
+ bcm_event_t *bcm_event;
+ uint8 *pktend;
+ int err = BCME_OK;
+
+ pktend = (uint8 *)pktdata + pktlen;
+ bcm_event = (bcm_event_t *)pktdata;
+
+ /* only care about 16-bit subtype / length versions */
+ if ((uint8 *)&bcm_event->bcm_hdr < pktend) {
+ uint8 short_subtype = *(uint8 *)&bcm_event->bcm_hdr;
+ if (!(short_subtype & 0x80)) {
+ err = BCME_NOTFOUND;
+ goto done;
+ }
+ }
+
+ /* must have both ether_header and bcmeth_hdr */
+ if (pktlen < OFFSETOF(bcm_event_t, event)) {
+ err = BCME_BADLEN;
+ goto done;
+ }
+
+ /* check length in bcmeth_hdr */
+ len = ntoh16_ua((void *)&bcm_event->bcm_hdr.length);
+ if (((uint8 *)&bcm_event->bcm_hdr.version + len) > pktend) {
+ err = BCME_BADLEN;
+ goto done;
+ }
+
+ /* match on subtype, oui and usr subtype for BRCM events */
+ subtype = ntoh16_ua((void *)&bcm_event->bcm_hdr.subtype);
+ if (subtype != BCMILCP_SUBTYPE_VENDOR_LONG) {
+ err = BCME_NOTFOUND;
+ goto done;
+ }
+
+ if (bcmp(BRCM_OUI, &bcm_event->bcm_hdr.oui[0], DOT11_OUI_LEN)) {
+ err = BCME_NOTFOUND;
+ goto done;
+ }
+
+ /* if it is a bcm_event or bcm_dngl_event_t, validate it */
+ usr_subtype = ntoh16_ua((void *)&bcm_event->bcm_hdr.usr_subtype);
+ switch (usr_subtype) {
+ case BCMILCP_BCM_SUBTYPE_EVENT:
+ if (pktlen < sizeof(bcm_event_t)) {
+ err = BCME_BADLEN;
+ goto done;
+ }
+
+ len = sizeof(bcm_event_t) + ntoh32_ua((void *)&bcm_event->event.datalen);
+ if ((uint8 *)pktdata + len > pktend) {
+ err = BCME_BADLEN;
+ goto done;
+ }
+
+ if (exp_usr_subtype && (exp_usr_subtype != usr_subtype)) {
+ err = BCME_NOTFOUND;
+ goto done;
+ }
+
+ if (out_event) {
+ /* ensure BRCM event pkt aligned */
+ memcpy(&out_event->event, &bcm_event->event, sizeof(wl_event_msg_t));
+ }
+
+ break;
+ case BCMILCP_BCM_SUBTYPE_DNGLEVENT:
+ if (pktlen < sizeof(bcm_dngl_event_t)) {
+ err = BCME_BADLEN;
+ goto done;
+ }
+
+ len = sizeof(bcm_dngl_event_t) +
+ ntoh16_ua((void *)&((bcm_dngl_event_t *)pktdata)->dngl_event.datalen);
+ if ((uint8 *)pktdata + len > pktend) {
+ err = BCME_BADLEN;
+ goto done;
+ }
+
+ if (exp_usr_subtype && (exp_usr_subtype != usr_subtype)) {
+ err = BCME_NOTFOUND;
+ goto done;
+ }
+
+ if (out_event) {
+ /* ensure BRCM dngl event pkt aligned */
+ memcpy(&out_event->dngl_event, &((bcm_dngl_event_t *)pktdata)->dngl_event,
+ sizeof(bcm_dngl_event_msg_t));
+ }
+
+ break;
+ default:
+ err = BCME_NOTFOUND;
+ goto done;
+ }
+
+done:
+ return err;
+}
diff --git a/drivers/net/wireless/bcmdhd/dhd.h b/drivers/net/wireless/bcmdhd/dhd.h
index f2cd8e646124..59e3148fa79d 100644
--- a/drivers/net/wireless/bcmdhd/dhd.h
+++ b/drivers/net/wireless/bcmdhd/dhd.h
@@ -812,6 +812,7 @@ extern int net_os_send_hang_message(struct net_device *dev);
extern int wl_host_event(dhd_pub_t *dhd_pub, int *idx, void *pktdata, size_t pktlen,
wl_event_msg_t *, void **data_ptr, void *);
extern void wl_event_to_host_order(wl_event_msg_t * evt);
+extern int wl_host_event_get_data(void *pktdata, uint pktlen, bcm_event_msg_u_t *evu);
extern int dhd_wl_ioctl(dhd_pub_t *dhd_pub, int ifindex, wl_ioctl_t *ioc, void *buf, int len);
extern int dhd_wl_ioctl_cmd(dhd_pub_t *dhd_pub, int cmd, void *arg, int len, uint8 set,
diff --git a/drivers/net/wireless/bcmdhd/dhd_common.c b/drivers/net/wireless/bcmdhd/dhd_common.c
index 235c4019e4ec..fc601d37263b 100644
--- a/drivers/net/wireless/bcmdhd/dhd_common.c
+++ b/drivers/net/wireless/bcmdhd/dhd_common.c
@@ -107,8 +107,11 @@ extern int dhd_change_mtu(dhd_pub_t *dhd, int new_mtu, int ifidx);
extern int dhd_get_concurrent_capabilites(dhd_pub_t *dhd);
#endif
extern int dhd_socram_dump(struct dhd_bus *bus);
-static void dngl_host_event_process(dhd_pub_t *dhdp, bcm_dngl_event_t *event, size_t pktlen);
-static int dngl_host_event(dhd_pub_t *dhdp, void *pktdata, size_t pktlen);
+static void dngl_host_event_process(dhd_pub_t *dhdp, bcm_dngl_event_t *event,
+ bcm_dngl_event_msg_t *dngl_event, size_t pktlen);
+static int dngl_host_event(dhd_pub_t *dhdp, void *pktdata, bcm_dngl_event_msg_t *dngl_event,
+ size_t pktlen);
+
bool ap_cfg_running = FALSE;
bool ap_fw_loaded = FALSE;
@@ -1377,27 +1380,18 @@ wl_show_host_event(dhd_pub_t *dhd_pub, wl_event_msg_t *event, void *event_data,
/* Check whether packet is a BRCM dngl event pkt. If it is, process event data. */
int
-dngl_host_event(dhd_pub_t *dhdp, void *pktdata, size_t pktlen)
+dngl_host_event(dhd_pub_t *dhdp, void *pktdata, bcm_dngl_event_msg_t *dngl_event, size_t pktlen)
{
bcm_dngl_event_t *pvt_data = (bcm_dngl_event_t *)pktdata;
- if (bcmp(BRCM_OUI, &pvt_data->bcm_hdr.oui[0], DOT11_OUI_LEN)) {
- DHD_ERROR(("%s: mismatched OUI, bailing\n", __FUNCTION__));
- return BCME_ERROR;
- }
- /* Check to see if this is a DNGL event */
- if (ntoh16_ua((void *)&pvt_data->bcm_hdr.usr_subtype) ==
- BCMILCP_BCM_SUBTYPE_DNGLEVENT) {
- dngl_host_event_process(dhdp, pvt_data, pktlen);
- return BCME_OK;
- }
- return BCME_ERROR;
+ dngl_host_event_process(dhdp, pvt_data, dngl_event, pktlen);
+ return BCME_OK;
}
void
-dngl_host_event_process(dhd_pub_t *dhdp, bcm_dngl_event_t *event, size_t pktlen)
+dngl_host_event_process(dhd_pub_t *dhdp, bcm_dngl_event_t *event,
+ bcm_dngl_event_msg_t *dngl_event, size_t pktlen)
{
- bcm_dngl_event_msg_t *dngl_event = &event->dngl_event;
uint8 *p = (uint8 *)(event + 1);
uint16 type = ntoh16_ua((void *)&dngl_event->event_type);
uint16 datalen = ntoh16_ua((void *)&dngl_event->datalen);
@@ -1497,6 +1491,21 @@ dngl_host_event_process(dhd_pub_t *dhdp, bcm_dngl_event_t *event, size_t pktlen)
break;
}
}
+
+/* Check whether packet is a BRCM event pkt. If it is, record event data. */
+int wl_host_event_get_data(void *pktdata, uint pktlen, bcm_event_msg_u_t *evu)
+{
+ int ret;
+
+ ret = is_wlc_event_frame(pktdata, pktlen, 0, evu);
+ if (ret != BCME_OK) {
+ DHD_ERROR(("%s: Invalid event frame, err = %d\n",
+ __FUNCTION__, ret));
+ }
+
+ return ret;
+}
+
int wl_host_event(dhd_pub_t *dhd_pub, int *ifidx, void *pktdata, size_t pktlen,
wl_event_msg_t *event, void **data_ptr, void *raw_event)
{
@@ -1507,45 +1516,41 @@ int wl_host_event(dhd_pub_t *dhd_pub, int *ifidx, void *pktdata, size_t pktlen,
uint16 flags;
int evlen;
int hostidx;
+ int ret;
+ uint16 usr_subtype;
+ bcm_event_msg_u_t evu;
- /* If it is a DNGL event process it first */
- if (dngl_host_event(dhd_pub, pktdata, pktlen) == BCME_OK) {
- return BCME_OK;
- }
-
- if (bcmp(BRCM_OUI, &pvt_data->bcm_hdr.oui[0], DOT11_OUI_LEN)) {
- DHD_ERROR(("%s: mismatched OUI, bailing\n", __FUNCTION__));
- return (BCME_ERROR);
+ ret = wl_host_event_get_data(pktdata, pktlen, &evu);
+ if (ret != BCME_OK) {
+ return ret;
}
- /* BRCM event pkt may be unaligned - use xxx_ua to load user_subtype. */
- if (ntoh16_ua((void *)&pvt_data->bcm_hdr.usr_subtype) != BCMILCP_BCM_SUBTYPE_EVENT) {
- DHD_ERROR(("%s: mismatched subtype, bailing\n", __FUNCTION__));
- return (BCME_ERROR);
- }
+ usr_subtype = ntoh16_ua((void *)&pvt_data->bcm_hdr.usr_subtype);
+ switch (usr_subtype) {
+ case BCMILCP_BCM_SUBTYPE_EVENT:
+ memcpy(event, &evu.event, sizeof(wl_event_msg_t));
+ *data_ptr = &pvt_data[1];
+ break;
- if (pktlen < sizeof(bcm_event_t))
- return (BCME_ERROR);
+ case BCMILCP_BCM_SUBTYPE_DNGLEVENT:
+ /* If it is a DNGL event process it first */
+ dngl_host_event(dhd_pub, pktdata, &evu.dngl_event, pktlen);
- *data_ptr = &pvt_data[1];
- event_data = *data_ptr;
+ /* Return error purposely to prevent DNGL event being processed as BRCM event */
+ return BCME_ERROR;
+ default:
+ return BCME_NOTFOUND;
+ }
- /* memcpy since BRCM event pkt may be unaligned. */
- memcpy(event, &pvt_data->event, sizeof(wl_event_msg_t));
+ /* start wl_event_msg process */
+ event_data = *data_ptr;
type = ntoh32_ua((void *)&event->event_type);
flags = ntoh16_ua((void *)&event->flags);
status = ntoh32_ua((void *)&event->status);
-
datalen = ntoh32_ua((void *)&event->datalen);
- if (datalen > pktlen)
- return (BCME_ERROR);
-
evlen = datalen + sizeof(bcm_event_t);
- if (evlen > pktlen) {
- return BCME_ERROR;
- }
/* find equivalent host index for event ifidx */
hostidx = dhd_ifidx2hostidx(dhd_pub->info, event->ifidx);
diff --git a/drivers/net/wireless/bcmdhd/dhd_linux.c b/drivers/net/wireless/bcmdhd/dhd_linux.c
index aac8cf5a5cfd..1e236b976f8b 100644
--- a/drivers/net/wireless/bcmdhd/dhd_linux.c
+++ b/drivers/net/wireless/bcmdhd/dhd_linux.c
@@ -3021,16 +3021,23 @@ dhd_rx_frame(dhd_pub_t *dhdp, int ifidx, void *pktbuf, int numpkt, uint8 chan,
/* Process special event packets and then discard them */
memset(&event, 0, sizeof(event));
if (ntoh16(skb->protocol) == ETHER_TYPE_BRCM) {
- dhd_wl_host_event(dhd, &ifidx,
+ int ret_event;
+
+ ret_event = dhd_wl_host_event(dhd, &ifidx,
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22)
skb_mac_header(skb),
#else
skb->mac.raw,
#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22) */
- len - 2,
+ len,
&event,
&data);
+ if (ret_event != BCME_OK) {
+ PKTFREE(dhdp->osh, pktbuf, FALSE);
+ continue;
+ }
+
wl_event_to_host_order(&event);
if (!tout_ctrl)
tout_ctrl = DHD_PACKET_TIMEOUT_MS;
@@ -7447,11 +7454,11 @@ dhd_wl_host_event(dhd_info_t *dhd, int *ifidx, void *pktdata, size_t pktlen,
ASSERT(dhd != NULL);
#ifdef SHOW_LOGTRACE
- bcmerror = wl_host_event(&dhd->pub, ifidx, pktdata, pktlen,
- event, data, &dhd->event_data);
+ bcmerror = wl_host_event(&dhd->pub, ifidx, pktdata, pktlen,
+ event, data, &dhd->event_data);
#else
- bcmerror = wl_host_event(&dhd->pub, ifidx, pktdata, pktlen,
- event, data, NULL);
+ bcmerror = wl_host_event(&dhd->pub, ifidx, pktdata, pktlen,
+ event, data, NULL);
#endif /* SHOW_LOGTRACE */
if (bcmerror != BCME_OK)
@@ -7462,12 +7469,11 @@ dhd_wl_host_event(dhd_info_t *dhd, int *ifidx, void *pktdata, size_t pktlen,
/*
* Wireless ext is on primary interface only
*/
-
- ASSERT(dhd->iflist[*ifidx] != NULL);
- ASSERT(dhd->iflist[*ifidx]->net != NULL);
+ ASSERT(dhd->iflist[*ifidx] != NULL);
+ ASSERT(dhd->iflist[*ifidx]->net != NULL);
if (dhd->iflist[*ifidx]->net) {
- wl_iw_event(dhd->iflist[*ifidx]->net, event, *data);
+ wl_iw_event(dhd->iflist[*ifidx]->net, event, *data);
}
}
#endif /* defined(WL_WIRELESS_EXT) */
diff --git a/drivers/net/wireless/bcmdhd/include/proto/bcmevent.h b/drivers/net/wireless/bcmdhd/include/proto/bcmevent.h
index 56cf83b32eaf..098da15f45f7 100644
--- a/drivers/net/wireless/bcmdhd/include/proto/bcmevent.h
+++ b/drivers/net/wireless/bcmdhd/include/proto/bcmevent.h
@@ -40,6 +40,7 @@
#endif
/* #include <ethernet.h> -- TODO: req., excluded to overwhelming coupling (break up ethernet.h) */
#include <proto/bcmeth.h>
+#include <proto/dnglevent.h>
/* This marks the start of a packed structure section. */
#include <packed_section_start.h>
@@ -94,6 +95,17 @@ typedef BWL_PRE_PACKED_STRUCT struct bcm_event {
/* data portion follows */
} BWL_POST_PACKED_STRUCT bcm_event_t;
+/*
+ * used by host event
+ * Note: If additional event types are added, it should come on is_wlc_event_frame() as well.
+ */
+typedef union bcm_event_msg_u {
+ wl_event_msg_t event;
+ bcm_dngl_event_msg_t dngl_event;
+
+ /* add new event here */
+} bcm_event_msg_u_t;
+
#define BCM_MSG_LEN (sizeof(bcm_event_t) - sizeof(bcmeth_hdr_t) - sizeof(struct ether_header))
/* Event messages */
@@ -234,6 +246,9 @@ typedef BWL_PRE_PACKED_STRUCT struct bcm_event {
/* define an API for getting the string name of an event */
extern const char *bcmevent_get_name(uint event_type);
+/* validate if the event is proper and if valid copy event header to event */
+extern int is_wlc_event_frame(void *pktdata, uint pktlen, uint16 exp_usr_subtype,
+ bcm_event_msg_u_t *out_event);
/* Event status codes */
diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c
index ce773cca2bf5..87734840292b 100644
--- a/drivers/usb/core/devio.c
+++ b/drivers/usb/core/devio.c
@@ -1105,10 +1105,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;
diff --git a/include/linux/ipv6.h b/include/linux/ipv6.h
index 6f50b7e62442..7d354837fda7 100644
--- a/include/linux/ipv6.h
+++ b/include/linux/ipv6.h
@@ -221,7 +221,7 @@ struct ipv6_pinfo {
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/linux/perf_event.h b/include/linux/perf_event.h
index a340726cedb8..44bb6bf179c5 100644
--- a/include/linux/perf_event.h
+++ b/include/linux/perf_event.h
@@ -702,6 +702,11 @@ extern int perf_proc_update_handler(struct ctl_table *table, int write,
void __user *buffer, size_t *lenp,
loff_t *ppos);
+static inline bool perf_paranoid_any(void)
+{
+ return sysctl_perf_event_paranoid > 2;
+}
+
static inline bool perf_paranoid_tracepoint_raw(void)
{
return sysctl_perf_event_paranoid > -1;
diff --git a/include/net/ipv6.h b/include/net/ipv6.h
index 67b43806b622..aaff01b765ff 100644
--- a/include/net/ipv6.h
+++ b/include/net/ipv6.h
@@ -203,6 +203,7 @@ extern rwlock_t ip6_ra_lock;
*/
struct ipv6_txoptions {
+ atomic_t refcnt;
/* Length of this structure */
int tot_len;
@@ -215,7 +216,7 @@ struct ipv6_txoptions {
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 ipv6_fl_socklist {
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/kernel/events/core.c b/kernel/events/core.c
index debb393cde11..f99f8c251211 100644
--- a/kernel/events/core.c
+++ b/kernel/events/core.c
@@ -156,8 +156,13 @@ static struct srcu_struct pmus_srcu;
* 0 - disallow raw tracepoint access for unpriv
* 1 - disallow cpu events for unpriv
* 2 - disallow kernel profiling for unpriv
+ * 3 - disallow all unpriv perf event use
*/
+#ifdef CONFIG_SECURITY_PERF_EVENTS_RESTRICT
+int sysctl_perf_event_paranoid __read_mostly = 3;
+#else
int sysctl_perf_event_paranoid __read_mostly = 1;
+#endif
/* Minimum for 512 kiB + 1 user control page */
int sysctl_perf_event_mlock __read_mostly = 512 + (PAGE_SIZE / 1024); /* 'free' kiB per user */
@@ -6613,6 +6618,9 @@ SYSCALL_DEFINE5(perf_event_open,
if (flags & ~PERF_FLAG_ALL)
return -EINVAL;
+ if (perf_paranoid_any() && !capable(CAP_SYS_ADMIN))
+ return -EACCES;
+
err = perf_copy_attr(attr_uptr, &attr);
if (err)
return err;
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
index 4c3087dffe78..b4e11e19c275 100644
--- a/net/core/rtnetlink.c
+++ b/net/core/rtnetlink.c
@@ -895,14 +895,14 @@ 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;
}
diff --git a/net/dccp/ipv6.c b/net/dccp/ipv6.c
index 6cf9f7782ad4..86eedbaf037f 100644
--- a/net/dccp/ipv6.c
+++ b/net/dccp/ipv6.c
@@ -235,7 +235,9 @@ static int dccp_v6_send_response(struct sock *sk, struct request_sock *req)
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)) {
@@ -252,7 +254,10 @@ static int dccp_v6_send_response(struct sock *sk, struct request_sock *req)
&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);
}
@@ -448,6 +453,7 @@ static struct sock *dccp_v6_request_recv_sock(struct sock *sk,
{
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;
@@ -571,13 +577,15 @@ static struct sock *dccp_v6_request_recv_sock(struct sock *sk,
* 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));
@@ -829,6 +837,7 @@ static int dccp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
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;
@@ -931,7 +940,8 @@ static int dccp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
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)) {
@@ -951,9 +961,8 @@ static int dccp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
__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 d29ae19ae698..04e88b508d4e 100644
--- a/net/ipv6/af_inet6.c
+++ b/net/ipv6/af_inet6.c
@@ -448,9 +448,11 @@ void inet6_destroy_sock(struct sock *sk)
/* 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 @@ int inet6_sk_rebuild_header(struct sock *sk)
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 e9a8ca614aae..58e6cf78ad42 100644
--- a/net/ipv6/datagram.c
+++ b/net/ipv6/datagram.c
@@ -169,8 +169,10 @@ ipv4_connected:
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 8d67900aa003..33dbd6c1a00d 100644
--- a/net/ipv6/exthdrs.c
+++ b/net/ipv6/exthdrs.c
@@ -727,6 +727,7 @@ ipv6_dup_options(struct sock *sk, struct ipv6_txoptions *opt)
*((char **)&opt2->dst1opt) += dif;
if (opt2->srcrt)
*((char **)&opt2->srcrt) += dif;
+ atomic_set(&opt2->refcnt, 1);
}
return opt2;
}
@@ -790,7 +791,7 @@ ipv6_renew_options(struct sock *sk, struct ipv6_txoptions *opt,
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 65a46058c854..157f2b2bb3ee 100644
--- a/net/ipv6/inet6_connection_sock.c
+++ b/net/ipv6/inet6_connection_sock.c
@@ -78,7 +78,9 @@ struct dst_entry *inet6_csk_route_req(struct sock *sk,
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 @@ static struct dst_entry *inet6_csk_route_socket(struct sock *sk,
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 @@ int inet6_csk_xmit(struct sk_buff *skb, struct flowi *fl_unused)
/* 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 d1e2e8ef29c5..f4d2412d9c60 100644
--- a/net/ipv6/ipv6_sockglue.c
+++ b/net/ipv6/ipv6_sockglue.c
@@ -110,10 +110,12 @@ struct ipv6_txoptions *ipv6_update_options(struct sock *sk,
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 @@ static int do_ipv6_setsockopt(struct sock *sk, int level, int optname,
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 @@ static int do_ipv6_setsockopt(struct sock *sk, int level, int optname,
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 @@ static int do_ipv6_setsockopt(struct sock *sk, int level, int optname,
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 @@ sticky_done:
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 @@ update:
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 @@ static int do_ipv6_getsockopt(struct sock *sk, int level, int optname,
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 a9db8d252c9b..5693cf212e8d 100644
--- a/net/ipv6/raw.c
+++ b/net/ipv6/raw.c
@@ -726,6 +726,7 @@ static int rawv6_probe_proto_opt(struct flowi6 *fl6, struct msghdr *msg)
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 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk,
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 @@ done:
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 ba8622daffd7..701d0656a402 100644
--- a/net/ipv6/syncookies.c
+++ b/net/ipv6/syncookies.c
@@ -237,7 +237,7 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb)
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 3dd3f01bcb06..dc348c13838e 100644
--- a/net/ipv6/tcp_ipv6.c
+++ b/net/ipv6/tcp_ipv6.c
@@ -133,6 +133,7 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
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 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
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 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
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 @@ static int tcp_v6_send_synack(struct sock *sk, struct dst_entry *dst,
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 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
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 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
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 c23a919331c5..b01d23d2ec8a 100644
--- a/net/ipv6/udp.c
+++ b/net/ipv6/udp.c
@@ -1017,6 +1017,7 @@ int udpv6_sendmsg(struct kiocb *iocb, struct sock *sk,
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;
@@ -1171,8 +1172,10 @@ do_udp_sendmsg:
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);
@@ -1273,6 +1276,7 @@ do_append_data:
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 e6e8408c9e36..3b61ddd6e4a6 100644
--- a/net/l2tp/l2tp_ip6.c
+++ b/net/l2tp/l2tp_ip6.c
@@ -485,6 +485,7 @@ static int l2tp_ip6_sendmsg(struct kiocb *iocb, struct sock *sk,
(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 @@ static int l2tp_ip6_sendmsg(struct kiocb *iocb, struct sock *sk,
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 @@ done:
dst_release(dst);
out:
fl6_sock_release(flowlabel);
+ txopt_put(opt_to_free);
return err < 0 ? err : len;
diff --git a/net/socket.c b/net/socket.c
index fc90b4f0da3c..2fefb3132aa7 100644
--- a/net/socket.c
+++ b/net/socket.c
@@ -1764,6 +1764,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;
@@ -1823,6 +1825,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;
diff --git a/security/Kconfig b/security/Kconfig
index e9c6ac724fef..e37182464f30 100644
--- a/security/Kconfig
+++ b/security/Kconfig
@@ -18,6 +18,15 @@ config SECURITY_DMESG_RESTRICT
If you are unsure how to answer this question, answer N.
+config SECURITY_PERF_EVENTS_RESTRICT
+ bool "Restrict unprivileged use of performance events"
+ depends on PERF_EVENTS
+ help
+ If you say Y here, the kernel.perf_event_paranoid sysctl
+ will be set to 3 by default, and no unprivileged use of the
+ perf_event_open syscall will be permitted unless it is
+ changed.
+
config SECURITY
bool "Enable different security models"
depends on SYSFS
diff --git a/sound/core/compress_offload.c b/sound/core/compress_offload.c
index bb0cb54f2132..959eccf5ae66 100644
--- a/sound/core/compress_offload.c
+++ b/sound/core/compress_offload.c
@@ -497,7 +497,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 */
diff --git a/sound/core/timer.c b/sound/core/timer.c
index 6ddcf06f52f9..ee81c947c24b 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 */
@@ -1174,6 +1174,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;
@@ -1208,6 +1209,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;
@@ -1256,7 +1258,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),
@@ -1276,8 +1278,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);
@@ -1515,7 +1519,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;
@@ -1559,7 +1562,6 @@ static int snd_timer_user_tselect(struct file *file,
}
__err:
- mutex_unlock(&tu->tread_sem);
return err;
}
@@ -1673,6 +1675,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;
@@ -1772,7 +1775,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;
@@ -1789,17 +1792,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:
@@ -1832,6 +1829,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;
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index 07b1a3ad3e24..54494df33dd2 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -1514,13 +1514,16 @@ int perf_evsel__open_strerror(struct perf_evsel *evsel,
switch (err) {
case EPERM:
case EACCES:
- return scnprintf(msg, size, "%s",
- "You may not have permission to collect %sstats.\n"
- "Consider tweaking /proc/sys/kernel/perf_event_paranoid:\n"
- " -1 - Not paranoid at all\n"
- " 0 - Disallow raw tracepoint access for unpriv\n"
- " 1 - Disallow cpu events for unpriv\n"
- " 2 - Disallow kernel profiling for unpriv",
+ return scnprintf(msg, size,
+ "You may not have permission to collect %sstats.\n\n"
+ "Consider tweaking /proc/sys/kernel/perf_event_paranoid,\n"
+ "which controls use of the performance events system by\n"
+ "unprivileged users (without CAP_SYS_ADMIN).\n\n"
+ "The default value is 1:\n\n"
+ " -1: Allow use of (almost) all events by all users\n"
+ ">= 0: Disallow raw tracepoint access by users without CAP_IOC_LOCK\n"
+ ">= 1: Disallow CPU event access by users without CAP_SYS_ADMIN\n"
+ ">= 2: Disallow kernel profiling by users without CAP_SYS_ADMIN",
target->system_wide ? "system-wide " : "");
case ENOENT:
return scnprintf(msg, size, "The %s event is not supported.",