summaryrefslogtreecommitdiff
path: root/dev-perl/SDL/files/SDL-2.548-uaf-surface.patch
blob: d64d27eab89be1061d9bc0fe0f90c01a87125495 (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
https://github.com/PerlGameDev/SDL/pull/306
https://github.com/PerlGameDev/SDL/issues/305
https://github.com/libsdl-org/sdl12-compat/issues/305

From e9b907c08d9fcce4fccb3084ff38e65cb5c6828b Mon Sep 17 00:00:00 2001
From: Simon McVittie <smcv@debian.org>
Date: Tue, 18 Jul 2023 18:00:12 +0100
Subject: [PATCH] Distinguish between owned and borrowed references to a
 SDL_Surface

In many SDL APIs that return a SDL_Surface *, the surface is considered
to be owned by the caller, and must be freed by the caller.

However, SDL_SetVideoMode and presumably SDL_GetVideoSurface return
a pointer to SDL's internal video surface, which will be freed by SDL
if necessary, and must not be freed by library users.
Incorrectly freeing this surface can lead to a use-after-free crash,
manifesting as a test failure in t/core_video.t.

See also https://github.com/libsdl-org/sdl12-compat/issues/305

Resolves: https://github.com/PerlGameDev/SDL/issues/305
Signed-off-by: Simon McVittie <smcv@debian.org>
---
 src/Core/Video.xs |  6 ++++--
 src/helper.h      |  7 ++++---
 typemap           | 23 +++++++++++++++++++++++
 3 files changed, 31 insertions(+), 5 deletions(-)

diff --git a/src/Core/Video.xs b/src/Core/Video.xs
index 8efa4b4a..e0d1a679 100644
--- a/src/Core/Video.xs
+++ b/src/Core/Video.xs
@@ -10,6 +10,8 @@
 
 #include <SDL.h>
 
+typedef SDL_Surface SDL_Surface_borrowed;
+
 void _uinta_free(Uint16* av, int len_from_av_len)
 {
 	if( av != NULL)
@@ -56,7 +58,7 @@ See: L<http:/*www.libsdl.org/cgi/docwiki.cgi/SDL_API#head-813f033ec44914f267f321
 
 =cut
 
-SDL_Surface *
+SDL_Surface_borrowed *
 video_get_video_surface()
 	PREINIT:
 		char* CLASS = "SDL::Surface";
@@ -125,7 +127,7 @@ video_video_mode_ok ( width, height, bpp, flags )
 		RETVAL
 
 
-SDL_Surface *
+SDL_Surface_borrowed *
 video_set_video_mode ( width, height, bpp, flags )
 	int width
 	int height
diff --git a/src/helper.h b/src/helper.h
index 1d2ee9a5..6b8e4ab5 100644
--- a/src/helper.h
+++ b/src/helper.h
@@ -58,12 +58,13 @@ void objDESTROY(SV *bag, void (* callback)(void *object))
         Uint32 *threadid = (Uint32*)(pointers[2]);
         
         if(PERL_GET_CONTEXT == pointers[1]
-        && *threadid == SDL_ThreadID())
+        && (threadid == NULL || *threadid == SDL_ThreadID()))
         {
             pointers[0] = NULL;
-            if(object)
+            if(object && threadid != NULL)
                 callback(object);
-            safefree(threadid);
+            if (threadid != NULL)
+                safefree(threadid);
             safefree(pointers);
         }
     }
diff --git a/typemap b/typemap
index c3ba997a..85a19265 100644
--- a/typemap
+++ b/typemap
@@ -34,6 +34,7 @@ SDL_UserEvent * 	O_OBJECT
 SDL_QuitEvent * 	O_OBJECT
 SDL_keysym *		O_OBJECT
 SDL_Surface *		O_OBJECT
+SDL_Surface_borrowed *	O_BORROWED
 SDL_SysWMmsg *		T_PTR
 SDL_CD *		O_OBJECT
 SDL_CDtrack *		O_OBJECT
@@ -122,6 +123,17 @@ O_OBJECT
         XSRETURN_UNDEF;
     }
 
+O_BORROWED
+    if ($var) {
+        void** pointers  = malloc(3 * sizeof(void*));
+        pointers[0]      = (void*)$var;
+        pointers[1]      = (void*)PERL_GET_CONTEXT;
+        pointers[2]      = NULL;
+        sv_setref_pv( $arg, CLASS, (void*)pointers );
+    } else {
+        XSRETURN_UNDEF;
+    }
+
 INPUT
 
 O_OBJECT_NPGC
@@ -136,3 +148,14 @@ O_OBJECT
     } else {
         XSRETURN_UNDEF;
     }
+
+O_BORROWED
+    /* Same as O_OBJECT */
+    if( sv_isobject($arg) && (SvTYPE(SvRV($arg)) == SVt_PVMG) ) {
+        void** pointers = (void**)INT2PTR(void *, SvIV((SV *)SvRV( $arg )));
+        $var = ($type)(pointers[0]);
+    } else if ($arg == 0) {
+        XSRETURN(0);
+    } else {
+        XSRETURN_UNDEF;
+    }