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, |