diff options
author | Lee Schermerhorn <Lee.Schermerhorn@hp.com> | 2007-07-16 02:40:54 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-07-16 12:05:46 -0400 |
commit | b4c07bce796833401317519e44075889c5fd4d5f (patch) | |
tree | 569448b0cc6e0eb1516e38c98bc770ad73308880 | |
parent | e73a75fa7f062b52d015f1c961685dcaac57f710 (diff) |
hugetlbfs: handle empty options string
I was seeing a null pointer deref in fs/super.c:vfs_kern_mount().
Some file system get_sb() handler was returning NULL mnt_sb with
a non-negative return value. I also noticed a "hugetlbfs: Bad
mount option:" message in the log.
Turns out that hugetlbfs_parse_options() was not checking for an
empty option string after call to strsep(). On failure,
hugetlbfs_parse_options() returns 1. hugetlbfs_fill_super() just
passed this return code back up the call stack where
vfs_kern_mount() missed the error and proceeded with a NULL mnt_sb.
Apparently introduced by patch:
hugetlbfs-use-lib-parser-fix-docs.patch
The problem was exposed by this line in my fstab:
none /huge hugetlbfs defaults 0 0
It can also be demonstrated by invoking mount of hugetlbfs
directly with no options or a bogus option.
This patch:
1) adds the check for empty option to hugetlbfs_parse_options(),
2) enhances the error message to bracket any unrecognized
option with quotes ,
3) modifies hugetlbfs_parse_options() to return -EINVAL on any
unrecognized option,
4) adds a BUG_ON() to vfs_kern_mount() to catch any get_sb()
handler that returns a NULL mnt->mnt_sb with a return value
>= 0.
Signed-off-by: Lee Schermerhorn <lee.schermerhorn@hp.com>
Acked-by: Randy Dunlap <randy.dunlap@oracle.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r-- | fs/hugetlbfs/inode.c | 8 | ||||
-rw-r--r-- | fs/super.c | 1 |
2 files changed, 6 insertions, 3 deletions
diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c index 711b801fbcdf..d145cb79c30a 100644 --- a/fs/hugetlbfs/inode.c +++ b/fs/hugetlbfs/inode.c | |||
@@ -621,6 +621,8 @@ hugetlbfs_parse_options(char *options, struct hugetlbfs_config *pconfig) | |||
621 | 621 | ||
622 | while ((p = strsep(&options, ",")) != NULL) { | 622 | while ((p = strsep(&options, ",")) != NULL) { |
623 | int token; | 623 | int token; |
624 | if (!*p) | ||
625 | continue; | ||
624 | 626 | ||
625 | token = match_token(p, tokens, args); | 627 | token = match_token(p, tokens, args); |
626 | switch (token) { | 628 | switch (token) { |
@@ -665,8 +667,9 @@ hugetlbfs_parse_options(char *options, struct hugetlbfs_config *pconfig) | |||
665 | break; | 667 | break; |
666 | 668 | ||
667 | default: | 669 | default: |
668 | printk(KERN_ERR "hugetlbfs: Bad mount option: %s\n", p); | 670 | printk(KERN_ERR "hugetlbfs: Bad mount option: \"%s\"\n", |
669 | return 1; | 671 | p); |
672 | return -EINVAL; | ||
670 | break; | 673 | break; |
671 | } | 674 | } |
672 | } | 675 | } |
@@ -693,7 +696,6 @@ hugetlbfs_fill_super(struct super_block *sb, void *data, int silent) | |||
693 | config.gid = current->fsgid; | 696 | config.gid = current->fsgid; |
694 | config.mode = 0755; | 697 | config.mode = 0755; |
695 | ret = hugetlbfs_parse_options(data, &config); | 698 | ret = hugetlbfs_parse_options(data, &config); |
696 | |||
697 | if (ret) | 699 | if (ret) |
698 | return ret; | 700 | return ret; |
699 | 701 | ||
diff --git a/fs/super.c b/fs/super.c index 5260d620c555..fc8ebedc6bed 100644 --- a/fs/super.c +++ b/fs/super.c | |||
@@ -884,6 +884,7 @@ vfs_kern_mount(struct file_system_type *type, int flags, const char *name, void | |||
884 | error = type->get_sb(type, flags, name, data, mnt); | 884 | error = type->get_sb(type, flags, name, data, mnt); |
885 | if (error < 0) | 885 | if (error < 0) |
886 | goto out_free_secdata; | 886 | goto out_free_secdata; |
887 | BUG_ON(!mnt->mnt_sb); | ||
887 | 888 | ||
888 | error = security_sb_kern_mount(mnt->mnt_sb, secdata); | 889 | error = security_sb_kern_mount(mnt->mnt_sb, secdata); |
889 | if (error) | 890 | if (error) |