5050 */
5151
5252/*
53- * To make sure we don't leak OpenSSL handles on abort, we keep OSSLDigest
54- * objects in a linked list, allocated in TopMemoryContext. We use the
55- * ResourceOwner mechanism to free them on abort.
53+ * To make sure we don't leak OpenSSL handles, we use the ResourceOwner
54+ * mechanism to free them on abort.
5655 */
5756typedef struct OSSLDigest
5857{
5958 const EVP_MD * algo ;
6059 EVP_MD_CTX * ctx ;
6160
6261 ResourceOwner owner ;
63- struct OSSLDigest * next ;
64- struct OSSLDigest * prev ;
6562} OSSLDigest ;
6663
67- static OSSLDigest * open_digests = NULL ;
68- static bool digest_resowner_callback_registered = false ;
64+ /* ResourceOwner callbacks to hold OpenSSL digest handles */
65+ static void ResOwnerReleaseOSSLDigest ( Datum res ) ;
6966
70- static void
71- free_openssl_digest (OSSLDigest * digest )
67+ static const ResourceOwnerDesc ossldigest_resowner_desc =
7268{
73- EVP_MD_CTX_destroy (digest -> ctx );
74- if (digest -> prev )
75- digest -> prev -> next = digest -> next ;
76- else
77- open_digests = digest -> next ;
78- if (digest -> next )
79- digest -> next -> prev = digest -> prev ;
80- pfree (digest );
69+ .name = "pgcrypto OpenSSL digest handle" ,
70+ .release_phase = RESOURCE_RELEASE_BEFORE_LOCKS ,
71+ .release_priority = RELEASE_PRIO_FIRST ,
72+ .ReleaseResource = ResOwnerReleaseOSSLDigest ,
73+ .DebugPrint = NULL , /* default message is fine */
74+ };
75+
76+ /* Convenience wrappers over ResourceOwnerRemember/Forget */
77+ static inline void
78+ ResourceOwnerRememberOSSLDigest (ResourceOwner owner , OSSLDigest * digest )
79+ {
80+ ResourceOwnerRemember (owner , PointerGetDatum (digest ), & ossldigest_resowner_desc );
81+ }
82+ static inline void
83+ ResourceOwnerForgetOSSLDigest (ResourceOwner owner , OSSLDigest * digest )
84+ {
85+ ResourceOwnerForget (owner , PointerGetDatum (digest ), & ossldigest_resowner_desc );
8186}
8287
83- /*
84- * Close any open OpenSSL handles on abort.
85- */
8688static void
87- digest_free_callback (ResourceReleasePhase phase ,
88- bool isCommit ,
89- bool isTopLevel ,
90- void * arg )
89+ free_openssl_digest (OSSLDigest * digest )
9190{
92- OSSLDigest * curr ;
93- OSSLDigest * next ;
94-
95- if (phase != RESOURCE_RELEASE_AFTER_LOCKS )
96- return ;
97-
98- next = open_digests ;
99- while (next )
100- {
101- curr = next ;
102- next = curr -> next ;
103-
104- if (curr -> owner == CurrentResourceOwner )
105- {
106- if (isCommit )
107- elog (WARNING , "pgcrypto digest reference leak: digest %p still referenced" , curr );
108- free_openssl_digest (curr );
109- }
110- }
91+ EVP_MD_CTX_destroy (digest -> ctx );
92+ if (digest -> owner != NULL )
93+ ResourceOwnerForgetOSSLDigest (digest -> owner , digest );
94+ pfree (digest );
11195}
11296
11397static unsigned
@@ -188,16 +172,12 @@ px_find_digest(const char *name, PX_MD **res)
188172 OpenSSL_add_all_algorithms ();
189173 }
190174
191- if (!digest_resowner_callback_registered )
192- {
193- RegisterResourceReleaseCallback (digest_free_callback , NULL );
194- digest_resowner_callback_registered = true;
195- }
196-
197175 md = EVP_get_digestbyname (name );
198176 if (md == NULL )
199177 return PXE_NO_HASH ;
200178
179+ ResourceOwnerEnlarge (CurrentResourceOwner );
180+
201181 /*
202182 * Create an OSSLDigest object, an OpenSSL MD object, and a PX_MD object.
203183 * The order is crucial, to make sure we don't leak anything on
@@ -221,9 +201,7 @@ px_find_digest(const char *name, PX_MD **res)
221201 digest -> algo = md ;
222202 digest -> ctx = ctx ;
223203 digest -> owner = CurrentResourceOwner ;
224- digest -> next = open_digests ;
225- digest -> prev = NULL ;
226- open_digests = digest ;
204+ ResourceOwnerRememberOSSLDigest (digest -> owner , digest );
227205
228206 /* The PX_MD object is allocated in the current memory context. */
229207 h = palloc (sizeof (* h ));
@@ -239,6 +217,17 @@ px_find_digest(const char *name, PX_MD **res)
239217 return 0 ;
240218}
241219
220+ /* ResourceOwner callbacks for OSSLDigest */
221+
222+ static void
223+ ResOwnerReleaseOSSLDigest (Datum res )
224+ {
225+ OSSLDigest * digest = (OSSLDigest * ) DatumGetPointer (res );
226+
227+ digest -> owner = NULL ;
228+ free_openssl_digest (digest );
229+ }
230+
242231/*
243232 * Ciphers
244233 *
@@ -266,9 +255,8 @@ struct ossl_cipher
266255 * OSSLCipher contains the state for using a cipher. A separate OSSLCipher
267256 * object is allocated in each px_find_cipher() call.
268257 *
269- * To make sure we don't leak OpenSSL handles on abort, we keep OSSLCipher
270- * objects in a linked list, allocated in TopMemoryContext. We use the
271- * ResourceOwner mechanism to free them on abort.
258+ * To make sure we don't leak OpenSSL handles, we use the ResourceOwner
259+ * mechanism to free them on abort.
272260 */
273261typedef struct OSSLCipher
274262{
@@ -281,54 +269,39 @@ typedef struct OSSLCipher
281269 const struct ossl_cipher * ciph ;
282270
283271 ResourceOwner owner ;
284- struct OSSLCipher * next ;
285- struct OSSLCipher * prev ;
286272} OSSLCipher ;
287273
288- static OSSLCipher * open_ciphers = NULL ;
289- static bool cipher_resowner_callback_registered = false ;
274+ /* ResourceOwner callbacks to hold OpenSSL cipher state */
275+ static void ResOwnerReleaseOSSLCipher ( Datum res ) ;
290276
291- static void
292- free_openssl_cipher (OSSLCipher * od )
277+ static const ResourceOwnerDesc osslcipher_resowner_desc =
293278{
294- EVP_CIPHER_CTX_free (od -> evp_ctx );
295- if (od -> prev )
296- od -> prev -> next = od -> next ;
297- else
298- open_ciphers = od -> next ;
299- if (od -> next )
300- od -> next -> prev = od -> prev ;
301- pfree (od );
279+ .name = "pgcrypto OpenSSL cipher handle" ,
280+ .release_phase = RESOURCE_RELEASE_BEFORE_LOCKS ,
281+ .release_priority = RELEASE_PRIO_FIRST ,
282+ .ReleaseResource = ResOwnerReleaseOSSLCipher ,
283+ .DebugPrint = NULL , /* default message is fine */
284+ };
285+
286+ /* Convenience wrappers over ResourceOwnerRemember/Forget */
287+ static inline void
288+ ResourceOwnerRememberOSSLCipher (ResourceOwner owner , OSSLCipher * od )
289+ {
290+ ResourceOwnerRemember (owner , PointerGetDatum (od ), & osslcipher_resowner_desc );
291+ }
292+ static inline void
293+ ResourceOwnerForgetOSSLCipher (ResourceOwner owner , OSSLCipher * od )
294+ {
295+ ResourceOwnerForget (owner , PointerGetDatum (od ), & osslcipher_resowner_desc );
302296}
303297
304- /*
305- * Close any open OpenSSL cipher handles on abort.
306- */
307298static void
308- cipher_free_callback (ResourceReleasePhase phase ,
309- bool isCommit ,
310- bool isTopLevel ,
311- void * arg )
299+ free_openssl_cipher (OSSLCipher * od )
312300{
313- OSSLCipher * curr ;
314- OSSLCipher * next ;
315-
316- if (phase != RESOURCE_RELEASE_AFTER_LOCKS )
317- return ;
318-
319- next = open_ciphers ;
320- while (next )
321- {
322- curr = next ;
323- next = curr -> next ;
324-
325- if (curr -> owner == CurrentResourceOwner )
326- {
327- if (isCommit )
328- elog (WARNING , "pgcrypto cipher reference leak: cipher %p still referenced" , curr );
329- free_openssl_cipher (curr );
330- }
331- }
301+ EVP_CIPHER_CTX_free (od -> evp_ctx );
302+ if (od -> owner != NULL )
303+ ResourceOwnerForgetOSSLCipher (od -> owner , od );
304+ pfree (od );
332305}
333306
334307/* Common routines for all algorithms */
@@ -782,11 +755,7 @@ px_find_cipher(const char *name, PX_Cipher **res)
782755 if (i -> name == NULL )
783756 return PXE_NO_CIPHER ;
784757
785- if (!cipher_resowner_callback_registered )
786- {
787- RegisterResourceReleaseCallback (cipher_free_callback , NULL );
788- cipher_resowner_callback_registered = true;
789- }
758+ ResourceOwnerEnlarge (CurrentResourceOwner );
790759
791760 /*
792761 * Create an OSSLCipher object, an EVP_CIPHER_CTX object and a PX_Cipher.
@@ -806,9 +775,7 @@ px_find_cipher(const char *name, PX_Cipher **res)
806775
807776 od -> evp_ctx = ctx ;
808777 od -> owner = CurrentResourceOwner ;
809- od -> next = open_ciphers ;
810- od -> prev = NULL ;
811- open_ciphers = od ;
778+ ResourceOwnerRememberOSSLCipher (od -> owner , od );
812779
813780 if (i -> ciph -> cipher_func )
814781 od -> evp_ciph = i -> ciph -> cipher_func ();
@@ -827,3 +794,11 @@ px_find_cipher(const char *name, PX_Cipher **res)
827794 * res = c ;
828795 return 0 ;
829796}
797+
798+ /* ResourceOwner callbacks for OSSLCipher */
799+
800+ static void
801+ ResOwnerReleaseOSSLCipher (Datum res )
802+ {
803+ free_openssl_cipher ((OSSLCipher * ) DatumGetPointer (res ));
804+ }
0 commit comments