diff mbox

bfs: add sanity check at bfs_fill_super().

Message ID CAK+_RL=3k4LipYPixFf1HsTvHu-ebgZQy5oTJtDwh9NGjrSxig@mail.gmail.com (mailing list archive)
State New, archived
Headers show

Commit Message

Tigran Aivazian June 14, 2018, 4:15 p.m. UTC
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):


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/

Comments

Tigran Aivazian June 14, 2018, 7 p.m. UTC | #1
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.
Tetsuo Handa June 14, 2018, 10:18 p.m. UTC | #2
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...
Tigran Aivazian June 15, 2018, 10:45 a.m. UTC | #3
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
diff mbox

Patch

--- 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;
  }