Skip to content

Commit

Permalink
Merge tag 'char-misc-4.19-rc4' of git://git.kernel.org/pub/scm/linux/…
Browse files Browse the repository at this point in the history
…kernel/git/gregkh/char-misc

Pull char/misc driver fixes from Greg KH:
 "Here are a small handful of char/misc driver fixes for 4.19-rc4.

  All of them are simple, resolving reported problems in a few drivers.
  Full details are in the shortlog.

  All of these have been in linux-next with no reported issues"

* tag 'char-misc-4.19-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc:
  firmware: Fix security issue with request_firmware_into_buf()
  vmbus: don't return values for uninitalized channels
  fpga: dfl: fme: fix return value check in in pr_mgmt_init()
  misc: hmc6352: fix potential Spectre v1
  Tools: hv: Fix a bug in the key delete code
  misc: ibmvsm: Fix wrong assignment of return code
  android: binder: fix the race mmap and alloc_new_buf_locked
  mei: bus: need to unlink client before freeing
  mei: bus: fix hw module get/put balance
  mei: fix use-after-free in mei_cl_write
  mei: ignore not found client in the enumeration
  • Loading branch information
torvalds committed Sep 14, 2018
2 parents a06b0c8 + 422b3db commit 319cbac
Show file tree
Hide file tree
Showing 10 changed files with 73 additions and 34 deletions.
43 changes: 35 additions & 8 deletions drivers/android/binder_alloc.c
Expand Up @@ -332,6 +332,35 @@ static int binder_update_page_range(struct binder_alloc *alloc, int allocate,
return vma ? -ENOMEM : -ESRCH;
}


static inline void binder_alloc_set_vma(struct binder_alloc *alloc,
struct vm_area_struct *vma)
{
if (vma)
alloc->vma_vm_mm = vma->vm_mm;
/*
* If we see alloc->vma is not NULL, buffer data structures set up
* completely. Look at smp_rmb side binder_alloc_get_vma.
* We also want to guarantee new alloc->vma_vm_mm is always visible
* if alloc->vma is set.
*/
smp_wmb();
alloc->vma = vma;
}

static inline struct vm_area_struct *binder_alloc_get_vma(
struct binder_alloc *alloc)
{
struct vm_area_struct *vma = NULL;

if (alloc->vma) {
/* Look at description in binder_alloc_set_vma */
smp_rmb();
vma = alloc->vma;
}
return vma;
}

