diff options
-rw-r--r-- | fs/devpts/inode.c | 100 |
1 files changed, 22 insertions, 78 deletions
diff --git a/fs/devpts/inode.c b/fs/devpts/inode.c index fb4da9d89130..70013dd8ec70 100644 --- a/fs/devpts/inode.c +++ b/fs/devpts/inode.c | |||
@@ -322,60 +322,21 @@ static int compare_init_pts_sb(struct super_block *s, void *p) | |||
322 | } | 322 | } |
323 | 323 | ||
324 | /* | 324 | /* |
325 | * Safely parse the mount options in @data and update @opts. | ||
326 | * | ||
327 | * devpts ends up parsing options two times during mount, due to the | ||
328 | * two modes of operation it supports. The first parse occurs in | ||
329 | * devpts_get_sb() when determining the mode (single-instance or | ||
330 | * multi-instance mode). The second parse happens in devpts_remount() | ||
331 | * or new_pts_mount() depending on the mode. | ||
332 | * | ||
333 | * Parsing of options modifies the @data making subsequent parsing | ||
334 | * incorrect. So make a local copy of @data and parse it. | ||
335 | * | ||
336 | * Return: 0 On success, -errno on error | ||
337 | */ | ||
338 | static int safe_parse_mount_options(void *data, struct pts_mount_opts *opts) | ||
339 | { | ||
340 | int rc; | ||
341 | void *datacp; | ||
342 | |||
343 | if (!data) | ||
344 | return 0; | ||
345 | |||
346 | /* Use kstrdup() ? */ | ||
347 | datacp = kmalloc(PAGE_SIZE, GFP_KERNEL); | ||
348 | if (!datacp) | ||
349 | return -ENOMEM; | ||
350 | |||
351 | memcpy(datacp, data, PAGE_SIZE); | ||
352 | rc = parse_mount_options((char *)datacp, PARSE_MOUNT, opts); | ||
353 | kfree(datacp); | ||
354 | |||
355 | return rc; | ||
356 | } | ||
357 | |||
358 | /* | ||
359 | * Mount a new (private) instance of devpts. PTYs created in this | 325 | * Mount a new (private) instance of devpts. PTYs created in this |
360 | * instance are independent of the PTYs in other devpts instances. | 326 | * instance are independent of the PTYs in other devpts instances. |
361 | */ | 327 | */ |
362 | static int new_pts_mount(struct file_system_type *fs_type, int flags, | 328 | static int new_pts_mount(struct file_system_type *fs_type, int flags, |
363 | void *data, struct vfsmount *mnt) | 329 | void *data, struct pts_mount_opts *opts, struct vfsmount *mnt) |
364 | { | 330 | { |
365 | int err; | 331 | int err; |
366 | struct pts_fs_info *fsi; | 332 | struct pts_fs_info *fsi; |
367 | struct pts_mount_opts *opts; | ||
368 | 333 | ||
369 | err = get_sb_nodev(fs_type, flags, data, devpts_fill_super, mnt); | 334 | err = get_sb_nodev(fs_type, flags, data, devpts_fill_super, mnt); |
370 | if (err) | 335 | if (err) |
371 | return err; | 336 | return err; |
372 | 337 | ||
373 | fsi = DEVPTS_SB(mnt->mnt_sb); | 338 | fsi = DEVPTS_SB(mnt->mnt_sb); |
374 | opts = &fsi->mount_opts; | 339 | memcpy(&fsi->mount_opts, opts, sizeof(opts)); |
375 | |||
376 | err = parse_mount_options(data, PARSE_MOUNT, opts); | ||
377 | if (err) | ||
378 | goto fail; | ||
379 | 340 | ||
380 | err = mknod_ptmx(mnt->mnt_sb); | 341 | err = mknod_ptmx(mnt->mnt_sb); |
381 | if (err) | 342 | if (err) |
@@ -391,28 +352,6 @@ fail: | |||
391 | } | 352 | } |
392 | 353 | ||
393 | /* | 354 | /* |
394 | * Check if 'newinstance' mount option was specified in @data. | ||
395 | * | ||
396 | * Return: -errno on error (eg: invalid mount options specified) | ||
397 | * : 1 if 'newinstance' mount option was specified | ||
398 | * : 0 if 'newinstance' mount option was NOT specified | ||
399 | */ | ||
400 | static int is_new_instance_mount(void *data) | ||
401 | { | ||
402 | int rc; | ||
403 | struct pts_mount_opts opts; | ||
404 | |||
405 | if (!data) | ||
406 | return 0; | ||
407 | |||
408 | rc = safe_parse_mount_options(data, &opts); | ||
409 | if (!rc) | ||
410 | rc = opts.newinstance; | ||
411 | |||
412 | return rc; | ||
413 | } | ||
414 | |||
415 | /* | ||
416 | * get_init_pts_sb() | 355 | * get_init_pts_sb() |
417 | * | 356 | * |
418 | * This interface is needed to support multiple namespace semantics in | 357 | * This interface is needed to support multiple namespace semantics in |
@@ -434,10 +373,9 @@ static int is_new_instance_mount(void *data) | |||
434 | * presence of the private namespace (i.e 'newinstance') super-blocks. | 373 | * presence of the private namespace (i.e 'newinstance') super-blocks. |
435 | */ | 374 | */ |
436 | static int get_init_pts_sb(struct file_system_type *fs_type, int flags, | 375 | static int get_init_pts_sb(struct file_system_type *fs_type, int flags, |
437 | void *data, struct vfsmount *mnt) | 376 | void *data, struct pts_mount_opts *opts, struct vfsmount *mnt) |
438 | { | 377 | { |
439 | struct super_block *s; | 378 | struct super_block *s; |
440 | struct pts_mount_opts *opts; | ||
441 | struct pts_fs_info *fsi; | 379 | struct pts_fs_info *fsi; |
442 | int error; | 380 | int error; |
443 | 381 | ||
@@ -455,11 +393,12 @@ static int get_init_pts_sb(struct file_system_type *fs_type, int flags, | |||
455 | } | 393 | } |
456 | s->s_flags |= MS_ACTIVE; | 394 | s->s_flags |= MS_ACTIVE; |
457 | } | 395 | } |
458 | fsi = DEVPTS_SB(s); | ||
459 | opts = &fsi->mount_opts; | ||
460 | parse_mount_options(data, PARSE_REMOUNT, opts); | ||
461 | 396 | ||
462 | simple_set_mnt(mnt, s); | 397 | simple_set_mnt(mnt, s); |
398 | |||
399 | fsi = DEVPTS_SB(mnt->mnt_sb); | ||
400 | memcpy(&fsi->mount_opts, opts, sizeof(opts)); | ||
401 | |||
463 | return 0; | 402 | return 0; |
464 | } | 403 | } |
465 | 404 | ||
@@ -469,11 +408,11 @@ static int get_init_pts_sb(struct file_system_type *fs_type, int flags, | |||
469 | * kernel still allows multiple-instances. | 408 | * kernel still allows multiple-instances. |
470 | */ | 409 | */ |
471 | static int init_pts_mount(struct file_system_type *fs_type, int flags, | 410 | static int init_pts_mount(struct file_system_type *fs_type, int flags, |
472 | void *data, struct vfsmount *mnt) | 411 | void *data, struct pts_mount_opts *opts, struct vfsmount *mnt) |
473 | { | 412 | { |
474 | int err; | 413 | int err; |
475 | 414 | ||
476 | err = get_init_pts_sb(fs_type, flags, data, mnt); | 415 | err = get_init_pts_sb(fs_type, flags, data, opts, mnt); |
477 | if (err) | 416 | if (err) |
478 | return err; | 417 | return err; |
479 | 418 | ||
@@ -490,17 +429,22 @@ static int init_pts_mount(struct file_system_type *fs_type, int flags, | |||
490 | static int devpts_get_sb(struct file_system_type *fs_type, | 429 | static int devpts_get_sb(struct file_system_type *fs_type, |
491 | int flags, const char *dev_name, void *data, struct vfsmount *mnt) | 430 | int flags, const char *dev_name, void *data, struct vfsmount *mnt) |
492 | { | 431 | { |
493 | int new; | 432 | int error; |
494 | 433 | struct pts_mount_opts opts; | |
495 | new = is_new_instance_mount(data); | ||
496 | if (new < 0) | ||
497 | return new; | ||
498 | 434 | ||
499 | if (new) | 435 | memset(&opts, 0, sizeof(opts)); |
500 | return new_pts_mount(fs_type, flags, data, mnt); | 436 | if (data) { |
437 | error = parse_mount_options(data, PARSE_MOUNT, &opts); | ||
438 | if (error) | ||
439 | return error; | ||
440 | } | ||
501 | 441 | ||
502 | return init_pts_mount(fs_type, flags, data, mnt); | 442 | if (opts.newinstance) |
443 | return new_pts_mount(fs_type, flags, data, &opts, mnt); | ||
444 | else | ||
445 | return init_pts_mount(fs_type, flags, data, &opts, mnt); | ||
503 | } | 446 | } |
447 | |||
504 | #else | 448 | #else |
505 | /* | 449 | /* |
506 | * This supports only the legacy single-instance semantics (no | 450 | * This supports only the legacy single-instance semantics (no |