Commit f60d16a8 authored by Jim Meyering's avatar Jim Meyering Committed by Josef Bacik

Btrfs: avoid buffer overrun in mount option handling

There is an off-by-one error: allocating room for a maximal result
string but without room for a trailing NUL.  That, can lead to
returning a transformed string that is not NUL-terminated, and
then to a caller reading beyond end of the malloc'd buffer.

Rewrite to s/kzalloc/kmalloc/, remove unwarranted use of strncpy
(the result is guaranteed to fit), remove dead strlen at end, and
change a few variable names and comments.
Reviewed-by: default avatarJosef Bacik <josef@redhat.com>
Signed-off-by: default avatarJim Meyering <meyering@redhat.com>
parent a27202fb
...@@ -923,63 +923,48 @@ static inline int is_subvolume_inode(struct inode *inode) ...@@ -923,63 +923,48 @@ static inline int is_subvolume_inode(struct inode *inode)
*/ */
static char *setup_root_args(char *args) static char *setup_root_args(char *args)
{ {
unsigned copied = 0; unsigned len = strlen(args) + 2 + 1;
unsigned len = strlen(args) + 2; char *src, *dst, *buf;
char *pos;
char *ret;
/* /*
* We need the same args as before, but minus * We need the same args as before, but with this substitution:
* s!subvol=[^,]+!subvolid=0!
* *
* subvol=a * Since the replacement string is up to 2 bytes longer than the
* * original, allocate strlen(args) + 2 + 1 bytes.
* and add
*
* subvolid=0
*
* which is a difference of 2 characters, so we allocate strlen(args) +
* 2 characters.
*/ */
ret = kzalloc(len * sizeof(char), GFP_NOFS);
if (!ret)
return NULL;
pos = strstr(args, "subvol=");
src = strstr(args, "subvol=");
/* This shouldn't happen, but just in case.. */ /* This shouldn't happen, but just in case.. */
if (!pos) { if (!src)
kfree(ret); return NULL;
buf = dst = kmalloc(len, GFP_NOFS);
if (!buf)
return NULL; return NULL;
}
/* /*
* The subvol=<> arg is not at the front of the string, copy everybody * If the subvol= arg is not at the start of the string,
* up to that into ret. * copy whatever precedes it into buf.
*/ */
if (pos != args) { if (src != args) {
*pos = '\0'; *src++ = '\0';
strcpy(ret, args); strcpy(buf, args);
copied += strlen(args); dst += strlen(args);
pos++;
} }
strncpy(ret + copied, "subvolid=0", len - copied); strcpy(dst, "subvolid=0");
dst += strlen("subvolid=0");
/* Length of subvolid=0 */
copied += 10;
/* /*
* If there is no , after the subvol= option then we know there's no * If there is a "," after the original subvol=... string,
* other options and we can just return. * copy that suffix into our buffer. Otherwise, we're done.
*/ */
pos = strchr(pos, ','); src = strchr(src, ',');
if (!pos) if (src)
return ret; strcpy(dst, src);
/* Copy the rest of the arguments into our buffer */ return buf;
strncpy(ret + copied, pos, len - copied);
copied += strlen(pos);
return ret;
} }
static struct dentry *mount_subvol(const char *subvol_name, int flags, static struct dentry *mount_subvol(const char *subvol_name, int flags,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment