Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit aec59fab authored by Raghavendra Rao Ananta's avatar Raghavendra Rao Ananta
Browse files

soc: qcom: ramdump: Abort user-space read if timed-out



It's possible that the user-space process can be woken up
very late to collect the ramdumps by which time, the ramdump
collection timer would have expired. Following this, the PIL
driver unmaps the memory and continues. The user-space process
has no way to know about this and can make an attempt to read
the unmapped memory, thus resulting in a data abort.

Hence, notify the user-space process that the ramdump timer
has expired such that it can reset its state machine.

Also add the srcu related symbols to the allowed-list and update
the ABI snapshot accordingly.

Change-Id: Idb92d98406a9032c999c82e2089213883c5a65eb
Signed-off-by: default avatarRaghavendra Rao Ananta <rananta@codeaurora.org>
parent 1e4aef37
Loading
Loading
Loading
Loading
+423 −363

File changed.

Preview size limit exceeded, changes collapsed.

+4 −0
Original line number Diff line number Diff line
@@ -1098,6 +1098,7 @@
  init_net
  __init_rwsem
  init_special_inode
  init_srcu_struct
  init_timer_key
  init_uts_ns
  init_wait_entry
@@ -2275,6 +2276,8 @@
  srcu_notifier_call_chain
  srcu_notifier_chain_register
  srcu_notifier_chain_unregister
  __srcu_read_lock
  __srcu_read_unlock
  sscanf
  __stack_chk_fail
  __stack_chk_guard
@@ -2317,6 +2320,7 @@
  synchronize_irq
  synchronize_net
  synchronize_rcu
  synchronize_srcu
  syscon_node_to_regmap
  syscon_regmap_lookup_by_phandle
  sysfs_create_bin_file
+35 −2
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
#include <linux/elf.h>
#include <linux/wait.h>
#include <linux/cdev.h>
#include <linux/srcu.h>
#include <linux/atomic.h>
#include <soc/qcom/ramdump.h>
#include <linux/of.h>
@@ -59,6 +60,8 @@ struct ramdump_device {
	size_t elfcore_size;
	char *elfcore_buf;
	bool complete_ramdump;
	bool abort_ramdump;
	struct srcu_struct rd_srcu;
};

static int ramdump_open(struct inode *inode, struct file *filep)
@@ -158,15 +161,26 @@ static ssize_t ramdump_read(struct file *filep, char __user *buf, size_t count,
	size_t copy_size = 0, alignsize;
	unsigned char *alignbuf = NULL, *finalbuf = NULL;
	int ret = 0;
	int srcu_idx;
	loff_t orig_pos = *pos;

	if ((filep->f_flags & O_NONBLOCK) && !entry->data_ready)
		return -EAGAIN;

	ret = wait_event_interruptible(rd_dev->dump_wait_q, entry->data_ready);
	ret = wait_event_interruptible(rd_dev->dump_wait_q,
				(entry->data_ready || rd_dev->abort_ramdump));
	if (ret)
		return ret;

	srcu_idx = srcu_read_lock(&rd_dev->rd_srcu);

	if (rd_dev->abort_ramdump) {
		pr_err("Ramdump(%s): Ramdump aborted\n", rd_dev->name);
		rd_dev->ramdump_status = -1;
		ret = -ETIME;
		goto ramdump_done;
	}

	if (*pos < rd_dev->elfcore_size) {
		copy_size = rd_dev->elfcore_size - *pos;
		copy_size = min(copy_size, count);
@@ -178,9 +192,11 @@ static ssize_t ramdump_read(struct file *filep, char __user *buf, size_t count,
		*pos += copy_size;
		count -= copy_size;
		buf += copy_size;
		if (count == 0)
		if (count == 0) {
			srcu_read_unlock(&rd_dev->rd_srcu, srcu_idx);
			return copy_size;
		}
	}

	addr = offset_translate(*pos - rd_dev->elfcore_size, rd_dev,
				&data_left, &vaddr);
@@ -252,9 +268,12 @@ static ssize_t ramdump_read(struct file *filep, char __user *buf, size_t count,
	pr_debug("Ramdump(%s): Read %zd bytes from address %lx.\n",
			rd_dev->name, copy_size, addr);

	srcu_read_unlock(&rd_dev->rd_srcu, srcu_idx);

	return *pos - orig_pos;

ramdump_done:
	srcu_read_unlock(&rd_dev->rd_srcu, srcu_idx);
	kfree(finalbuf);
	*pos = 0;
	reset_ramdump_entry(entry);
@@ -361,6 +380,7 @@ void *create_ramdump_device(const char *dev_name, struct device *parent)

	mutex_init(&rd_dev->consumer_lock);
	atomic_set(&rd_dev->readers_left, 0);
	init_srcu_struct(&rd_dev->rd_srcu);
	cdev_init(&rd_dev->cdev, &ramdump_file_ops);

	ret = cdev_add(&rd_dev->cdev, MKDEV(MAJOR(ramdump_dev), minor), 1);
@@ -373,6 +393,7 @@ void *create_ramdump_device(const char *dev_name, struct device *parent)
	return (void *)rd_dev;

fail_cdev_add:
	cleanup_srcu_struct(&rd_dev->rd_srcu);
	mutex_destroy(&rd_dev->consumer_lock);
	device_unregister(rd_dev->dev);
fail_return_minor:
@@ -393,6 +414,7 @@ void destroy_ramdump_device(void *dev)

	cdev_del(&rd_dev->cdev);
	device_unregister(rd_dev->dev);
	cleanup_srcu_struct(&rd_dev->rd_srcu);
	ida_simple_remove(&rd_minor_id, minor);
	kfree(rd_dev);
}
@@ -473,6 +495,7 @@ static int _do_ramdump(void *handle, struct ramdump_segment *segments,
	list_for_each_entry(entry, &rd_dev->consumer_list, list)
		entry->data_ready = true;
	rd_dev->ramdump_status = -1;
	rd_dev->abort_ramdump = false;

	reinit_completion(&rd_dev->ramdump_complete);
	atomic_set(&rd_dev->readers_left, rd_dev->consumers);
@@ -489,6 +512,11 @@ static int _do_ramdump(void *handle, struct ramdump_segment *segments,
		pr_err("Ramdump(%s): Timed out waiting for userspace.\n",
			rd_dev->name);
		ret = -EPIPE;
		rd_dev->abort_ramdump = true;

		/* Wait for pending readers to complete (if any) */
		synchronize_srcu(&rd_dev->rd_srcu);

	} else
		ret = (rd_dev->ramdump_status == 0) ? 0 : -EPIPE;

@@ -602,6 +630,7 @@ static int _do_minidump(void *handle, struct ramdump_segment *segments,
	list_for_each_entry(entry, &rd_dev->consumer_list, list)
		entry->data_ready = true;
	rd_dev->ramdump_status = -1;
	rd_dev->abort_ramdump = false;

	reinit_completion(&rd_dev->ramdump_complete);
	atomic_set(&rd_dev->readers_left, rd_dev->consumers);
@@ -618,6 +647,10 @@ static int _do_minidump(void *handle, struct ramdump_segment *segments,
		pr_err("Ramdump(%s): Timed out waiting for userspace.\n",
		       rd_dev->name);
		ret = -EPIPE;
		rd_dev->abort_ramdump = true;

		/* Wait for pending readers to complete (if any) */
		synchronize_srcu(&rd_dev->rd_srcu);
	} else {
		ret = (rd_dev->ramdump_status == 0) ? 0 : -EPIPE;
	}