diff options
| author | Arnd Bergmann <arnd@arndb.de> | 2005-12-09 13:21:44 -0500 |
|---|---|---|
| committer | Paul Mackerras <paulus@samba.org> | 2006-01-08 22:53:31 -0500 |
| commit | f9ce299fc629d5c899a2e56b00e21f5da05cf590 (patch) | |
| tree | da8f883f72d08f9534e9eca3bba662413b9bd865 | |
| parent | d52771fce4e774fa786097d34412a057d487c697 (diff) | |
[PATCH] powerpc: fix large nvram access
/dev/nvram uses the user-provided read/write size
for kmalloc, which fails, if a large number is passed.
This will always use a single page at most, which
can be expected to succeed.
Signed-off-by: Arnd Bergmann <arndb@de.ibm.com>
Signed-off-by: Paul Mackerras <paulus@samba.org>
| -rw-r--r-- | arch/powerpc/kernel/nvram_64.c | 106 |
1 files changed, 50 insertions, 56 deletions
diff --git a/arch/powerpc/kernel/nvram_64.c b/arch/powerpc/kernel/nvram_64.c index c0fcd29918ce..fd7db8d542db 100644 --- a/arch/powerpc/kernel/nvram_64.c +++ b/arch/powerpc/kernel/nvram_64.c | |||
| @@ -80,80 +80,74 @@ static loff_t dev_nvram_llseek(struct file *file, loff_t offset, int origin) | |||
| 80 | static ssize_t dev_nvram_read(struct file *file, char __user *buf, | 80 | static ssize_t dev_nvram_read(struct file *file, char __user *buf, |
| 81 | size_t count, loff_t *ppos) | 81 | size_t count, loff_t *ppos) |
| 82 | { | 82 | { |
| 83 | ssize_t len; | 83 | ssize_t ret; |
| 84 | char *tmp_buffer; | 84 | char *tmp = NULL; |
| 85 | int size; | 85 | ssize_t size; |
| 86 | 86 | ||
| 87 | if (ppc_md.nvram_size == NULL) | 87 | ret = -ENODEV; |
| 88 | return -ENODEV; | 88 | if (!ppc_md.nvram_size) |
| 89 | goto out; | ||
| 90 | |||
| 91 | ret = 0; | ||
| 89 | size = ppc_md.nvram_size(); | 92 | size = ppc_md.nvram_size(); |
| 93 | if (*ppos >= size || size < 0) | ||
| 94 | goto out; | ||
| 90 | 95 | ||
| 91 | if (!access_ok(VERIFY_WRITE, buf, count)) | 96 | count = min_t(size_t, count, size - *ppos); |
| 92 | return -EFAULT; | 97 | count = min(count, PAGE_SIZE); |
| 93 | if (*ppos >= size) | ||
| 94 | return 0; | ||
| 95 | if (count > size) | ||
| 96 | count = size; | ||
| 97 | 98 | ||
| 98 | tmp_buffer = (char *) kmalloc(count, GFP_KERNEL); | 99 | ret = -ENOMEM; |
| 99 | if (!tmp_buffer) { | 100 | tmp = kmalloc(count, GFP_KERNEL); |
| 100 | printk(KERN_ERR "dev_read_nvram: kmalloc failed\n"); | 101 | if (!tmp) |
| 101 | return -ENOMEM; | 102 | goto out; |
| 102 | } | ||
| 103 | 103 | ||
| 104 | len = ppc_md.nvram_read(tmp_buffer, count, ppos); | 104 | ret = ppc_md.nvram_read(tmp, count, ppos); |
| 105 | if ((long)len <= 0) { | 105 | if (ret <= 0) |
| 106 | kfree(tmp_buffer); | 106 | goto out; |
| 107 | return len; | ||
| 108 | } | ||
| 109 | 107 | ||
| 110 | if (copy_to_user(buf, tmp_buffer, len)) { | 108 | if (copy_to_user(buf, tmp, ret)) |
| 111 | kfree(tmp_buffer); | 109 | ret = -EFAULT; |
| 112 | return -EFAULT; | ||
| 113 | } | ||
| 114 | 110 | ||
| 115 | kfree(tmp_buffer); | 111 | out: |
| 116 | return len; | 112 | kfree(tmp); |
| 113 | return ret; | ||
| 117 | 114 | ||
| 118 | } | 115 | } |
| 119 | 116 | ||
| 120 | static ssize_t dev_nvram_write(struct file *file, const char __user *buf, | 117 | static ssize_t dev_nvram_write(struct file *file, const char __user *buf, |
| 121 | size_t count, loff_t *ppos) | 118 | size_t count, loff_t *ppos) |
| 122 | { | 119 | { |
| 123 | ssize_t len; | 120 | ssize_t ret; |
| 124 | char * tmp_buffer; | 121 | char *tmp = NULL; |
| 125 | int size; | 122 | ssize_t size; |
| 126 | 123 | ||
| 127 | if (ppc_md.nvram_size == NULL) | 124 | ret = -ENODEV; |
| 128 | return -ENODEV; | 125 | if (!ppc_md.nvram_size) |
| 126 | goto out; | ||
| 127 | |||
| 128 | ret = 0; | ||
| 129 | size = ppc_md.nvram_size(); | 129 | size = ppc_md.nvram_size(); |
| 130 | if (*ppos >= size || size < 0) | ||
| 131 | goto out; | ||
| 130 | 132 | ||
| 131 | if (!access_ok(VERIFY_READ, buf, count)) | 133 | count = min_t(size_t, count, size - *ppos); |
| 132 | return -EFAULT; | 134 | count = min(count, PAGE_SIZE); |
| 133 | if (*ppos >= size) | ||
| 134 | return 0; | ||
| 135 | if (count > size) | ||
| 136 | count = size; | ||
| 137 | 135 | ||
| 138 | tmp_buffer = (char *) kmalloc(count, GFP_KERNEL); | 136 | ret = -ENOMEM; |
| 139 | if (!tmp_buffer) { | 137 | tmp = kmalloc(count, GFP_KERNEL); |
| 140 | printk(KERN_ERR "dev_nvram_write: kmalloc failed\n"); | 138 | if (!tmp) |
| 141 | return -ENOMEM; | 139 | goto out; |
| 142 | } | ||
| 143 | |||
| 144 | if (copy_from_user(tmp_buffer, buf, count)) { | ||
| 145 | kfree(tmp_buffer); | ||
| 146 | return -EFAULT; | ||
| 147 | } | ||
| 148 | 140 | ||
| 149 | len = ppc_md.nvram_write(tmp_buffer, count, ppos); | 141 | ret = -EFAULT; |
| 150 | if ((long)len <= 0) { | 142 | if (copy_from_user(tmp, buf, count)) |
| 151 | kfree(tmp_buffer); | 143 | goto out; |
| 152 | return len; | 144 | |
| 153 | } | 145 | ret = ppc_md.nvram_write(tmp, count, ppos); |
| 146 | |||
| 147 | out: | ||
| 148 | kfree(tmp); | ||
| 149 | return ret; | ||
| 154 | 150 | ||
| 155 | kfree(tmp_buffer); | ||
| 156 | return len; | ||
| 157 | } | 151 | } |
| 158 | 152 | ||
| 159 | static int dev_nvram_ioctl(struct inode *inode, struct file *file, | 153 | static int dev_nvram_ioctl(struct inode *inode, struct file *file, |
