kern/vfs_mount.c vfs_donmount() checks of MFSNAMELEN
Kirk McKusick
mckusick at mckusick.com
Tue Sep 24 09:42:24 UTC 2013
> Date: Tue, 24 Sep 2013 10:48:45 +1000 (EST)
> From: Bruce Evans <brde at optusnet.com.au>
> To: sbruno at FreeBSD.org
> cc: Kirk McKusick <mckusick at mckusick.com>, freebsd-fs <freebsd-fs at FreeBSD.org>
> Subject: Re: kern/vfs_mount.c vfs_donmount() checks of MFSNAMELEN
>
> On Mon, 23 Sep 2013, Sean Bruno wrote:
>
>> On Mon, 2013-09-23 at 11:02 -0700, Kirk McKusick wrote:
>>>> So, I'm confused by this check:
>>>>
>>>> if (fstypelen >= MFSNAMELEN - 1 || fspathlen >= MNAMELEN -
>>> 1) {
>>>> error = ENAMETOOLONG;
>>>> goto bail;
>>>> }
>>>>
>>>> MFSNAMELEN is 16, why do we check against >= MFSNAMELEN - 1? Why
>>> dont
>>>> we check against (> MFSNAMELEN - 1) or (>= MFSNAMELEN)? Is a 14
>>>> character fstypelen with a "\0" at the end considered too long?
>>>>
>>>> Sean
>>>>
>>>> p.s. e.g. mount -t fuse.glusterfs ...
>>>
>>> I agree with you. It should either be (> MFSNAMELEN - 1) or (>=
>>> MFSNAMELEN).
>
> Apart from the existence of this check being a bug, it is still off by
> 1 for fstypename and off by 2 for fspathlen. It used to be off by 2
> for both.
>
> fstypelen and fsnamelen are not string lengths; they are array sizes
> where the array includes space for the terminating NUL (you can see
> this most easily a few lines earlier where it is checked that the byte
> at the end is NUL, where the end is determined by these variables).
> MFSNAMELEN and MNAMELEN are also not string lengths; they are also array
> sizes where the array includes space for the terminating NUL. Thus
> fstypelen == MFSNAMELEN and fspathlen == MNAMELEN are maximal non-lengths,
> not errors.
>
> "fuse.glusterfs" happens to have length 14 and size 15, so it is is maximal
> for the off-by-1 limit.
>
>> Not sure if we should adjust MNAMELEN or not too while we're at it, I
>> need to do a bit more of a code audit before thunking that one.
>
> The existence of the MNAMELEN check is a bug. It breaks mounting of file
> systems when fspathlen is too long to fit in the copy of the pathname
> that will be returned by statfs() if statfs() is ever called (except with
> the off-by-2 bug it breaks even for pathnames that fit). mount() worked
> correctly in old versions of FreeBSD -- pathnames were only limited by
> MAXPATHLEN, except where they are copied to struct statfs and possibly
> to superblocks (where the array reserved for the pathname is typically
> also too short, but not as short as MNAMELEN). Utilities using statfs()
> couldn't report correct pathnames for truncated ones, and the full
> pathname needed to be remembered somewhere if unmount() needs to be by
> pathname, but that is better than not allowing the mount at all.
>
> The MFSNAMELEN check doesn't break anything, but is just silly. fstype
> just points to a full copy of a mount arg and isn't copied to any array
> of limited length MFSNAMELEN. It is only used to look up the file
> system in vfs_byname() or vfs_byname_kld(). If the caller is silly
> enough to try to mount a file system whose name length (plus 1) exceeds
> MFSNAMELEN, then the lookup obviously fails since the name is longer
> than the name of any file system that can be supported. The relevant
> bounds check is in vfs_buildopts() where the arg is copied in.
>
> vfs_mount.c now has internal dependencies on the buggy up-front MNAMELEN
> limit, but these should be easy to fix by using the correct limit
> MAXPATHLEN everywhere except where the pathname is copied to the statfs
> struct. This copying used to be repeated in individual file systems,
> but is now centralized in vfs_mount_alloc(), and it still explicitly
> truncates although truncation is now always null due to the up-front
> check.
>
>> Propsed patch to set fstyplen check:
>> Index: sys/kern/vfs_mount.c
>> ===================================================================
>> --- sys/kern/vfs_mount.c (revision 255831)
>> +++ sys/kern/vfs_mount.c (working copy)
>> @@ -656,7 +656,7 @@
>> * variables will fit in our mp buffers, including the
>> * terminating NUL.
>> */
>> - if (fstypelen >= MFSNAMELEN - 1 || fspathlen >= MNAMELEN - 1) {
>> + if (fstypelen >= MFSNAMELEN || fspathlen >= MNAMELEN - 1) {
>> error = ENAMETOOLONG;
>> goto bail;
>> }
>
> The correct checks for implementing this bug are simpler and more natural:
>
> if (fstypelen > MFSNAMELEN || fspathlen > MNAMELEN) {
>
> These buggy checks are repeated at the start of vfs_domount(), except
> the checks there use strlen() and are naturally missing the off-by-[12]
> errors:
>
> if (strlen(fstype) >= MFSNAMELEN || strlen(fspath) >= MNAMELEN)
>
> Bruce
I agree with Bruce's arguments and his proposed solution. Notably the
change should be:
Index: sys/kern/vfs_mount.c
===================================================================
--- sys/kern/vfs_mount.c (revision 255831)
+++ sys/kern/vfs_mount.c (working copy)
@@ -656,7 +656,7 @@
* variables will fit in our mp buffers, including the
* terminating NUL.
*/
- if (fstypelen >= MFSNAMELEN - 1 || fspathlen >= MNAMELEN - 1) {
+ if (fstypelen > MFSNAMELEN || fspathlen > MNAMELEN) {
error = ENAMETOOLONG;
goto bail;
}
More information about the freebsd-fs
mailing list