The match_int, match_hex and match_octal functions return 0 on non-numeric input (input error). But the user will legitimately want to set options to zero. This is indistinguishable from an error. So change these functions to return two values rather than one overloaded one. fs/adfs/super.c | 17 +++++++++++++---- fs/affs/super.c | 23 ++++++++++++++++------- fs/autofs/inode.c | 27 ++++++++++++++++++++------- fs/autofs4/inode.c | 26 +++++++++++++++++++------- fs/ext2/super.c | 9 +++++++-- fs/ext3/super.c | 19 ++++++++++++++----- fs/fat/inode.c | 40 ++++++++++++++-------------------------- fs/hfs/super.c | 21 ++++++++++++++++----- fs/hpfs/super.c | 13 ++++++++++--- fs/isofs/inode.c | 25 +++++++++++++++++++------ fs/proc/inode.c | 9 +++++++-- fs/udf/super.c | 45 ++++++++++++++++++++++++++++++++++----------- include/linux/parser.h | 6 +++--- lib/parser.c | 24 ++++++++++++++++++------ 14 files changed, 210 insertions(+), 94 deletions(-) diff -puN fs/adfs/super.c~filesystem-option-parsing-fixes fs/adfs/super.c --- 25/fs/adfs/super.c~filesystem-option-parsing-fixes 2003-09-27 19:38:46.000000000 -0700 +++ 25-akpm/fs/adfs/super.c 2003-09-27 19:38:46.000000000 -0700 @@ -148,6 +148,7 @@ static int parse_options(struct super_bl { char *p; struct adfs_sb_info *asb = ADFS_SB(sb); + int option; if (!options) return 0; @@ -161,16 +162,24 @@ static int parse_options(struct super_bl token = match_token(p, tokens, args); switch (token) { case Opt_uid: - asb->s_uid = match_int(args); + if (match_int(args, &option)) + return -EINVAL; + asb->s_uid = option; break; case Opt_gid: - asb->s_gid = match_int(args); + if (match_int(args, &option)) + return -EINVAL; + asb->s_gid = option; break; case Opt_ownmask: - asb->s_owner_mask = match_octal(args); + if (match_octal(args, &option)) + return -EINVAL; + asb->s_owner_mask = option; break; case Opt_othmask: - asb->s_other_mask = match_octal(args); + if (match_octal(args, &option)) + return -EINVAL; + asb->s_other_mask = option; break; default: printk("ADFS-fs: unrecognised mount option \"%s\" " diff -puN fs/affs/super.c~filesystem-option-parsing-fixes fs/affs/super.c --- 25/fs/affs/super.c~filesystem-option-parsing-fixes 2003-09-27 19:38:46.000000000 -0700 +++ 25-akpm/fs/affs/super.c 2003-09-27 19:38:46.000000000 -0700 @@ -189,14 +189,15 @@ parse_options(char *options, uid_t *uid, return 1; while ((p = strsep(&options, ",")) != NULL) { - int token, n; + int token, n, option; if (!*p) continue; token = match_token(p, tokens, args); switch (token) { case Opt_bs: - n = match_int(&args[0]); + if (match_int(&args[0], &n)) + return -EINVAL; if (n != 512 && n != 1024 && n != 2048 && n != 4096) { printk ("AFFS: Invalid blocksize (512, 1024, 2048, 4096 allowed)\n"); @@ -205,7 +206,9 @@ parse_options(char *options, uid_t *uid, *blocksize = n; break; case Opt_mode: - *mode = match_octal(&args[0]) & 0777; + if (match_octal(&args[0], &option)) + return 1; + *mode = option & 0777; *mount_opts |= SF_SETMODE; break; case Opt_mufs: @@ -225,17 +228,23 @@ parse_options(char *options, uid_t *uid, *mount_opts |= SF_IMMUTABLE; break; case Opt_reserved: - *reserved = match_int(&args[0]); + if (match_int(&args[0], reserved)) + return 1; break; case Opt_root: - *root = match_int(&args[0]); + if (match_int(&args[0], root)) + return 1; break; case Opt_setgid: - *gid = match_int(&args[0]); + if (match_int(&args[0], &option)) + return 1; + *gid = option; *mount_opts |= SF_SETGID; break; case Opt_setuid: - *uid = match_int(&args[0]); + if (match_int(&args[0], &option)) + return -EINVAL; + *uid = option; *mount_opts |= SF_SETUID; break; case Opt_verbose: diff -puN fs/autofs4/inode.c~filesystem-option-parsing-fixes fs/autofs4/inode.c --- 25/fs/autofs4/inode.c~filesystem-option-parsing-fixes 2003-09-27 19:38:46.000000000 -0700 +++ 25-akpm/fs/autofs4/inode.c 2003-09-27 19:38:46.000000000 -0700 @@ -112,7 +112,8 @@ static int parse_options(char *options, { char *p; substring_t args[MAX_OPT_ARGS]; - + int option; + *uid = tsk_uid(current); *gid = tsk_gid(current); *pgrp = process_group(current); @@ -133,22 +134,33 @@ static int parse_options(char *options, token = match_token(p, tokens, args); switch (token) { case Opt_fd: - *pipefd = match_int(args); + if (match_int(args, pipefd)) + return 1; break; case Opt_uid: - *uid = match_int(args); + if (match_int(args, &option)) + return 1; + *uid = option; break; case Opt_gid: - *gid = match_int(args); + if (match_int(args, &option)) + return 1; + *gid = option; break; case Opt_pgrp: - *pgrp = match_int(args); + if (match_int(args, &option)) + return 1; + *pgrp = option; break; case Opt_minproto: - *minproto = match_int(args); + if (match_int(args, &option)) + return 1; + *minproto = option; break; case Opt_maxproto: - *maxproto = match_int(args); + if (match_int(args, &option)) + return 1; + *maxproto = option; break; default: return 1; diff -puN fs/autofs/inode.c~filesystem-option-parsing-fixes fs/autofs/inode.c --- 25/fs/autofs/inode.c~filesystem-option-parsing-fixes 2003-09-27 19:38:46.000000000 -0700 +++ 25-akpm/fs/autofs/inode.c 2003-09-27 19:38:46.000000000 -0700 @@ -62,7 +62,8 @@ static int parse_options(char *options, { char *p; substring_t args[MAX_OPT_ARGS]; - + int option; + *uid = tsk_uid(current); *gid = tsk_gid(current); *pgrp = process_group(current); @@ -82,22 +83,34 @@ static int parse_options(char *options, token = match_token(p, autofs_tokens, args); switch (token) { case Opt_fd: - *pipefd = match_int(&args[0]); + if (match_int(&args[0], &option)) + return 1; + *pipefd = option; break; case Opt_uid: - *uid = match_int(&args[0]); + if (match_int(&args[0], &option)) + return 1; + *uid = option; break; case Opt_gid: - *gid = match_int(&args[0]); + if (match_int(&args[0], &option)) + return 1; + *gid = option; break; case Opt_pgrp: - *pgrp = match_int(&args[0]); + if (match_int(&args[0], &option)) + return 1; + *pgrp = option; break; case Opt_minproto: - *minproto = match_int(&args[0]); + if (match_int(&args[0], &option)) + return 1; + *minproto = option; break; case Opt_maxproto: - *maxproto = match_int(&args[0]); + if (match_int(&args[0], &option)) + return 1; + *maxproto = option; break; default: return 1; diff -puN fs/ext2/super.c~filesystem-option-parsing-fixes fs/ext2/super.c --- 25/fs/ext2/super.c~filesystem-option-parsing-fixes 2003-09-27 19:38:46.000000000 -0700 +++ 25-akpm/fs/ext2/super.c 2003-09-27 19:38:46.000000000 -0700 @@ -312,6 +312,7 @@ static int parse_options (char * options char * p; substring_t args[MAX_OPT_ARGS]; unsigned long kind = EXT2_MOUNT_ERRORS_CONT; + int option; if (!options) return 1; @@ -336,10 +337,14 @@ static int parse_options (char * options clear_opt (sbi->s_mount_opt, GRPID); break; case Opt_resuid: - sbi->s_resuid = match_int(&args[0]); + if (match_int(&args[0], &option)) + return 0; + sbi->s_resuid = option; break; case Opt_resgid: - sbi->s_resgid = match_int(&args[0]); + if (match_int(&args[0], &option)) + return 0; + sbi->s_resgid = option; break; case Opt_sb: /* handled by get_sb_block() instead of here */ diff -puN fs/ext3/super.c~filesystem-option-parsing-fixes fs/ext3/super.c --- 25/fs/ext3/super.c~filesystem-option-parsing-fixes 2003-09-27 19:38:46.000000000 -0700 +++ 25-akpm/fs/ext3/super.c 2003-09-27 19:38:46.000000000 -0700 @@ -602,6 +602,7 @@ static int parse_options (char * options char * p; substring_t args[MAX_OPT_ARGS]; int data_opt = 0; + int option; if (!options) return 1; @@ -626,10 +627,14 @@ static int parse_options (char * options clear_opt (sbi->s_mount_opt, GRPID); break; case Opt_resuid: - sbi->s_resuid = match_int(&args[0]); + if (match_int(&args[0], &option)) + return 0; + sbi->s_resuid = option; break; case Opt_resgid: - sbi->s_resgid = match_int(&args[0]); + if (match_int(&args[0], &option)) + return 0; + sbi->s_resgid = option; break; case Opt_sb: /* handled by get_sb_block() instead of here */ @@ -718,13 +723,17 @@ static int parse_options (char * options "journal on remount\n"); return 0; } - *inum = match_int(&args[0]); + if (match_int(&args[0], &option)) + return 0; + *inum = option; break; case Opt_noload: set_opt (sbi->s_mount_opt, NOLOAD); break; case Opt_commit: - sbi->s_commit_interval = HZ * match_int(&args[0]); + if (match_int(&args[0], &option)) + return 0; + sbi->s_commit_interval = HZ * option; break; case Opt_data_journal: data_opt = EXT3_MOUNT_JOURNAL_DATA; @@ -749,7 +758,7 @@ static int parse_options (char * options } break; case Opt_abort: - set_opt (sbi->s_mount_opt, ABORT); + set_opt(sbi->s_mount_opt, ABORT); break; case Opt_ignore: break; diff -puN fs/fat/inode.c~filesystem-option-parsing-fixes fs/fat/inode.c --- 25/fs/fat/inode.c~filesystem-option-parsing-fixes 2003-09-27 19:38:46.000000000 -0700 +++ 25-akpm/fs/fat/inode.c 2003-09-27 19:38:46.000000000 -0700 @@ -334,6 +334,7 @@ static int parse_options(char *options, { char *p; substring_t args[MAX_OPT_ARGS]; + int option; opts->isvfat = is_vfat; @@ -402,47 +403,34 @@ static int parse_options(char *options, opts->sys_immutable = 1; break; case Opt_uid: - { - int uid = match_int(&args[0]); - if (!uid) + if (match_int(&args[0], &option)) return 0; - opts->fs_uid = uid; + opts->fs_uid = option; break; - } case Opt_gid: - { - int gid = match_int(&args[0]); - if (!gid) + if (match_int(&args[0], &option)) return 0; - opts->fs_gid = gid; + opts->fs_gid = option; break; - } case Opt_umask: - { - int mask = match_octal(&args[0]); - if (!mask) + if (match_octal(&args[0], &option)) return 0; - opts->fs_fmask = opts->fs_dmask = mask; + opts->fs_fmask = opts->fs_dmask = option; break; - } case Opt_dmask: - { - int mask = match_octal(&args[0]); - if (!mask) + if (match_octal(&args[0], &option)) return 0; - opts->fs_dmask = mask; + opts->fs_dmask = option; break; - } case Opt_fmask: - { - int mask = match_octal(&args[0]); - if (!mask) + if (match_octal(&args[0], &option)) return 0; - opts->fs_fmask = mask; + opts->fs_fmask = option; break; - } case Opt_codepage: - opts->codepage = match_int(&args[0]); + if (match_int(&args[0], &option)) + return 0; + opts->codepage = option; printk("MSDOS FS: Using codepage %d\n", opts->codepage); break; diff -puN fs/hfs/super.c~filesystem-option-parsing-fixes fs/hfs/super.c --- 25/fs/hfs/super.c~filesystem-option-parsing-fixes 2003-09-27 19:38:46.000000000 -0700 +++ 25-akpm/fs/hfs/super.c 2003-09-27 19:38:46.000000000 -0700 @@ -277,6 +277,7 @@ static int parse_options(char *options, char *p; char names, fork; substring_t args[MAX_OPT_ARGS]; + int option; /* initialize the sb with defaults */ memset(hsb, 0, sizeof(*hsb)); @@ -308,19 +309,29 @@ static int parse_options(char *options, switch (token) { /* Numeric-valued options */ case Opt_version: - hsb->s_version = match_int(&args[0]); + if (match_int(&args[0], &option)) + return 0; + hsb->s_version = option; break; case Opt_uid: - hsb->s_uid = match_int(&args[0]); + if (match_int(&args[0], &option)) + return 0; + hsb->s_uid = option; break; case Opt_gid: - hsb->s_gid = match_int(&args[0]); + if (match_int(&args[0], &option)) + return 0; + hsb->s_gid = option; break; case Opt_umask: - hsb->s_umask = match_octal(&args[0]); + if (match_octal(&args[0], &option)) + return 0; + hsb->s_umask = option; break; case Opt_part: - *part = match_int(&args[0]); + if (match_int(&args[0], &option)) + return 0; + *part = option; break; /* String-valued options */ case Opt_type: diff -puN fs/hpfs/super.c~filesystem-option-parsing-fixes fs/hpfs/super.c --- 25/fs/hpfs/super.c~filesystem-option-parsing-fixes 2003-09-27 19:38:46.000000000 -0700 +++ 25-akpm/fs/hpfs/super.c 2003-09-27 19:38:46.000000000 -0700 @@ -265,6 +265,7 @@ int parse_opts(char *opts, uid_t *uid, g int *chkdsk, int *timeshift) { char *p; + int option; if (!opts) return 1; @@ -282,13 +283,19 @@ int parse_opts(char *opts, uid_t *uid, g case Opt_help: return 2; case Opt_uid: - *uid = match_int(args); + if (match_int(args, &option)) + return 0; + *uid = option; break; case Opt_gid: - *gid = match_int(args); + if (match_int(args, &option)) + return 0; + *gid = option; break; case Opt_umask: - *umask = match_octal(args); + if (match_octal(args, &option)) + return 0; + *umask = option; break; case Opt_case_lower: *lowercase = 1; diff -puN fs/isofs/inode.c~filesystem-option-parsing-fixes fs/isofs/inode.c --- 25/fs/isofs/inode.c~filesystem-option-parsing-fixes 2003-09-27 19:38:46.000000000 -0700 +++ 25-akpm/fs/isofs/inode.c 2003-09-27 19:38:46.000000000 -0700 @@ -374,6 +374,7 @@ static match_table_t tokens = { static int parse_options(char *options, struct iso9660_options * popt) { char *p; + int option; popt->map = 'n'; popt->rock = 'y'; @@ -436,13 +437,17 @@ static int parse_options(char *options, popt->map = 'n'; break; case Opt_session: - n = match_int(&args[0]); + if (match_int(&args[0], &option)) + return 0; + n = option; if (n > 99) return 0; popt->session = n + 1; break; case Opt_sb: - n = match_int(&args[0]); + if (match_int(&args[0], &option)) + return 0; + n = option; if (n > 660 * 512) return 0; popt->sbsector = n; @@ -456,16 +461,24 @@ static int parse_options(char *options, case Opt_ignore: break; case Opt_uid: - popt->uid = match_int(&args[0]); + if (match_int(&args[0], &option)) + return 0; + popt->uid = option; break; case Opt_gid: - popt->gid = match_int(&args[0]); + if (match_int(&args[0], &option)) + return 0; + popt->gid = option; break; case Opt_mode: - popt->mode = match_int(&args[0]); + if (match_int(&args[0], &option)) + return 0; + popt->mode = option; break; case Opt_block: - n = match_int(&args[0]); + if (match_int(&args[0], &option)) + return 0; + n = option; if (n != 512 && n != 1024 && n != 2048) return 0; popt->blocksize = n; diff -puN fs/proc/inode.c~filesystem-option-parsing-fixes fs/proc/inode.c --- 25/fs/proc/inode.c~filesystem-option-parsing-fixes 2003-09-27 19:38:46.000000000 -0700 +++ 25-akpm/fs/proc/inode.c 2003-09-27 19:38:46.000000000 -0700 @@ -149,6 +149,7 @@ static match_table_t tokens = { static int parse_options(char *options,uid_t *uid,gid_t *gid) { char *p; + int option; *uid = tsk_uid(current); *gid = tsk_gid(current); @@ -164,10 +165,14 @@ static int parse_options(char *options,u token = match_token(p, tokens, args); switch (token) { case Opt_uid: - *uid = match_int(args); + if (match_int(args, &option)) + return 0; + *uid = option; break; case Opt_gid: - *gid = match_int(args); + if (match_int(args, &option)) + return 0; + *gid = option; break; default: return 0; diff -puN fs/udf/super.c~filesystem-option-parsing-fixes fs/udf/super.c --- 25/fs/udf/super.c~filesystem-option-parsing-fixes 2003-09-27 19:38:46.000000000 -0700 +++ 25-akpm/fs/udf/super.c 2003-09-27 19:38:46.000000000 -0700 @@ -306,6 +306,7 @@ static int udf_parse_options(char *options, struct udf_options *uopt) { char *p; + int option; uopt->novrs = 0; uopt->blocksize = 2048; @@ -333,7 +334,9 @@ udf_parse_options(char *options, struct uopt->novrs = 1; break; case Opt_bs: - uopt->blocksize = match_int(&args[0]); + if (match_int(&args[0], &option)) + return 0; + uopt->blocksize = option; break; case Opt_unhide: uopt->flags |= (1 << UDF_FLAG_UNHIDE); @@ -354,37 +357,57 @@ udf_parse_options(char *options, struct uopt->flags &= ~(1 << UDF_FLAG_USE_SHORT_AD); break; case Opt_gid: - uopt->gid = match_int(args); + if (match_int(args, &option)) + return 0; + uopt->gid = option; break; case Opt_uid: - uopt->uid = match_int(args); + if (match_int(args, &option)) + return 0; + uopt->uid = option; break; case Opt_umask: - uopt->umask = match_octal(args); + if (match_octal(args, &option)) + return 0; + uopt->umask = option; break; case Opt_nostrict: uopt->flags &= ~(1 << UDF_FLAG_STRICT); break; case Opt_session: - uopt->session = match_int(args); + if (match_int(args, &option)) + return 0; + uopt->session = option; break; case Opt_lastblock: - uopt->lastblock = match_int(args); + if (match_int(args, &option)) + return 0; + uopt->lastblock = option; break; case Opt_anchor: - uopt->anchor = match_int(args); + if (match_int(args, &option)) + return 0; + uopt->anchor = option; break; case Opt_volume: - uopt->volume = match_int(args); + if (match_int(args, &option)) + return 0; + uopt->volume = option; break; case Opt_partition: - uopt->partition = match_int(args); + if (match_int(args, &option)) + return 0; + uopt->partition = option; break; case Opt_fileset: - uopt->fileset = match_int(args); + if (match_int(args, &option)) + return 0; + uopt->fileset = option; break; case Opt_rootdir: - uopt->rootdir = match_int(args); + if (match_int(args, &option)) + return 0; + uopt->rootdir = option; break; case Opt_utf8: uopt->flags |= (1 << UDF_FLAG_UTF8); diff -puN include/linux/parser.h~filesystem-option-parsing-fixes include/linux/parser.h --- 25/include/linux/parser.h~filesystem-option-parsing-fixes 2003-09-27 19:38:46.000000000 -0700 +++ 25-akpm/include/linux/parser.h 2003-09-27 19:38:46.000000000 -0700 @@ -14,8 +14,8 @@ typedef struct { int match_token(char *s, match_table_t table, substring_t args[]); -int match_int(substring_t *); -int match_octal(substring_t *); -int match_hex(substring_t *); +int match_int(substring_t *, int *result); +int match_octal(substring_t *, int *result); +int match_hex(substring_t *, int *result); void match_strcpy(char *, substring_t *); char *match_strdup(substring_t *); diff -puN lib/parser.c~filesystem-option-parsing-fixes lib/parser.c --- 25/lib/parser.c~filesystem-option-parsing-fixes 2003-09-27 19:38:46.000000000 -0700 +++ 25-akpm/lib/parser.c 2003-09-27 19:38:46.000000000 -0700 @@ -82,31 +82,43 @@ int match_token(char *s, match_table_t t return p->token; } -int match_int(substring_t *s) +int match_int(substring_t *s, int *result) { + char *endp; char buf[s->to - s->from + 1]; memcpy(buf, s->from, s->to - s->from); buf[s->to - s->from] = '\0'; - return simple_strtol(buf, NULL, 0); + *result = simple_strtol(buf, &endp, 0); + if (endp == buf) + return -EINVAL; + return 0; } -int match_octal(substring_t *s) +int match_octal(substring_t *s, int *result) { + char *endp; char buf[s->to - s->from + 1]; memcpy(buf, s->from, s->to - s->from); buf[s->to - s->from] = '\0'; - return simple_strtoul(buf, NULL, 8); + *result = simple_strtoul(buf, &endp, 8); + if (endp == buf) + return -EINVAL; + return 0; } -int match_hex(substring_t *s) +int match_hex(substring_t *s, int *result) { + char *endp; char buf[s->to - s->from + 1]; memcpy(buf, s->from, s->to - s->from); buf[s->to - s->from] = '\0'; - return simple_strtoul(buf, NULL, 16); + *result = simple_strtoul(buf, &endp, 16); + if (endp == buf) + return -EINVAL; + return 0; } void match_strcpy(char *to, substring_t *s) _