Repository: python-pillow/Pillow

Issue:
ValueError: buffer is not large enough
### What did you do?

I tried to open a bmp image and show it. 
### What did you expect to happen?

The image is opened and loaded normally.

### What actually happened?
ValueError: buffer is not large enough

```
Traceback (most recent call last):
  File "D:\Anaconda3\envs\paddle_env\lib\site-packages\IPython\core\interactiveshell.py", line 3444, in run_code
    exec(code_obj, self.user_global_ns, self.user_ns)
  File "<ipython-input-2-2a2b01505643>", line 1, in <module>
    runfile('E:/00IT/P/uniform/tests/test_image.py', wdir='E:/00IT/P/uniform/tests')
  File "D:\PyCharm\plugins\python\helpers\pydev\_pydev_bundle\pydev_umd.py", line 198, in runfile
    pydev_imports.execfile(filename, global_vars, local_vars)  # execute the script
  File "D:\PyCharm\plugins\python\helpers\pydev\_pydev_imps\_pydev_execfile.py", line 18, in execfile
    exec(compile(contents+"\n", file, 'exec'), glob, loc)
  File "E:/00IT/P/uniform/tests/test_image.py", line 13, in <module>
    img.putalpha(mask_image)
  File "D:\Anaconda3\envs\paddle_env\lib\site-packages\PIL\Image.py", line 1717, in putalpha
    alpha.load()
  File "D:\Anaconda3\envs\paddle_env\lib\site-packages\PIL\ImageFile.py", line 200, in load
    self.im = Image.core.map_buffer(
ValueError: buffer is not large enough
```
### What are your OS, Python and Pillow versions?

* OS: windows
* Python: 3.9.5
* Pillow: 8.10

<!--
Please include **code** that reproduces the issue and whenever possible, an **image** that demonstrates the issue. Please upload images to GitHub, not to third-party file hosting sites. If necessary, add the image to a zip or tar archive.

The best reproductions are self-contained scripts with minimal dependencies. If you are using a framework such as Plone, Django, or Buildout, try to replicate the issue just using Pillow.
-->

```python
from PIL import Image

path = "MX11.bmp"
image = Image.open(path)
image .show()
```
[MX11.zip](https://github.com/python-pillow/Pillow/files/9347642/MX11.zip)

### How to fix this?
I modified ImageFile.load method like this. Put ValueError in the Exception Tuple. It solved my problem. I wonder if there will be side effects.

```python
                try:
                    # use mmap, if possible
                    import mmap

                    with open(self.filename) as fp:
                        self.map = mmap.mmap(fp.fileno(), 0, access=mmap.ACCESS_READ)
                    self.im = Image.core.map_buffer(
                        self.map, self.size, decoder_name, offset, args
                    )
                    readonly = 1
                    # After trashing self.im,
                    # we might need to reload the palette data.
                    if self.palette:
                        self.palette.dirty = 1
                except (AttributeError, OSError, ImportError, ValueError):
                    self.map = None
```


Discussion:
On my macOS machine, the image won't open in Preview.

If I try and use ImageMagick to convert it to a PNG, I get the following.
```
$ convert MX11.bmp out.png
convert: length and filesize do not match `MX11.bmp' @ error/bmp.c/ReadBMPImage/854.
convert: insufficient image data in file `MX11.bmp' @ error/bmp.c/ReadBMPImage/1002.
convert: no images defined `out.png' @ error/convert.c/ConvertImageCommand/3229.
```

Is there any reason that you think the image isn't invalid? How was it created?
The image is a mask. it has only 1 channel. I can only view it in PyCharm, It can not be opened on my win10 machine too. And it was created by [pdfminer.image.ImageWriter](https://github.com/pdfminer/pdfminer.six/blob/master/pdfminer/image.py). But I don't know the details. Maybe I should give them this issue
You can choose to either try and convince us to be more lenient in reading your broken image, or to convince pdfminer to try and save a valid BMP file from your PDF.

I would think that getting pdfminer to save a valid BMP file would be more helpful to you if you are planning to do other things with the BMP file than just pass it to Pillow, but it's up to you.
In fact, I'm trying to convert PDF to Image in pure Python and Pillow. It's almost done.  If you want this new feature, you'd better be more lenient.  And I will get pdfminer to save a valid BMP file too.
If you'd like an immediate solution, I've found that the following code works.
```python
from PIL import Image
with open("MX11.bmp", "rb") as f:
    with Image.open(f) as im:
        im.show()
```

Resolving patch:
diff --git a/src/PIL/ImageFile.py b/src/PIL/ImageFile.py
--- a/src/PIL/ImageFile.py
+++ b/src/PIL/ImageFile.py
@@ -192,6 +192,9 @@ def load(self):
 
                     with open(self.filename) as fp:
                         self.map = mmap.mmap(fp.fileno(), 0, access=mmap.ACCESS_READ)
+                    if offset + self.size[1] * args[1] > self.map.size():
+                        # buffer is not large enough
+                        raise OSError
                     self.im = Image.core.map_buffer(
                         self.map, self.size, decoder_name, offset, args
                     )


Test patch:
diff --git a/Tests/images/mmap_error.bmp b/Tests/images/mmap_error.bmp
new file mode 100644
Binary files /dev/null and b/Tests/images/mmap_error.bmp differ
diff --git a/Tests/test_file_bmp.py b/Tests/test_file_bmp.py
--- a/Tests/test_file_bmp.py
+++ b/Tests/test_file_bmp.py
@@ -39,6 +39,13 @@ def test_invalid_file():
             BmpImagePlugin.BmpImageFile(fp)
 
 
+def test_fallback_if_mmap_errors():
+    # This image has been truncated,
+    # so that the buffer is not large enough when using mmap
+    with Image.open("Tests/images/mmap_error.bmp") as im:
+        assert_image_equal_tofile(im, "Tests/images/pal8_offset.bmp")
+
+
 def test_save_to_bytes():
     output = io.BytesIO()
     im = hopper()