diff options
| -rw-r--r-- | drivers/block/loop.c | 160 | ||||
| -rw-r--r-- | fs/compat_ioctl.c | 68 | ||||
| -rw-r--r-- | include/linux/compat_ioctl.h | 6 |
3 files changed, 160 insertions, 74 deletions
diff --git a/drivers/block/loop.c b/drivers/block/loop.c index 68b0471ad5a6..d6bb8da955a2 100644 --- a/drivers/block/loop.c +++ b/drivers/block/loop.c | |||
| @@ -66,6 +66,7 @@ | |||
| 66 | #include <linux/swap.h> | 66 | #include <linux/swap.h> |
| 67 | #include <linux/slab.h> | 67 | #include <linux/slab.h> |
| 68 | #include <linux/loop.h> | 68 | #include <linux/loop.h> |
| 69 | #include <linux/compat.h> | ||
| 69 | #include <linux/suspend.h> | 70 | #include <linux/suspend.h> |
| 70 | #include <linux/writeback.h> | 71 | #include <linux/writeback.h> |
| 71 | #include <linux/buffer_head.h> /* for invalidate_bdev() */ | 72 | #include <linux/buffer_head.h> /* for invalidate_bdev() */ |
| @@ -1165,6 +1166,162 @@ static int lo_ioctl(struct inode * inode, struct file * file, | |||
| 1165 | return err; | 1166 | return err; |
| 1166 | } | 1167 | } |
| 1167 | 1168 | ||
| 1169 | #ifdef CONFIG_COMPAT | ||
| 1170 | struct compat_loop_info { | ||
| 1171 | compat_int_t lo_number; /* ioctl r/o */ | ||
| 1172 | compat_dev_t lo_device; /* ioctl r/o */ | ||
| 1173 | compat_ulong_t lo_inode; /* ioctl r/o */ | ||
| 1174 | compat_dev_t lo_rdevice; /* ioctl r/o */ | ||
| 1175 | compat_int_t lo_offset; | ||
| 1176 | compat_int_t lo_encrypt_type; | ||
| 1177 | compat_int_t lo_encrypt_key_size; /* ioctl w/o */ | ||
| 1178 | compat_int_t lo_flags; /* ioctl r/o */ | ||
| 1179 | char lo_name[LO_NAME_SIZE]; | ||
| 1180 | unsigned char lo_encrypt_key[LO_KEY_SIZE]; /* ioctl w/o */ | ||
| 1181 | compat_ulong_t lo_init[2]; | ||
| 1182 | char reserved[4]; | ||
| 1183 | }; | ||
| 1184 | |||
| 1185 | /* | ||
| 1186 | * Transfer 32-bit compatibility structure in userspace to 64-bit loop info | ||
| 1187 | * - noinlined to reduce stack space usage in main part of driver | ||
| 1188 | */ | ||
| 1189 | static noinline int | ||
| 1190 | loop_info64_from_compat(const struct compat_loop_info *arg, | ||
| 1191 | struct loop_info64 *info64) | ||
| 1192 | { | ||
| 1193 | struct compat_loop_info info; | ||
| 1194 | |||
| 1195 | if (copy_from_user(&info, arg, sizeof(info))) | ||
| 1196 | return -EFAULT; | ||
| 1197 | |||
| 1198 | memset(info64, 0, sizeof(*info64)); | ||
| 1199 | info64->lo_number = info.lo_number; | ||
| 1200 | info64->lo_device = info.lo_device; | ||
| 1201 | info64->lo_inode = info.lo_inode; | ||
| 1202 | info64->lo_rdevice = info.lo_rdevice; | ||
| 1203 | info64->lo_offset = info.lo_offset; | ||
| 1204 | info64->lo_sizelimit = 0; | ||
| 1205 | info64->lo_encrypt_type = info.lo_encrypt_type; | ||
| 1206 | info64->lo_encrypt_key_size = info.lo_encrypt_key_size; | ||
| 1207 | info64->lo_flags = info.lo_flags; | ||
| 1208 | info64->lo_init[0] = info.lo_init[0]; | ||
| 1209 | info64->lo_init[1] = info.lo_init[1]; | ||
| 1210 | if (info.lo_encrypt_type == LO_CRYPT_CRYPTOAPI) | ||
| 1211 | memcpy(info64->lo_crypt_name, info.lo_name, LO_NAME_SIZE); | ||
| 1212 | else | ||
| 1213 | memcpy(info64->lo_file_name, info.lo_name, LO_NAME_SIZE); | ||
| 1214 | memcpy(info64->lo_encrypt_key, info.lo_encrypt_key, LO_KEY_SIZE); | ||
| 1215 | return 0; | ||
| 1216 | } | ||
| 1217 | |||
| 1218 | /* | ||
| 1219 | * Transfer 64-bit loop info to 32-bit compatibility structure in userspace | ||
| 1220 | * - noinlined to reduce stack space usage in main part of driver | ||
| 1221 | */ | ||
| 1222 | static noinline int | ||
| 1223 | loop_info64_to_compat(const struct loop_info64 *info64, | ||
| 1224 | struct compat_loop_info __user *arg) | ||
| 1225 | { | ||
| 1226 | struct compat_loop_info info; | ||
| 1227 | |||
| 1228 | memset(&info, 0, sizeof(info)); | ||
| 1229 | info.lo_number = info64->lo_number; | ||
| 1230 | info.lo_device = info64->lo_device; | ||
| 1231 | info.lo_inode = info64->lo_inode; | ||
| 1232 | info.lo_rdevice = info64->lo_rdevice; | ||
| 1233 | info.lo_offset = info64->lo_offset; | ||
| 1234 | info.lo_encrypt_type = info64->lo_encrypt_type; | ||
| 1235 | info.lo_encrypt_key_size = info64->lo_encrypt_key_size; | ||
| 1236 | info.lo_flags = info64->lo_flags; | ||
| 1237 | info.lo_init[0] = info64->lo_init[0]; | ||
| 1238 | info.lo_init[1] = info64->lo_init[1]; | ||
| 1239 | if (info.lo_encrypt_type == LO_CRYPT_CRYPTOAPI) | ||
| 1240 | memcpy(info.lo_name, info64->lo_crypt_name, LO_NAME_SIZE); | ||
| 1241 | else | ||
| 1242 | memcpy(info.lo_name, info64->lo_file_name, LO_NAME_SIZE); | ||
| 1243 | memcpy(info.lo_encrypt_key, info64->lo_encrypt_key, LO_KEY_SIZE); | ||
| 1244 | |||
| 1245 | /* error in case values were truncated */ | ||
| 1246 | if (info.lo_device != info64->lo_device || | ||
| 1247 | info.lo_rdevice != info64->lo_rdevice || | ||
| 1248 | info.lo_inode != info64->lo_inode || | ||
| 1249 | info.lo_offset != info64->lo_offset || | ||
| 1250 | info.lo_init[0] != info64->lo_init[0] || | ||
| 1251 | info.lo_init[1] != info64->lo_init[1]) | ||
| 1252 | return -EOVERFLOW; | ||
| 1253 | |||
| 1254 | if (copy_to_user(arg, &info, sizeof(info))) | ||
| 1255 | return -EFAULT; | ||
| 1256 | return 0; | ||
| 1257 | } | ||
| 1258 | |||
| 1259 | static int | ||
| 1260 | loop_set_status_compat(struct loop_device *lo, | ||
| 1261 | const struct compat_loop_info __user *arg) | ||
| 1262 | { | ||
| 1263 | struct loop_info64 info64; | ||
| 1264 | int ret; | ||
| 1265 | |||
| 1266 | ret = loop_info64_from_compat(arg, &info64); | ||
| 1267 | if (ret < 0) | ||
| 1268 | return ret; | ||
| 1269 | return loop_set_status(lo, &info64); | ||
| 1270 | } | ||
| 1271 | |||
| 1272 | static int | ||
| 1273 | loop_get_status_compat(struct loop_device *lo, | ||
| 1274 | struct compat_loop_info __user *arg) | ||
| 1275 | { | ||
| 1276 | struct loop_info64 info64; | ||
| 1277 | int err = 0; | ||
| 1278 | |||
| 1279 | if (!arg) | ||
| 1280 | err = -EINVAL; | ||
| 1281 | if (!err) | ||
| 1282 | err = loop_get_status(lo, &info64); | ||
| 1283 | if (!err) | ||
| 1284 | err = loop_info64_to_compat(&info64, arg); | ||
| 1285 | return err; | ||
| 1286 | } | ||
| 1287 | |||
| 1288 | static long lo_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | ||
| 1289 | { | ||
| 1290 | struct inode *inode = file->f_dentry->d_inode; | ||
| 1291 | struct loop_device *lo = inode->i_bdev->bd_disk->private_data; | ||
| 1292 | int err; | ||
| 1293 | |||
| 1294 | lock_kernel(); | ||
| 1295 | switch(cmd) { | ||
| 1296 | case LOOP_SET_STATUS: | ||
| 1297 | mutex_lock(&lo->lo_ctl_mutex); | ||
| 1298 | err = loop_set_status_compat( | ||
| 1299 | lo, (const struct compat_loop_info __user *) arg); | ||
| 1300 | mutex_unlock(&lo->lo_ctl_mutex); | ||
| 1301 | break; | ||
| 1302 | case LOOP_GET_STATUS: | ||
| 1303 | mutex_lock(&lo->lo_ctl_mutex); | ||
| 1304 | err = loop_get_status_compat( | ||
| 1305 | lo, (struct compat_loop_info __user *) arg); | ||
| 1306 | mutex_unlock(&lo->lo_ctl_mutex); | ||
| 1307 | break; | ||
| 1308 | case LOOP_CLR_FD: | ||
| 1309 | case LOOP_GET_STATUS64: | ||
| 1310 | case LOOP_SET_STATUS64: | ||
| 1311 | arg = (unsigned long) compat_ptr(arg); | ||
| 1312 | case LOOP_SET_FD: | ||
| 1313 | case LOOP_CHANGE_FD: | ||
| 1314 | err = lo_ioctl(inode, file, cmd, arg); | ||
| 1315 | break; | ||
| 1316 | default: | ||
| 1317 | err = -ENOIOCTLCMD; | ||
| 1318 | break; | ||
| 1319 | } | ||
| 1320 | unlock_kernel(); | ||
| 1321 | return err; | ||
| 1322 | } | ||
| 1323 | #endif | ||
| 1324 | |||
| 1168 | static int lo_open(struct inode *inode, struct file *file) | 1325 | static int lo_open(struct inode *inode, struct file *file) |
| 1169 | { | 1326 | { |
| 1170 | struct loop_device *lo = inode->i_bdev->bd_disk->private_data; | 1327 | struct loop_device *lo = inode->i_bdev->bd_disk->private_data; |
| @@ -1192,6 +1349,9 @@ static struct block_device_operations lo_fops = { | |||
| 1192 | .open = lo_open, | 1349 | .open = lo_open, |
| 1193 | .release = lo_release, | 1350 | .release = lo_release, |
| 1194 | .ioctl = lo_ioctl, | 1351 | .ioctl = lo_ioctl, |
| 1352 | #ifdef CONFIG_COMPAT | ||
| 1353 | .compat_ioctl = lo_compat_ioctl, | ||
| 1354 | #endif | ||
| 1195 | }; | 1355 | }; |
| 1196 | 1356 | ||
| 1197 | /* | 1357 | /* |
diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c index ab74c9bd55fe..3b0cf7fbd95a 100644 --- a/fs/compat_ioctl.c +++ b/fs/compat_ioctl.c | |||
| @@ -40,7 +40,6 @@ | |||
| 40 | #include <linux/if_pppox.h> | 40 | #include <linux/if_pppox.h> |
| 41 | #include <linux/mtio.h> | 41 | #include <linux/mtio.h> |
| 42 | #include <linux/cdrom.h> | 42 | #include <linux/cdrom.h> |
| 43 | #include <linux/loop.h> | ||
| 44 | #include <linux/auto_fs.h> | 43 | #include <linux/auto_fs.h> |
| 45 | #include <linux/auto_fs4.h> | 44 | #include <linux/auto_fs4.h> |
| 46 | #include <linux/tty.h> | 45 | #include <linux/tty.h> |
| @@ -1214,71 +1213,6 @@ static int cdrom_ioctl_trans(unsigned int fd, unsigned int cmd, unsigned long ar | |||
| 1214 | return err; | 1213 | return err; |
| 1215 | } | 1214 | } |
| 1216 | 1215 | ||
| 1217 | struct loop_info32 { | ||
| 1218 | compat_int_t lo_number; /* ioctl r/o */ | ||
| 1219 | compat_dev_t lo_device; /* ioctl r/o */ | ||
| 1220 | compat_ulong_t lo_inode; /* ioctl r/o */ | ||
| 1221 | compat_dev_t lo_rdevice; /* ioctl r/o */ | ||
| 1222 | compat_int_t lo_offset; | ||
| 1223 | compat_int_t lo_encrypt_type; | ||
| 1224 | compat_int_t lo_encrypt_key_size; /* ioctl w/o */ | ||
| 1225 | compat_int_t lo_flags; /* ioctl r/o */ | ||
| 1226 | char lo_name[LO_NAME_SIZE]; | ||
| 1227 | unsigned char lo_encrypt_key[LO_KEY_SIZE]; /* ioctl w/o */ | ||
| 1228 | compat_ulong_t lo_init[2]; | ||
| 1229 | char reserved[4]; | ||
| 1230 | }; | ||
| 1231 | |||
| 1232 | static int loop_status(unsigned int fd, unsigned int cmd, unsigned long arg) | ||
| 1233 | { | ||
| 1234 | mm_segment_t old_fs = get_fs(); | ||
| 1235 | struct loop_info l; | ||
| 1236 | struct loop_info32 __user *ul; | ||
| 1237 | int err = -EINVAL; | ||
| 1238 | |||
| 1239 | ul = compat_ptr(arg); | ||
| 1240 | switch(cmd) { | ||
| 1241 | case LOOP_SET_STATUS: | ||
| 1242 | err = get_user(l.lo_number, &ul->lo_number); | ||
| 1243 | err |= __get_user(l.lo_device, &ul->lo_device); | ||
| 1244 | err |= __get_user(l.lo_inode, &ul->lo_inode); | ||
| 1245 | err |= __get_user(l.lo_rdevice, &ul->lo_rdevice); | ||
| 1246 | err |= __copy_from_user(&l.lo_offset, &ul->lo_offset, | ||
| 1247 | 8 + (unsigned long)l.lo_init - (unsigned long)&l.lo_offset); | ||
| 1248 | if (err) { | ||
| 1249 | err = -EFAULT; | ||
| 1250 | } else { | ||
| 1251 | set_fs (KERNEL_DS); | ||
| 1252 | err = sys_ioctl (fd, cmd, (unsigned long)&l); | ||
| 1253 | set_fs (old_fs); | ||
| 1254 | } | ||
| 1255 | break; | ||
| 1256 | case LOOP_GET_STATUS: | ||
| 1257 | set_fs (KERNEL_DS); | ||
| 1258 | err = sys_ioctl (fd, cmd, (unsigned long)&l); | ||
| 1259 | set_fs (old_fs); | ||
| 1260 | if (!err) { | ||
| 1261 | err = put_user(l.lo_number, &ul->lo_number); | ||
| 1262 | err |= __put_user(l.lo_device, &ul->lo_device); | ||
| 1263 | err |= __put_user(l.lo_inode, &ul->lo_inode); | ||
| 1264 | err |= __put_user(l.lo_rdevice, &ul->lo_rdevice); | ||
| 1265 | err |= __copy_to_user(&ul->lo_offset, &l.lo_offset, | ||
| 1266 | (unsigned long)l.lo_init - (unsigned long)&l.lo_offset); | ||
| 1267 | if (err) | ||
| 1268 | err = -EFAULT; | ||
| 1269 | } | ||
| 1270 | break; | ||
| 1271 | default: { | ||
| 1272 | static int count; | ||
| 1273 | if (++count <= 20) | ||
| 1274 | printk("%s: Unknown loop ioctl cmd, fd(%d) " | ||
| 1275 | "cmd(%08x) arg(%08lx)\n", | ||
| 1276 | __FUNCTION__, fd, cmd, arg); | ||
| 1277 | } | ||
| 1278 | } | ||
| 1279 | return err; | ||
| 1280 | } | ||
| 1281 | |||
| 1282 | #ifdef CONFIG_VT | 1216 | #ifdef CONFIG_VT |
| 1283 | 1217 | ||
| 1284 | static int vt_check(struct file *file) | 1218 | static int vt_check(struct file *file) |
| @@ -2808,8 +2742,6 @@ HANDLE_IOCTL(MTIOCGET32, mt_ioctl_trans) | |||
| 2808 | HANDLE_IOCTL(MTIOCPOS32, mt_ioctl_trans) | 2742 | HANDLE_IOCTL(MTIOCPOS32, mt_ioctl_trans) |
| 2809 | HANDLE_IOCTL(CDROMREADAUDIO, cdrom_ioctl_trans) | 2743 | HANDLE_IOCTL(CDROMREADAUDIO, cdrom_ioctl_trans) |
| 2810 | HANDLE_IOCTL(CDROM_SEND_PACKET, cdrom_ioctl_trans) | 2744 | HANDLE_IOCTL(CDROM_SEND_PACKET, cdrom_ioctl_trans) |
| 2811 | HANDLE_IOCTL(LOOP_SET_STATUS, loop_status) | ||
| 2812 | HANDLE_IOCTL(LOOP_GET_STATUS, loop_status) | ||
| 2813 | #define AUTOFS_IOC_SETTIMEOUT32 _IOWR(0x93,0x64,unsigned int) | 2745 | #define AUTOFS_IOC_SETTIMEOUT32 _IOWR(0x93,0x64,unsigned int) |
| 2814 | HANDLE_IOCTL(AUTOFS_IOC_SETTIMEOUT32, ioc_settimeout) | 2746 | HANDLE_IOCTL(AUTOFS_IOC_SETTIMEOUT32, ioc_settimeout) |
| 2815 | #ifdef CONFIG_VT | 2747 | #ifdef CONFIG_VT |
diff --git a/include/linux/compat_ioctl.h b/include/linux/compat_ioctl.h index bea0255196c4..98d40e08ba6e 100644 --- a/include/linux/compat_ioctl.h +++ b/include/linux/compat_ioctl.h | |||
| @@ -395,12 +395,6 @@ COMPATIBLE_IOCTL(DVD_WRITE_STRUCT) | |||
| 395 | COMPATIBLE_IOCTL(DVD_AUTH) | 395 | COMPATIBLE_IOCTL(DVD_AUTH) |
| 396 | /* pktcdvd */ | 396 | /* pktcdvd */ |
| 397 | COMPATIBLE_IOCTL(PACKET_CTRL_CMD) | 397 | COMPATIBLE_IOCTL(PACKET_CTRL_CMD) |
| 398 | /* Big L */ | ||
| 399 | ULONG_IOCTL(LOOP_SET_FD) | ||
| 400 | ULONG_IOCTL(LOOP_CHANGE_FD) | ||
| 401 | COMPATIBLE_IOCTL(LOOP_CLR_FD) | ||
| 402 | COMPATIBLE_IOCTL(LOOP_GET_STATUS64) | ||
| 403 | COMPATIBLE_IOCTL(LOOP_SET_STATUS64) | ||
| 404 | /* Big A */ | 398 | /* Big A */ |
| 405 | /* sparc only */ | 399 | /* sparc only */ |
| 406 | /* Big Q for sound/OSS */ | 400 | /* Big Q for sound/OSS */ |
