summaryrefslogtreecommitdiffstats
path: root/meta-python/recipes-devtools/python/python3-pillow/CVE-2026-25990.patch
blob: e2c12b7b241ceab765e5cd4b3452e6590ee040a3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
From 829bd7b5c533e3a58d6f0a0ef4f001ea2605b784 Mon Sep 17 00:00:00 2001
From: Andrew Murray <3112309+radarhere@users.noreply.github.com>
Date: Wed, 11 Feb 2026 10:24:50 +1100
Subject: [PATCH] Fix OOB Write with invalid tile extents (#9427)

Co-authored-by: Eric Soroos <eric-github@soroos.net>

CVE: CVE-2026-25990
Upstream-Status: Backport [https://github.com/python-pillow/Pillow/commit/9000313cc5d4a31bdcdd6d7f0781101abab553aa]
Signed-off-by: Gyorgy Sarvari <skandigraun@gmail.com>
---
 Tests/images/psd-oob-write-x.psd | Bin 0 -> 1126 bytes
 Tests/images/psd-oob-write-y.psd | Bin 0 -> 1126 bytes
 Tests/images/psd-oob-write.psd   | Bin 0 -> 37212 bytes
 Tests/test_file_psd.py           |  17 +++++++++++++++++
 Tests/test_imagefile.py          |   7 +++++++
 src/decode.c                     |   3 ++-
 src/encode.c                     |   3 ++-
 7 files changed, 28 insertions(+), 2 deletions(-)
 create mode 100644 Tests/images/psd-oob-write-x.psd
 create mode 100644 Tests/images/psd-oob-write-y.psd
 create mode 100644 Tests/images/psd-oob-write.psd

diff --git a/Tests/images/psd-oob-write-x.psd b/Tests/images/psd-oob-write-x.psd
new file mode 100644
index 0000000000000000000000000000000000000000..86359f4cb7e826a69a8e69a4b85947498ec18923
GIT binary patch
literal 1126
zcma)5J!lkB5dL=WC-F>3z$=1SY;juU8Wp`VZp09|z;cO@XbSh|ZgXUJ@7TRX4pIuX
z0SkW`qZT&S+FIBOg5VE`wTL!~HWJqFz0GA0$%PEez3<J;H#cu)wx%1)P>@QFhrkNP
zAuvV#TGJPoazEr{TAAgkKpC9EmzOT6P~@#DuSJ<hm6j=CQFnxTwjbr^06*x3jRjp>
zUAwN0ePiq~9H(A1?WlXnFzSMFu>5&1Gvi%V<T^NJq;=A1Mm8UyF=Ec{hCSk&#20S$
zx&q%PF54TXL;Re0He`XsABEjY@ppk;iB&?B!<EK7-&Q8p+#zfYVS6L=8FQX76~_;l
zUtLYHBk-2Mz8AALDPjf_&EVQH&kFSv7O;pV7|>uLMjIY_sPYVGiO`^5AHhE<`36}Q
zS#8*4Tt){zOv#6s0b?jxZ==?^v(ltY=s@91lKeUijNJuxx0B@W<0RRA0^~jeuY!!<
z*#T<5Y2VIll}EtTZQ#Z0%x2vKUfuy_K6TB|l>Z~PO>MP+pU;5FHQ>ZspmZbc8-2o$
zryqb7_Nx8{c<>N7<1+X9h<A^Zu-~^sWA^&TIbWq-;U;II5Gs4$Lb}sM=`V`S4mzQq
zq_OJ*N=Y~EO*ibs9I}Y<;-F3647CKEJ-4w57a=DQb9#=9>9@HB$WwFjZhIlIc)`9T
z6kgJL@)8%N^RTLn0liQ+`%UH?s%V<N0_v=&k0$F$eOV>)+x7mhM3JvQ>aRNJ<v*Wo
Br)B^E

literal 0
HcmV?d00001

diff --git a/Tests/images/psd-oob-write-y.psd b/Tests/images/psd-oob-write-y.psd
new file mode 100644
index 0000000000000000000000000000000000000000..73498266a7d732ad70be649718229fa5f07997b7
GIT binary patch
literal 1126
zcma)5O=uHQ5dL=a(;8b^Foz-@_7FWa7ZuI1ZpBhbVM!~r+JpO(Y(sZ9VK++&coe)A
zJot05>cNX=y?XE}2!cN#o<;Pc=tau<y|;-Qq$v(e-uGtao6MV;t?9-p6r_^lA+Ul;
z2ux8w*YxF;+&6idRpxmrP==@Q<)sTM6nU%4Yf<J=rDaA~)IFh|?ML|qzz=$1V@cQ6
zH?C?EUl@A?N2%vcJL+CAjJjYPEWh5$%y?53xeksQYn^tQk<ABaj99R{VUPGa@wuH|
zSKzzEWqZqXh@TSAhb)lzy|7y;{wlC5u}X+?xYk(Y+see6JA$ndY;T1=W6m<B;`jmc
ztLrIt1im4#@5QW5ikQJvGq|$KvqC+AB`jkF1~gcR(T0Z}syqW)A~fjN$MBC!zCo5n
zRvR`M7tw(aQ}Q8Zz!*x_+o*Nsv@|JGI#BqOBtK396Ssl=-6Z+_FiG|w0lAOBiy-57
z_JG<?+IKTs<pD5r6L|JAvsrh5=eK~l4_z}f<^PCnQ(G<I`x9V#132~?C|yhYMxXHG
z@jGCRy{f+g?%fAYxy-#e=G~Jd{O#MJF@yeb&X=i|xXGC)gv#JsNO!s@{YA0aK_~Q+
zG<I`HDe0!Y?S`G0Ll!Y!9JJ}1qn4nv=Qg(CBIE>OPS24s{WiA%d1_AHZ7(DiFOZT@
z1~9EBFYiTZJFF^Wz(S#J_M6N(Qqe4Z1=LwlA5GSi`m##ox9j~=340;B^S{69u$O-T
DuU)5R

literal 0
HcmV?d00001

diff --git a/Tests/images/psd-oob-write.psd b/Tests/images/psd-oob-write.psd
new file mode 100644
index 0000000000000000000000000000000000000000..65a4472cf263a94277952c06903709afb0c8213f
GIT binary patch
literal 37212
zcmeI!I|{-;5CG8e2f;Js6jo_XXCVk)LDH$<2|S2L%6V+#=3`?OM1sW|nCvc@*<D_>
zMR_>JEc#fa;nZao?R<!Q8IecK-|IB4yX<SKuD|O3S4FwoU#_=vGZZ&X^GNwj%T3Bv
zzi(EzJ?WeF%<9jci0uU7lnIa>L4W`O0t5&U7$GptyKKZoln@|5fB*pk1ildPmiYor
z3jqQI2oNCfHv$oNL4W`O0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
t009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+0D&I~yZ}A8uQLDu

literal 0
HcmV?d00001

diff --git a/Tests/test_file_psd.py b/Tests/test_file_psd.py
index 38a88cd17..63db7b26a 100644
--- a/Tests/test_file_psd.py
+++ b/Tests/test_file_psd.py
@@ -184,3 +184,20 @@ def test_layer_crashes(test_file: str) -> None:
             assert isinstance(im, PsdImagePlugin.PsdImageFile)
             with pytest.raises(SyntaxError):
                 im.layers
+
+
+@pytest.mark.parametrize(
+    "test_file",
+    [
+        "Tests/images/psd-oob-write.psd",
+        "Tests/images/psd-oob-write-x.psd",
+        "Tests/images/psd-oob-write-y.psd",
+    ],
+)
+def test_bounds_crash(test_file: str) -> None:
+    with Image.open(test_file) as im:
+        assert isinstance(im, PsdImagePlugin.PsdImageFile)
+        im.seek(im.n_frames)
+
+        with pytest.raises(ValueError):
+            im.load()
diff --git a/Tests/test_imagefile.py b/Tests/test_imagefile.py
index 7dfb3abf9..2ef9fe2b9 100644
--- a/Tests/test_imagefile.py
+++ b/Tests/test_imagefile.py
@@ -169,6 +169,13 @@ class TestImageFile:
             with pytest.raises(ValueError, match="Tile offset cannot be negative"):
                 im.load()
 
+    @pytest.mark.parametrize("xy", ((-1, 0), (0, -1)))
+    def test_negative_tile_extents(self, xy: tuple[int, int]) -> None:
+        im = Image.new("1", (1, 1))
+        fp = BytesIO()
+        with pytest.raises(SystemError, match="tile cannot extend outside image"):
+            ImageFile._save(im, fp, [ImageFile._Tile("raw", xy + (1, 1), 0, "1")])
+
     def test_no_format(self) -> None:
         buf = BytesIO(b"\x00" * 255)
 
diff --git a/src/decode.c b/src/decode.c
index 051623ed4..7ec461c0e 100644
--- a/src/decode.c
+++ b/src/decode.c
@@ -186,7 +186,8 @@ _setimage(ImagingDecoderObject *decoder, PyObject *args) {
         state->ysize = y1 - y0;
     }
 
-    if (state->xsize <= 0 || state->xsize + state->xoff > (int)im->xsize ||
+    if (state->xoff < 0 || state->xsize <= 0 ||
+        state->xsize + state->xoff > (int)im->xsize || state->yoff < 0 ||
         state->ysize <= 0 || state->ysize + state->yoff > (int)im->ysize) {
         PyErr_SetString(PyExc_ValueError, "tile cannot extend outside image");
         return NULL;
diff --git a/src/encode.c b/src/encode.c
index b1d0181e0..117bf2164 100644
--- a/src/encode.c
+++ b/src/encode.c
@@ -254,7 +254,8 @@ _setimage(ImagingEncoderObject *encoder, PyObject *args) {
         state->ysize = y1 - y0;
     }
 
-    if (state->xsize <= 0 || state->xsize + state->xoff > im->xsize ||
+    if (state->xoff < 0 || state->xsize <= 0 ||
+        state->xsize + state->xoff > im->xsize || state->yoff < 0 ||
         state->ysize <= 0 || state->ysize + state->yoff > im->ysize) {
         PyErr_SetString(PyExc_SystemError, "tile cannot extend outside image");
         return NULL;