Commit e18ed145c7f556f1de8350c32739bf35b26df705
Committed by
David S. Miller
1 parent
2bf427b25b
Exists in
master
and in
20 other branches
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 |