Commit e18ed145c7f556f1de8350c32739bf35b26df705

Authored by Christian Engelmayer
Committed by David S. Miller
1 parent 2bf427b25b

ide: memory overrun in ide_get_identity_ioctl() on big endian machines using ioc…

…tl HDIO_OBSOLETE_IDENTITY

This patch fixes a memory overrun in function ide_get_identity_ioctl() which
chooses the size of a memory buffer depending on the ioctl command that led
to the function call, however, passes that buffer to a function which needs the
buffer size to be always chosen unconditionally.

Due to conditional compilation the memory overrun can only happen on big endian
machines. The error can be triggered using ioctl HDIO_OBSOLETE_IDENTITY. Usage
of ioctl HDIO_GET_IDENTITY is safe.

Signed-off-by: Christian Engelmayer <christian.engelmayer@frequentis.com>
Acked-by: Bartlomiej Zolnierkiewicz <bzolnier@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

Showing 1 changed file with 2 additions and 1 deletions Inline Diff

drivers/ide/ide-ioctls.c
1 /* 1 /*
2 * IDE ioctls handling. 2 * IDE ioctls handling.
3 */ 3 */
4 4
5 #include <linux/hdreg.h> 5 #include <linux/hdreg.h>
6 #include <linux/ide.h> 6 #include <linux/ide.h>
7 7
8 static const struct ide_ioctl_devset ide_ioctl_settings[] = { 8 static const struct ide_ioctl_devset ide_ioctl_settings[] = {
9 { HDIO_GET_32BIT, HDIO_SET_32BIT, &ide_devset_io_32bit }, 9 { HDIO_GET_32BIT, HDIO_SET_32BIT, &ide_devset_io_32bit },
10 { HDIO_GET_KEEPSETTINGS, HDIO_SET_KEEPSETTINGS, &ide_devset_keepsettings }, 10 { HDIO_GET_KEEPSETTINGS, HDIO_SET_KEEPSETTINGS, &ide_devset_keepsettings },
11 { HDIO_GET_UNMASKINTR, HDIO_SET_UNMASKINTR, &ide_devset_unmaskirq }, 11 { HDIO_GET_UNMASKINTR, HDIO_SET_UNMASKINTR, &ide_devset_unmaskirq },
12 { HDIO_GET_DMA, HDIO_SET_DMA, &ide_devset_using_dma }, 12 { HDIO_GET_DMA, HDIO_SET_DMA, &ide_devset_using_dma },
13 { -1, HDIO_SET_PIO_MODE, &ide_devset_pio_mode }, 13 { -1, HDIO_SET_PIO_MODE, &ide_devset_pio_mode },
14 { 0 } 14 { 0 }
15 }; 15 };
16 16
17 int ide_setting_ioctl(ide_drive_t *drive, struct block_device *bdev, 17 int ide_setting_ioctl(ide_drive_t *drive, struct block_device *bdev,
18 unsigned int cmd, unsigned long arg, 18 unsigned int cmd, unsigned long arg,
19 const struct ide_ioctl_devset *s) 19 const struct ide_ioctl_devset *s)
20 { 20 {
21 const struct ide_devset *ds; 21 const struct ide_devset *ds;
22 int err = -EOPNOTSUPP; 22 int err = -EOPNOTSUPP;
23 23
24 for (; (ds = s->setting); s++) { 24 for (; (ds = s->setting); s++) {
25 if (ds->get && s->get_ioctl == cmd) 25 if (ds->get && s->get_ioctl == cmd)
26 goto read_val; 26 goto read_val;
27 else if (ds->set && s->set_ioctl == cmd) 27 else if (ds->set && s->set_ioctl == cmd)
28 goto set_val; 28 goto set_val;
29 } 29 }
30 30
31 return err; 31 return err;
32 32
33 read_val: 33 read_val:
34 mutex_lock(&ide_setting_mtx); 34 mutex_lock(&ide_setting_mtx);
35 err = ds->get(drive); 35 err = ds->get(drive);
36 mutex_unlock(&ide_setting_mtx); 36 mutex_unlock(&ide_setting_mtx);
37 return err >= 0 ? put_user(err, (long __user *)arg) : err; 37 return err >= 0 ? put_user(err, (long __user *)arg) : err;
38 38
39 set_val: 39 set_val:
40 if (bdev != bdev->bd_contains) 40 if (bdev != bdev->bd_contains)
41 err = -EINVAL; 41 err = -EINVAL;
42 else { 42 else {
43 if (!capable(CAP_SYS_ADMIN)) 43 if (!capable(CAP_SYS_ADMIN))
44 err = -EACCES; 44 err = -EACCES;
45 else { 45 else {
46 mutex_lock(&ide_setting_mtx); 46 mutex_lock(&ide_setting_mtx);
47 err = ide_devset_execute(drive, ds, arg); 47 err = ide_devset_execute(drive, ds, arg);
48 mutex_unlock(&ide_setting_mtx); 48 mutex_unlock(&ide_setting_mtx);
49 } 49 }
50 } 50 }
51 return err; 51 return err;
52 } 52 }
53 EXPORT_SYMBOL_GPL(ide_setting_ioctl); 53 EXPORT_SYMBOL_GPL(ide_setting_ioctl);
54 54
55 static int ide_get_identity_ioctl(ide_drive_t *drive, unsigned int cmd, 55 static int ide_get_identity_ioctl(ide_drive_t *drive, unsigned int cmd,
56 unsigned long arg) 56 unsigned long arg)
57 { 57 {
58 u16 *id = NULL; 58 u16 *id = NULL;
59 int size = (cmd == HDIO_GET_IDENTITY) ? (ATA_ID_WORDS * 2) : 142; 59 int size = (cmd == HDIO_GET_IDENTITY) ? (ATA_ID_WORDS * 2) : 142;
60 int rc = 0; 60 int rc = 0;
61 61
62 if ((drive->dev_flags & IDE_DFLAG_ID_READ) == 0) { 62 if ((drive->dev_flags & IDE_DFLAG_ID_READ) == 0) {
63 rc = -ENOMSG; 63 rc = -ENOMSG;
64 goto out; 64 goto out;
65 } 65 }
66 66
67 id = kmalloc(size, GFP_KERNEL); 67 /* ata_id_to_hd_driveid() relies on 'id' to be fully allocated. */
68 id = kmalloc(ATA_ID_WORDS * 2, GFP_KERNEL);
68 if (id == NULL) { 69 if (id == NULL) {
69 rc = -ENOMEM; 70 rc = -ENOMEM;
70 goto out; 71 goto out;
71 } 72 }
72 73
73 memcpy(id, drive->id, size); 74 memcpy(id, drive->id, size);
74 ata_id_to_hd_driveid(id); 75 ata_id_to_hd_driveid(id);
75 76
76 if (copy_to_user((void __user *)arg, id, size)) 77 if (copy_to_user((void __user *)arg, id, size))
77 rc = -EFAULT; 78 rc = -EFAULT;
78 79
79 kfree(id); 80 kfree(id);
80 out: 81 out:
81 return rc; 82 return rc;
82 } 83 }
83 84
84 static int ide_get_nice_ioctl(ide_drive_t *drive, unsigned long arg) 85 static int ide_get_nice_ioctl(ide_drive_t *drive, unsigned long arg)
85 { 86 {
86 return put_user((!!(drive->dev_flags & IDE_DFLAG_DSC_OVERLAP) 87 return put_user((!!(drive->dev_flags & IDE_DFLAG_DSC_OVERLAP)
87 << IDE_NICE_DSC_OVERLAP) | 88 << IDE_NICE_DSC_OVERLAP) |
88 (!!(drive->dev_flags & IDE_DFLAG_NICE1) 89 (!!(drive->dev_flags & IDE_DFLAG_NICE1)
89 << IDE_NICE_1), (long __user *)arg); 90 << IDE_NICE_1), (long __user *)arg);
90 } 91 }
91 92
92 static int ide_set_nice_ioctl(ide_drive_t *drive, unsigned long arg) 93 static int ide_set_nice_ioctl(ide_drive_t *drive, unsigned long arg)
93 { 94 {
94 if (arg != (arg & ((1 << IDE_NICE_DSC_OVERLAP) | (1 << IDE_NICE_1)))) 95 if (arg != (arg & ((1 << IDE_NICE_DSC_OVERLAP) | (1 << IDE_NICE_1))))
95 return -EPERM; 96 return -EPERM;
96 97
97 if (((arg >> IDE_NICE_DSC_OVERLAP) & 1) && 98 if (((arg >> IDE_NICE_DSC_OVERLAP) & 1) &&
98 (drive->media != ide_tape)) 99 (drive->media != ide_tape))
99 return -EPERM; 100 return -EPERM;
100 101
101 if ((arg >> IDE_NICE_DSC_OVERLAP) & 1) 102 if ((arg >> IDE_NICE_DSC_OVERLAP) & 1)
102 drive->dev_flags |= IDE_DFLAG_DSC_OVERLAP; 103 drive->dev_flags |= IDE_DFLAG_DSC_OVERLAP;
103 else 104 else
104 drive->dev_flags &= ~IDE_DFLAG_DSC_OVERLAP; 105 drive->dev_flags &= ~IDE_DFLAG_DSC_OVERLAP;
105 106
106 if ((arg >> IDE_NICE_1) & 1) 107 if ((arg >> IDE_NICE_1) & 1)
107 drive->dev_flags |= IDE_DFLAG_NICE1; 108 drive->dev_flags |= IDE_DFLAG_NICE1;
108 else 109 else
109 drive->dev_flags &= ~IDE_DFLAG_NICE1; 110 drive->dev_flags &= ~IDE_DFLAG_NICE1;
110 111
111 return 0; 112 return 0;
112 } 113 }
113 114
114 static int ide_cmd_ioctl(ide_drive_t *drive, unsigned long arg) 115 static int ide_cmd_ioctl(ide_drive_t *drive, unsigned long arg)
115 { 116 {
116 u8 *buf = NULL; 117 u8 *buf = NULL;
117 int bufsize = 0, err = 0; 118 int bufsize = 0, err = 0;
118 u8 args[4], xfer_rate = 0; 119 u8 args[4], xfer_rate = 0;
119 struct ide_cmd cmd; 120 struct ide_cmd cmd;
120 struct ide_taskfile *tf = &cmd.tf; 121 struct ide_taskfile *tf = &cmd.tf;
121 122
122 if (NULL == (void *) arg) { 123 if (NULL == (void *) arg) {
123 struct request *rq; 124 struct request *rq;
124 125
125 rq = blk_get_request(drive->queue, READ, __GFP_WAIT); 126 rq = blk_get_request(drive->queue, READ, __GFP_WAIT);
126 rq->cmd_type = REQ_TYPE_ATA_TASKFILE; 127 rq->cmd_type = REQ_TYPE_ATA_TASKFILE;
127 err = blk_execute_rq(drive->queue, NULL, rq, 0); 128 err = blk_execute_rq(drive->queue, NULL, rq, 0);
128 blk_put_request(rq); 129 blk_put_request(rq);
129 130
130 return err; 131 return err;
131 } 132 }
132 133
133 if (copy_from_user(args, (void __user *)arg, 4)) 134 if (copy_from_user(args, (void __user *)arg, 4))
134 return -EFAULT; 135 return -EFAULT;
135 136
136 memset(&cmd, 0, sizeof(cmd)); 137 memset(&cmd, 0, sizeof(cmd));
137 tf->feature = args[2]; 138 tf->feature = args[2];
138 if (args[0] == ATA_CMD_SMART) { 139 if (args[0] == ATA_CMD_SMART) {
139 tf->nsect = args[3]; 140 tf->nsect = args[3];
140 tf->lbal = args[1]; 141 tf->lbal = args[1];
141 tf->lbam = 0x4f; 142 tf->lbam = 0x4f;
142 tf->lbah = 0xc2; 143 tf->lbah = 0xc2;
143 cmd.valid.out.tf = IDE_VALID_OUT_TF; 144 cmd.valid.out.tf = IDE_VALID_OUT_TF;
144 cmd.valid.in.tf = IDE_VALID_NSECT; 145 cmd.valid.in.tf = IDE_VALID_NSECT;
145 } else { 146 } else {
146 tf->nsect = args[1]; 147 tf->nsect = args[1];
147 cmd.valid.out.tf = IDE_VALID_FEATURE | IDE_VALID_NSECT; 148 cmd.valid.out.tf = IDE_VALID_FEATURE | IDE_VALID_NSECT;
148 cmd.valid.in.tf = IDE_VALID_NSECT; 149 cmd.valid.in.tf = IDE_VALID_NSECT;
149 } 150 }
150 tf->command = args[0]; 151 tf->command = args[0];
151 cmd.protocol = args[3] ? ATA_PROT_PIO : ATA_PROT_NODATA; 152 cmd.protocol = args[3] ? ATA_PROT_PIO : ATA_PROT_NODATA;
152 153
153 if (args[3]) { 154 if (args[3]) {
154 cmd.tf_flags |= IDE_TFLAG_IO_16BIT; 155 cmd.tf_flags |= IDE_TFLAG_IO_16BIT;
155 bufsize = SECTOR_SIZE * args[3]; 156 bufsize = SECTOR_SIZE * args[3];
156 buf = kzalloc(bufsize, GFP_KERNEL); 157 buf = kzalloc(bufsize, GFP_KERNEL);
157 if (buf == NULL) 158 if (buf == NULL)
158 return -ENOMEM; 159 return -ENOMEM;
159 } 160 }
160 161
161 if (tf->command == ATA_CMD_SET_FEATURES && 162 if (tf->command == ATA_CMD_SET_FEATURES &&
162 tf->feature == SETFEATURES_XFER && 163 tf->feature == SETFEATURES_XFER &&
163 tf->nsect >= XFER_SW_DMA_0) { 164 tf->nsect >= XFER_SW_DMA_0) {
164 xfer_rate = ide_find_dma_mode(drive, XFER_UDMA_6); 165 xfer_rate = ide_find_dma_mode(drive, XFER_UDMA_6);
165 if (xfer_rate != tf->nsect) { 166 if (xfer_rate != tf->nsect) {
166 err = -EINVAL; 167 err = -EINVAL;
167 goto abort; 168 goto abort;
168 } 169 }
169 } 170 }
170 171
171 err = ide_raw_taskfile(drive, &cmd, buf, args[3]); 172 err = ide_raw_taskfile(drive, &cmd, buf, args[3]);
172 173
173 args[0] = tf->status; 174 args[0] = tf->status;
174 args[1] = tf->error; 175 args[1] = tf->error;
175 args[2] = tf->nsect; 176 args[2] = tf->nsect;
176 177
177 if (!err && xfer_rate) { 178 if (!err && xfer_rate) {
178 /* active-retuning-calls future */ 179 /* active-retuning-calls future */
179 ide_set_xfer_rate(drive, xfer_rate); 180 ide_set_xfer_rate(drive, xfer_rate);
180 ide_driveid_update(drive); 181 ide_driveid_update(drive);
181 } 182 }
182 abort: 183 abort:
183 if (copy_to_user((void __user *)arg, &args, 4)) 184 if (copy_to_user((void __user *)arg, &args, 4))
184 err = -EFAULT; 185 err = -EFAULT;
185 if (buf) { 186 if (buf) {
186 if (copy_to_user((void __user *)(arg + 4), buf, bufsize)) 187 if (copy_to_user((void __user *)(arg + 4), buf, bufsize))
187 err = -EFAULT; 188 err = -EFAULT;
188 kfree(buf); 189 kfree(buf);
189 } 190 }
190 return err; 191 return err;
191 } 192 }
192 193
193 static int ide_task_ioctl(ide_drive_t *drive, unsigned long arg) 194 static int ide_task_ioctl(ide_drive_t *drive, unsigned long arg)
194 { 195 {
195 void __user *p = (void __user *)arg; 196 void __user *p = (void __user *)arg;
196 int err = 0; 197 int err = 0;
197 u8 args[7]; 198 u8 args[7];
198 struct ide_cmd cmd; 199 struct ide_cmd cmd;
199 200
200 if (copy_from_user(args, p, 7)) 201 if (copy_from_user(args, p, 7))
201 return -EFAULT; 202 return -EFAULT;
202 203
203 memset(&cmd, 0, sizeof(cmd)); 204 memset(&cmd, 0, sizeof(cmd));
204 memcpy(&cmd.tf.feature, &args[1], 6); 205 memcpy(&cmd.tf.feature, &args[1], 6);
205 cmd.tf.command = args[0]; 206 cmd.tf.command = args[0];
206 cmd.valid.out.tf = IDE_VALID_OUT_TF | IDE_VALID_DEVICE; 207 cmd.valid.out.tf = IDE_VALID_OUT_TF | IDE_VALID_DEVICE;
207 cmd.valid.in.tf = IDE_VALID_IN_TF | IDE_VALID_DEVICE; 208 cmd.valid.in.tf = IDE_VALID_IN_TF | IDE_VALID_DEVICE;
208 209
209 err = ide_no_data_taskfile(drive, &cmd); 210 err = ide_no_data_taskfile(drive, &cmd);
210 211
211 args[0] = cmd.tf.command; 212 args[0] = cmd.tf.command;
212 memcpy(&args[1], &cmd.tf.feature, 6); 213 memcpy(&args[1], &cmd.tf.feature, 6);
213 214
214 if (copy_to_user(p, args, 7)) 215 if (copy_to_user(p, args, 7))
215 err = -EFAULT; 216 err = -EFAULT;
216 217
217 return err; 218 return err;
218 } 219 }
219 220
220 static int generic_drive_reset(ide_drive_t *drive) 221 static int generic_drive_reset(ide_drive_t *drive)
221 { 222 {
222 struct request *rq; 223 struct request *rq;
223 int ret = 0; 224 int ret = 0;
224 225
225 rq = blk_get_request(drive->queue, READ, __GFP_WAIT); 226 rq = blk_get_request(drive->queue, READ, __GFP_WAIT);
226 rq->cmd_type = REQ_TYPE_SPECIAL; 227 rq->cmd_type = REQ_TYPE_SPECIAL;
227 rq->cmd_len = 1; 228 rq->cmd_len = 1;
228 rq->cmd[0] = REQ_DRIVE_RESET; 229 rq->cmd[0] = REQ_DRIVE_RESET;
229 if (blk_execute_rq(drive->queue, NULL, rq, 1)) 230 if (blk_execute_rq(drive->queue, NULL, rq, 1))
230 ret = rq->errors; 231 ret = rq->errors;
231 blk_put_request(rq); 232 blk_put_request(rq);
232 return ret; 233 return ret;
233 } 234 }
234 235
235 int generic_ide_ioctl(ide_drive_t *drive, struct block_device *bdev, 236 int generic_ide_ioctl(ide_drive_t *drive, struct block_device *bdev,
236 unsigned int cmd, unsigned long arg) 237 unsigned int cmd, unsigned long arg)
237 { 238 {
238 int err; 239 int err;
239 240
240 err = ide_setting_ioctl(drive, bdev, cmd, arg, ide_ioctl_settings); 241 err = ide_setting_ioctl(drive, bdev, cmd, arg, ide_ioctl_settings);
241 if (err != -EOPNOTSUPP) 242 if (err != -EOPNOTSUPP)
242 return err; 243 return err;
243 244
244 switch (cmd) { 245 switch (cmd) {
245 case HDIO_OBSOLETE_IDENTITY: 246 case HDIO_OBSOLETE_IDENTITY:
246 case HDIO_GET_IDENTITY: 247 case HDIO_GET_IDENTITY:
247 if (bdev != bdev->bd_contains) 248 if (bdev != bdev->bd_contains)
248 return -EINVAL; 249 return -EINVAL;
249 return ide_get_identity_ioctl(drive, cmd, arg); 250 return ide_get_identity_ioctl(drive, cmd, arg);
250 case HDIO_GET_NICE: 251 case HDIO_GET_NICE:
251 return ide_get_nice_ioctl(drive, arg); 252 return ide_get_nice_ioctl(drive, arg);
252 case HDIO_SET_NICE: 253 case HDIO_SET_NICE:
253 if (!capable(CAP_SYS_ADMIN)) 254 if (!capable(CAP_SYS_ADMIN))
254 return -EACCES; 255 return -EACCES;
255 return ide_set_nice_ioctl(drive, arg); 256 return ide_set_nice_ioctl(drive, arg);
256 #ifdef CONFIG_IDE_TASK_IOCTL 257 #ifdef CONFIG_IDE_TASK_IOCTL
257 case HDIO_DRIVE_TASKFILE: 258 case HDIO_DRIVE_TASKFILE:
258 if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO)) 259 if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
259 return -EACCES; 260 return -EACCES;
260 if (drive->media == ide_disk) 261 if (drive->media == ide_disk)
261 return ide_taskfile_ioctl(drive, arg); 262 return ide_taskfile_ioctl(drive, arg);
262 return -ENOMSG; 263 return -ENOMSG;
263 #endif 264 #endif
264 case HDIO_DRIVE_CMD: 265 case HDIO_DRIVE_CMD:
265 if (!capable(CAP_SYS_RAWIO)) 266 if (!capable(CAP_SYS_RAWIO))
266 return -EACCES; 267 return -EACCES;
267 return ide_cmd_ioctl(drive, arg); 268 return ide_cmd_ioctl(drive, arg);
268 case HDIO_DRIVE_TASK: 269 case HDIO_DRIVE_TASK:
269 if (!capable(CAP_SYS_RAWIO)) 270 if (!capable(CAP_SYS_RAWIO))
270 return -EACCES; 271 return -EACCES;
271 return ide_task_ioctl(drive, arg); 272 return ide_task_ioctl(drive, arg);
272 case HDIO_DRIVE_RESET: 273 case HDIO_DRIVE_RESET:
273 if (!capable(CAP_SYS_ADMIN)) 274 if (!capable(CAP_SYS_ADMIN))
274 return -EACCES; 275 return -EACCES;
275 return generic_drive_reset(drive); 276 return generic_drive_reset(drive);
276 case HDIO_GET_BUSSTATE: 277 case HDIO_GET_BUSSTATE:
277 if (!capable(CAP_SYS_ADMIN)) 278 if (!capable(CAP_SYS_ADMIN))
278 return -EACCES; 279 return -EACCES;
279 if (put_user(BUSSTATE_ON, (long __user *)arg)) 280 if (put_user(BUSSTATE_ON, (long __user *)arg))
280 return -EFAULT; 281 return -EFAULT;
281 return 0; 282 return 0;
282 case HDIO_SET_BUSSTATE: 283 case HDIO_SET_BUSSTATE:
283 if (!capable(CAP_SYS_ADMIN)) 284 if (!capable(CAP_SYS_ADMIN))
284 return -EACCES; 285 return -EACCES;
285 return -EOPNOTSUPP; 286 return -EOPNOTSUPP;
286 default: 287 default:
287 return -EINVAL; 288 return -EINVAL;
288 } 289 }
289 } 290 }
290 EXPORT_SYMBOL(generic_ide_ioctl); 291 EXPORT_SYMBOL(generic_ide_ioctl);
291 292