static struct binder_buffer *binder_alloc_new_buf_locked(
struct binder_alloc *alloc,
size_t data_size,
Expand All @@ -348,7 +377,7 @@ static struct binder_buffer *binder_alloc_new_buf_locked(
size_t size, data_offsets_size;
int ret;

if (alloc->vma == NULL) {
if (!binder_alloc_get_vma(alloc)) {
binder_alloc_debug(BINDER_DEBUG_USER_ERROR,
"%d: binder_alloc_buf, no vma\n",
alloc->pid);
Expand Down Expand Up @@ -723,9 +752,7 @@ int binder_alloc_mmap_handler(struct binder_alloc *alloc,
buffer->free = 1;
binder_insert_free_buffer(alloc, buffer);
alloc->free_async_space = alloc->buffer_size / 2;
barrier();
alloc->vma = vma;
alloc->vma_vm_mm = vma->vm_mm;
binder_alloc_set_vma(alloc, vma);
mmgrab(alloc->vma_vm_mm);

return 0;
Expand Down Expand Up @@ -754,10 +781,10 @@ void binder_alloc_deferred_release(struct binder_alloc *alloc)
int buffers, page_count;
struct binder_buffer *buffer;

BUG_ON(alloc->vma);

buffers = 0;
mutex_lock(&alloc->mutex);
BUG_ON(alloc->vma);

while ((n = rb_first(&alloc->allocated_buffers))) {
buffer = rb_entry(n, struct binder_buffer, rb_node);

Expand Down Expand Up @@ -900,7 +927,7 @@ int binder_alloc_get_allocated_count(struct binder_alloc *alloc)
*/
void binder_alloc_vma_close(struct binder_alloc *alloc)
{
WRITE_ONCE(alloc->vma, NULL);
binder_alloc_set_vma(alloc, NULL);
}

/**
Expand Down Expand Up @@ -935,7 +962,7 @@ enum lru_status binder_alloc_free_page(struct list_head *item,

index = page - alloc->pages;
page_addr = (uintptr_t)alloc->buffer + index * PAGE_SIZE;
vma = alloc->vma;
vma = binder_alloc_get_vma(alloc);
if (vma) {
if (!mmget_not_zero(alloc->vma_vm_mm))
goto err_mmget;
Expand Down
30 changes: 18 additions & 12 deletions drivers/base/firmware_loader/main.c
Expand Up @@ -209,21 +209,24 @@ static struct fw_priv *__lookup_fw_priv(const char *fw_name)
static int alloc_lookup_fw_priv(const char *fw_name,
struct firmware_cache *fwc,
struct fw_priv **fw_priv, void *dbuf,
size_t size)
size_t size, enum fw_opt opt_flags)
{
struct fw_priv *tmp;

spin_lock(&fwc->lock);
tmp = __lookup_fw_priv(fw_name);
if (tmp) {
kref_get(&tmp->ref);
spin_unlock(&fwc->lock);
*fw_priv = tmp;
pr_debug("batched request - sharing the same struct fw_priv and lookup for multiple requests\n");
return 1;
if (!(opt_flags & FW_OPT_NOCACHE)) {
tmp = __lookup_fw_priv(fw_name);
if (tmp) {
kref_get(&tmp->ref);
spin_unlock(&fwc->lock);
*fw_priv = tmp;
pr_debug("batched request - sharing the same struct fw_priv and lookup for multiple requests\n");
return 1;
}
}

tmp = __allocate_fw_priv(fw_name, fwc, dbuf, size);
if (tmp)
if (tmp && !(opt_flags & FW_OPT_NOCACHE))
list_add(&tmp->list, &fwc->head);
spin_unlock(&fwc->lock);

Expand Down Expand Up @@ -493,7 +496,8 @@ int assign_fw(struct firmware *fw, struct device *device,
*/
static int
_request_firmware_prepare(struct firmware **firmware_p, const char *name,
struct device *device, void *dbuf, size_t size)
struct device *device, void *dbuf, size_t size,
enum fw_opt opt_flags)
{
struct firmware *firmware;
struct fw_priv *fw_priv;
Expand All @@ -511,7 +515,8 @@ _request_firmware_prepare(struct firmware **firmware_p, const char *name,
return 0; /* assigned */
}

ret = alloc_lookup_fw_priv(name, &fw_cache, &fw_priv, dbuf, size);
ret = alloc_lookup_fw_priv(name, &fw_cache, &fw_priv, dbuf, size,
opt_flags);

/*
* bind with 'priv' now to avoid warning in failure path
Expand Down Expand Up @@ -571,7 +576,8 @@ _request_firmware(const struct firmware **firmware_p, const char *name,
goto out;
}

ret = _request_firmware_prepare(&fw, name, device, buf, size);
ret = _request_firmware_prepare(&fw, name, device, buf, size,
opt_flags);
if (ret <= 0) /* error or already assigned */
goto out;

Expand Down
2 changes: 1 addition & 1 deletion drivers/fpga/dfl-fme-pr.c
Expand Up @@ -420,7 +420,7 @@ static int pr_mgmt_init(struct platform_device *pdev,
/* Create region for each port */
fme_region = dfl_fme_create_region(pdata, mgr,
fme_br->br, i);
if (!fme_region) {
if (IS_ERR(fme_region)) {
ret = PTR_ERR(fme_region);
goto destroy_region;
}
Expand Down
3 changes: 3 additions & 0 deletions drivers/hv/vmbus_drv.c
Expand Up @@ -1291,6 +1291,9 @@ static ssize_t vmbus_chan_attr_show(struct kobject *kobj,
if (!attribute->show)
return -EIO;

if (chan->state != CHANNEL_OPENED_STATE)
return -EINVAL;

return attribute->show(chan, buf);
}

Expand Down
2 changes: 2 additions & 0 deletions drivers/misc/hmc6352.c
Expand Up @@ -27,6 +27,7 @@
#include <linux/err.h>
#include <linux/delay.h>
#include <linux/sysfs.h>
#include <linux/nospec.h>

static DEFINE_MUTEX(compass_mutex);

Expand All @@ -50,6 +51,7 @@ static int compass_store(struct device *dev, const char *buf, size_t count,
return ret;
if (val >= strlen(map))
return -EINVAL;
val = array_index_nospec(val, strlen(map));
mutex_lock(&compass_mutex);
ret = compass_command(c, map[val]);
mutex_unlock(&compass_mutex);
Expand Down
2 changes: 1 addition & 1 deletion drivers/misc/ibmvmc.c
Expand Up @@ -2131,7 +2131,7 @@ static int ibmvmc_init_crq_queue(struct crq_server_adapter *adapter)
retrc = plpar_hcall_norets(H_REG_CRQ,
vdev->unit_address,
queue->msg_token, PAGE_SIZE);
retrc = rc;
rc = retrc;

if (rc == H_RESOURCE)
rc = ibmvmc_reset_crq_queue(adapter);
Expand Down
12 changes: 5 additions & 7 deletions drivers/misc/mei/bus.c
Expand Up @@ -521,17 +521,15 @@ int mei_cldev_enable(struct mei_cl_device *cldev)

cl = cldev->cl;

mutex_lock(&bus->device_lock);
if (cl->state == MEI_FILE_UNINITIALIZED) {
mutex_lock(&bus->device_lock);
ret = mei_cl_link(cl);
mutex_unlock(&bus->device_lock);
if (ret)
return ret;
goto out;
/* update pointers */
cl->cldev = cldev;
}

mutex_lock(&bus->device_lock);
if (mei_cl_is_connected(cl)) {
ret = 0;
goto out;
Expand Down Expand Up @@ -616,9 +614,8 @@ int mei_cldev_disable(struct mei_cl_device *cldev)
if (err < 0)
dev_err(bus->dev, "Could not disconnect from the ME client\n");

out:
mei_cl_bus_module_put(cldev);

out:
/* Flush queues and remove any pending read */
mei_cl_flush_queues(cl, NULL);
mei_cl_unlink(cl);
Expand Down Expand Up @@ -876,12 +873,13 @@ static void mei_cl_bus_dev_release(struct device *dev)

mei_me_cl_put(cldev->me_cl);
mei_dev_bus_put(cldev->bus);
mei_cl_unlink(cldev->cl);
kfree(cldev->cl);
kfree(cldev);
}

static const struct device_type mei_cl_device_type = {
.release = mei_cl_bus_dev_release,
.release = mei_cl_bus_dev_release,
};

/**
Expand Down
2 changes: 1 addition & 1 deletion drivers/misc/mei/client.c
Expand Up @@ -1767,7 +1767,7 @@ ssize_t mei_cl_write(struct mei_cl *cl, struct mei_cl_cb *cb)
}
}

rets = buf->size;
rets = len;
err:
cl_dbg(dev, cl, "rpm: autosuspend\n");
pm_runtime_mark_last_busy(dev->dev);
Expand Down
9 changes: 6 additions & 3 deletions drivers/misc/mei/hbm.c
Expand Up @@ -1161,15 +1161,18 @@ int mei_hbm_dispatch(struct mei_device *dev, struct mei_msg_hdr *hdr)

props_res = (struct hbm_props_response *)mei_msg;

if (props_res->status) {
if (props_res->status == MEI_HBMS_CLIENT_NOT_FOUND) {
dev_dbg(dev->dev, "hbm: properties response: %d CLIENT_NOT_FOUND\n",
props_res->me_addr);
} else if (props_res->status) {
dev_err(dev->dev, "hbm: properties response: wrong status = %d %s\n",
props_res->status,
mei_hbm_status_str(props_res->status));
return -EPROTO;
} else {
mei_hbm_me_cl_add(dev, props_res);
}

mei_hbm_me_cl_add(dev, props_res);

/* request property for the next client */
if (mei_hbm_prop_req(dev, props_res->me_addr + 1))
return -EIO;
Expand Down
2 changes: 1 addition & 1 deletion tools/hv/hv_kvp_daemon.c
Expand Up @@ -286,7 +286,7 @@ static int kvp_key_delete(int pool, const __u8 *key, int key_size)
* Found a match; just move the remaining
* entries up.
*/
if (i == num_records) {
if (i == (num_records - 1)) {
kvp_file_info[pool].num_records--;
kvp_update_file(pool);
return 0;
Expand Down

0 comments on commit 319cbac

Please sign in to comment.