Commit 319cbacf authored by Linus Torvalds's avatar Linus Torvalds
Browse files
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
parents a06b0c82 422b3db2
Loading
Loading
Loading
Loading
+35 −8
Original line number Diff line number Diff line
@@ -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;
+18 −12
Original line number Diff line number Diff line
@@ -209,11 +209,12 @@ 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);
	if (!(opt_flags & FW_OPT_NOCACHE)) {
		tmp = __lookup_fw_priv(fw_name);
		if (tmp) {
			kref_get(&tmp->ref);
@@ -222,8 +223,10 @@ static int alloc_lookup_fw_priv(const char *fw_name,
			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;

+1 −1
Original line number Diff line number Diff line
@@ -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;
		}
+3 −0
Original line number Diff line number Diff line
@@ -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);
}

+2 −0
Original line number Diff line number Diff line
@@ -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);
Loading