mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-09-12 13:55:32 +00:00
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:
commit
319cbacfc0
10 changed files with 73 additions and 34 deletions
|
@ -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,
|
||||
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue