summaryrefslogtreecommitdiff
path: root/drivers/char
diff options
context:
space:
mode:
authorTao Huang <huangtao@rock-chips.com>2018-09-07 17:34:34 +0800
committerTao Huang <huangtao@rock-chips.com>2018-09-07 17:34:34 +0800
commit75654db87775a407f17aa04fd31562fc2bdaa72f (patch)
treeefbaa9c47e541b0ee8861105de6bf49fa27e22ab /drivers/char
parent78585b99a328f6f2a9f76ef2f4b2fee2b1a8d788 (diff)
parent82eacc8a7bb8eb5809ef9ad8fae8104110626305 (diff)
Merge branch 'linux-linaro-lsk-v4.4' of git://git.linaro.org/kernel/linux-linaro-stable.git
* linux-linaro-lsk-v4.4: (519 commits) Linux 4.4.154 cdrom: Fix info leak/OOB read in cdrom_ioctl_drive_status iscsi target: fix session creation failure handling scsi: core: Avoid that SCSI device removal through sysfs triggers a deadlock scsi: sysfs: Introduce sysfs_{un,}break_active_protection() MIPS: lib: Provide MIPS64r6 __multi3() for GCC < 7 MIPS: Correct the 64-bit DSP accumulator register size kprobes: Make list and blacklist root user read only s390/pci: fix out of bounds access during irq setup s390/qdio: reset old sbal_state flags s390: fix br_r1_trampoline for machines without exrl x86/spectre: Add missing family 6 check to microcode check x86/irqflags: Mark native_restore_fl extern inline pinctrl: freescale: off by one in imx1_pinconf_group_dbg_show() ASoC: sirf: Fix potential NULL pointer dereference ASoC: dpcm: don't merge format from invalid codec dai udl-kms: fix crash due to uninitialized memory udl-kms: handle allocation failure udl-kms: change down_interruptible to down fuse: Add missed unlock_page() to fuse_readpages_fill() ... Conflicts: Makefile arch/arm64/mm/init.c fs/squashfs/block.c include/uapi/linux/prctl.h kernel/sys.c Change-Id: Ie03b5adfbbb4ab2bf16bc55d99f0d8a9c540a53b
Diffstat (limited to 'drivers/char')
-rw-r--r--drivers/char/random.c10
-rw-r--r--drivers/char/tpm/tpm-dev.c43
2 files changed, 29 insertions, 24 deletions
diff --git a/drivers/char/random.c b/drivers/char/random.c
index dffd06a3bb76..2916d08ee30e 100644
--- a/drivers/char/random.c
+++ b/drivers/char/random.c
@@ -1503,14 +1503,22 @@ static int
write_pool(struct entropy_store *r, const char __user *buffer, size_t count)
{
size_t bytes;
- __u32 buf[16];
+ __u32 t, buf[16];
const char __user *p = buffer;
while (count > 0) {
+ int b, i = 0;
+
bytes = min(count, sizeof(buf));
if (copy_from_user(&buf, p, bytes))
return -EFAULT;
+ for (b = bytes ; b > 0 ; b -= sizeof(__u32), i++) {
+ if (!arch_get_random_int(&t))
+ break;
+ buf[i] ^= t;
+ }
+
count -= bytes;
p += bytes;
diff --git a/drivers/char/tpm/tpm-dev.c b/drivers/char/tpm/tpm-dev.c
index 912ad30be585..4719aa781bf2 100644
--- a/drivers/char/tpm/tpm-dev.c
+++ b/drivers/char/tpm/tpm-dev.c
@@ -25,7 +25,7 @@ struct file_priv {
struct tpm_chip *chip;
/* Data passed to and from the tpm via the read/write calls */
- atomic_t data_pending;
+ size_t data_pending;
struct mutex buffer_mutex;
struct timer_list user_read_timer; /* user needs to claim result */
@@ -46,7 +46,7 @@ static void timeout_work(struct work_struct *work)
struct file_priv *priv = container_of(work, struct file_priv, work);
mutex_lock(&priv->buffer_mutex);
- atomic_set(&priv->data_pending, 0);
+ priv->data_pending = 0;
memset(priv->data_buffer, 0, sizeof(priv->data_buffer));
mutex_unlock(&priv->buffer_mutex);
}
@@ -72,7 +72,6 @@ static int tpm_open(struct inode *inode, struct file *file)
}
priv->chip = chip;
- atomic_set(&priv->data_pending, 0);
mutex_init(&priv->buffer_mutex);
setup_timer(&priv->user_read_timer, user_reader_timeout,
(unsigned long)priv);
@@ -86,28 +85,24 @@ static ssize_t tpm_read(struct file *file, char __user *buf,
size_t size, loff_t *off)
{
struct file_priv *priv = file->private_data;
- ssize_t ret_size;
+ ssize_t ret_size = 0;
int rc;
del_singleshot_timer_sync(&priv->user_read_timer);
flush_work(&priv->work);
- ret_size = atomic_read(&priv->data_pending);
- if (ret_size > 0) { /* relay data */
- ssize_t orig_ret_size = ret_size;
- if (size < ret_size)
- ret_size = size;
+ mutex_lock(&priv->buffer_mutex);
- mutex_lock(&priv->buffer_mutex);
+ if (priv->data_pending) {
+ ret_size = min_t(ssize_t, size, priv->data_pending);
rc = copy_to_user(buf, priv->data_buffer, ret_size);
- memset(priv->data_buffer, 0, orig_ret_size);
+ memset(priv->data_buffer, 0, priv->data_pending);
if (rc)
ret_size = -EFAULT;
- mutex_unlock(&priv->buffer_mutex);
+ priv->data_pending = 0;
}
- atomic_set(&priv->data_pending, 0);
-
+ mutex_unlock(&priv->buffer_mutex);
return ret_size;
}
@@ -118,18 +113,20 @@ static ssize_t tpm_write(struct file *file, const char __user *buf,
size_t in_size = size;
ssize_t out_size;
- /* cannot perform a write until the read has cleared
- either via tpm_read or a user_read_timer timeout.
- This also prevents splitted buffered writes from blocking here.
- */
- if (atomic_read(&priv->data_pending) != 0)
- return -EBUSY;
-
if (in_size > TPM_BUFSIZE)
return -E2BIG;
mutex_lock(&priv->buffer_mutex);
+ /* Cannot perform a write until the read has cleared either via
+ * tpm_read or a user_read_timer timeout. This also prevents split
+ * buffered writes from blocking here.
+ */
+ if (priv->data_pending != 0) {
+ mutex_unlock(&priv->buffer_mutex);
+ return -EBUSY;
+ }
+
if (copy_from_user
(priv->data_buffer, (void __user *) buf, in_size)) {
mutex_unlock(&priv->buffer_mutex);
@@ -153,7 +150,7 @@ static ssize_t tpm_write(struct file *file, const char __user *buf,
return out_size;
}
- atomic_set(&priv->data_pending, out_size);
+ priv->data_pending = out_size;
mutex_unlock(&priv->buffer_mutex);
/* Set a timeout by which the reader must come claim the result */
@@ -172,7 +169,7 @@ static int tpm_release(struct inode *inode, struct file *file)
del_singleshot_timer_sync(&priv->user_read_timer);
flush_work(&priv->work);
file->private_data = NULL;
- atomic_set(&priv->data_pending, 0);
+ priv->data_pending = 0;
clear_bit(0, &priv->chip->is_open);
kfree(priv);
return 0;