Char/Misc driver fixes for 4.19-rc4

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.
 
 Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
 -----BEGIN PGP SIGNATURE-----
 
 iG0EABECAC0WIQT0tgzFv3jCIUoxPcsxR9QN2y37KQUCW5uYvQ8cZ3JlZ0Brcm9h
 aC5jb20ACgkQMUfUDdst+yl4MQCgkSLYti3Cu2A90S/H0DKTyW8+21oAnj3wfuUn
 sgFdJOwM1PNB5Y/Cfyvl
 =NcTu
 -----END PGP SIGNATURE-----

Merge tag 'char-misc-4.19-rc4' of git://git.kernel.org/pub/scm/linux/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
This commit is contained in:
Linus Torvalds 2018-09-14 05:40:13 -10:00
commit 319cbacfc0
10 changed files with 73 additions and 34 deletions

View File

@ -332,6 +332,35 @@ err_no_vma:
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,
@ -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);
@ -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;
@ -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);
@ -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);
}
/**
@ -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;

View File

@ -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);
@ -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;
@ -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
@ -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;

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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);
@ -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);

View File

@ -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);

View File

@ -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;
@ -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);
@ -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,
};
/**

View File

@ -1767,7 +1767,7 @@ out:
}
}
rets = buf->size;
rets = len;
err:
cl_dbg(dev, cl, "rpm: autosuspend\n");
pm_runtime_mark_last_busy(dev->dev);

View File

@ -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;

View File

@ -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;