Message ID | CAK+_RL=3k4LipYPixFf1HsTvHu-ebgZQy5oTJtDwh9NGjrSxig@mail.gmail.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
On 14 June 2018 at 17:15, Tigran Aivazian <aivazian.tigran@gmail.com> wrote: > On 14 June 2018 at 16:13, Tigran Aivazian <aivazian.tigran@gmail.com> wrote: >> On 14 June 2018 at 14:28, Tetsuo Handa >> <penguin-kernel@i-love.sakura.ne.jp> wrote: >>> What is possible largest value for imap_len ? >>> >>> info->si_lasti = (le32_to_cpu(bfs_sb->s_start) - BFS_BSIZE) / sizeof(struct bfs_inode) + BFS_ROOT_INO - 1; >>> imap_len = (info->si_lasti / 8) + 1; >>> info->si_imap = kzalloc(imap_len, GFP_KERNEL); >>> >>> Since sizeof(struct bfs_inode) is 64 and bfs_sb->s_start is unsigned 32bits integer >>> (where constraints is BFS_BSIZE <= bfs_sb->s_start <= bfs_sb->s_end), theoretically >>> it is possible to assign bfs_sb->s_start > 2GB (apart from whether such value makes >>> sense). Then, isn't it possible that imap_len > 4M and still hit KMALLOC_MAX_SIZE limit? >> >> You are correct, but the proper fix should be to restrict imap_len to >> whatever the maximum value allowed by BFS filesystem layout and reject >> anything beyond it. I will try to remember what it was from the notes >> I made when I wrote BFS back in 1999. Please wait (possibly a few >> days) and I will let you know what those values are. > > Actually, a more accurate sanity check for the value of s_start should > be (patch against 4.16.3): > > --- fs/bfs/inode.c.0 2018-06-14 16:50:52.136792126 +0100 > +++ fs/bfs/inode.c 2018-06-14 16:51:49.344792119 +0100 > @@ -350,7 +350,8 @@ > > s->s_magic = BFS_MAGIC; > > - if (le32_to_cpu(bfs_sb->s_start) > le32_to_cpu(bfs_sb->s_end)) { > + if (le32_to_cpu(bfs_sb->s_start) > le32_to_cpu(bfs_sb->s_end) || > + le32_to_cpu(bfs_sb->s_start) < sizeof(struct bfs_super_block) > + sizeof(struct bfs_dirent)) { > printf("Superblock is corrupted\n"); > goto out1; > } > > However, that doesn't address the issue of the _upper_ limit of > s_start, i.e. it can still get (on an invalid image pretending to be > BFS) arbitrarily large and cause the allocation to fail as you > described. I will dig a bit more (in my memories :) and try to come up > with the check which doesn't reject a valid BFS image and at the same > time restricts s_start (or imap_len which ultimately depends on it) > sufficiently to prevent wild kernel memory allocation requests. > > Btw, I included in the WikiPedia article "Boot File System" a > reference to the original "BFS kernel support" webpage from those > ancient days: http://ftp.linux.org.uk/pub/linux/iBCS/bfs/ Ah, it turned out easier than I thought! The maximum number of inodes of a BFS filesystem is 512, so an inode map cannot be longer than 65 bytes. Well, we can be generous and restrict imap_len to 128 and be done with it :) Namely, if the calculated imap_len turns out to be greater than 128, then something is definitely wrong and the filesystem image should be rejected as corrupted.
On 2018/06/15 4:00, Tigran Aivazian wrote: >> However, that doesn't address the issue of the _upper_ limit of >> s_start, i.e. it can still get (on an invalid image pretending to be >> BFS) arbitrarily large and cause the allocation to fail as you >> described. I will dig a bit more (in my memories :) and try to come up >> with the check which doesn't reject a valid BFS image and at the same >> time restricts s_start (or imap_len which ultimately depends on it) >> sufficiently to prevent wild kernel memory allocation requests. >> >> Btw, I included in the WikiPedia article "Boot File System" a >> reference to the original "BFS kernel support" webpage from those >> ancient days: http://ftp.linux.org.uk/pub/linux/iBCS/bfs/ > > Ah, it turned out easier than I thought! The maximum number of inodes > of a BFS filesystem is 512, so an inode map cannot be longer than 65 > bytes. Well, we can be generous and restrict imap_len to 128 and be > done with it :) > > Namely, if the calculated imap_len turns out to be greater than 128, > then something is definitely wrong and the filesystem image should be > rejected as corrupted. > So, the constraint is if (le32_to_cpu(bfs_sb->s_start) > le32_to_cpu(bfs_sb->s_end) || le32_to_cpu(bfs_sb->s_end) > What_is_the_number_here) you can write the fix yourself...
On 14 June 2018 at 23:18, Tetsuo Handa <penguin-kernel@i-love.sakura.ne.jp> wrote: > On 2018/06/15 4:00, Tigran Aivazian wrote: >> Ah, it turned out easier than I thought! The maximum number of inodes >> of a BFS filesystem is 512, so an inode map cannot be longer than 65 >> bytes. Well, we can be generous and restrict imap_len to 128 and be >> done with it :) >> >> Namely, if the calculated imap_len turns out to be greater than 128, >> then something is definitely wrong and the filesystem image should be >> rejected as corrupted. >> > So, the constraint is > > if (le32_to_cpu(bfs_sb->s_start) > le32_to_cpu(bfs_sb->s_end) || > le32_to_cpu(bfs_sb->s_end) > What_is_the_number_here) > > you can write the fix yourself... No, s_end has nothing to do with the number of inodes, it is to do with the actual data blocks. Yes, I am writing the fix myself and will test it under 4.17.1 to which I switched my Ubuntu desktop just now. Thanks, Tigran
--- fs/bfs/inode.c.0 2018-06-14 16:50:52.136792126 +0100 +++ fs/bfs/inode.c 2018-06-14 16:51:49.344792119 +0100 @@ -350,7 +350,8 @@ s->s_magic = BFS_MAGIC; - if (le32_to_cpu(bfs_sb->s_start) > le32_to_cpu(bfs_sb->s_end)) { + if (le32_to_cpu(bfs_sb->s_start) > le32_to_cpu(bfs_sb->s_end) || + le32_to_cpu(bfs_sb->s_start) < sizeof(struct bfs_super_block) + sizeof(struct bfs_dirent)) { printf("Superblock is corrupted\n"); goto out1; }