50
50
*/
51
51
52
52
/*
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.
56
55
*/
57
56
typedef struct OSSLDigest
58
57
{
59
58
const EVP_MD * algo ;
60
59
EVP_MD_CTX * ctx ;
61
60
62
61
ResourceOwner owner ;
63
- struct OSSLDigest * next ;
64
- struct OSSLDigest * prev ;
65
62
} OSSLDigest ;
66
63
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 ) ;
69
66
70
- static void
71
- free_openssl_digest (OSSLDigest * digest )
67
+ static const ResourceOwnerDesc ossldigest_resowner_desc =
72
68
{
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 );
81
86
}
82
87
83
- /*
84
- * Close any open OpenSSL handles on abort.
85
- */
86
88
static void
87
- digest_free_callback (ResourceReleasePhase phase ,
88
- bool isCommit ,
89
- bool isTopLevel ,
90
- void * arg )
89
+ free_openssl_digest (OSSLDigest * digest )
91
90
{
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 );
111
95
}
112
96
113
97
static unsigned
@@ -188,16 +172,12 @@ px_find_digest(const char *name, PX_MD **res)
188
172
OpenSSL_add_all_algorithms ();
189
173
}
190
174
191
- if (!digest_resowner_callback_registered )
192
- {
193
- RegisterResourceReleaseCallback (digest_free_callback , NULL );
194
- digest_resowner_callback_registered = true;
195
- }
196
-
197
175
md = EVP_get_digestbyname (name );
198
176
if (md == NULL )
199
177
return PXE_NO_HASH ;
200
178
179
+ ResourceOwnerEnlarge (CurrentResourceOwner );
180
+
201
181
/*
202
182
* Create an OSSLDigest object, an OpenSSL MD object, and a PX_MD object.
203
183
* 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)
221
201
digest -> algo = md ;
222
202
digest -> ctx = ctx ;
223
203
digest -> owner = CurrentResourceOwner ;
224
- digest -> next = open_digests ;
225
- digest -> prev = NULL ;
226
- open_digests = digest ;
204
+ ResourceOwnerRememberOSSLDigest (digest -> owner , digest );
227
205
228
206
/* The PX_MD object is allocated in the current memory context. */
229
207
h = palloc (sizeof (* h ));
@@ -239,6 +217,17 @@ px_find_digest(const char *name, PX_MD **res)
239
217
return 0 ;
240
218
}
241
219
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
+
242
231
/*
243
232
* Ciphers
244
233
*
@@ -266,9 +255,8 @@ struct ossl_cipher
266
255
* OSSLCipher contains the state for using a cipher. A separate OSSLCipher
267
256
* object is allocated in each px_find_cipher() call.
268
257
*
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.
272
260
*/
273
261
typedef struct OSSLCipher
274
262
{
@@ -281,54 +269,39 @@ typedef struct OSSLCipher
281
269
const struct ossl_cipher * ciph ;
282
270
283
271
ResourceOwner owner ;
284
- struct OSSLCipher * next ;
285
- struct OSSLCipher * prev ;
286
272
} OSSLCipher ;
287
273
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 ) ;
290
276
291
- static void
292
- free_openssl_cipher (OSSLCipher * od )
277
+ static const ResourceOwnerDesc osslcipher_resowner_desc =
293
278
{
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 );
302
296
}
303
297
304
- /*
305
- * Close any open OpenSSL cipher handles on abort.
306
- */
307
298
static void
308
- cipher_free_callback (ResourceReleasePhase phase ,
309
- bool isCommit ,
310
- bool isTopLevel ,
311
- void * arg )
299
+ free_openssl_cipher (OSSLCipher * od )
312
300
{
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 );
332
305
}
333
306
334
307
/* Common routines for all algorithms */
@@ -782,11 +755,7 @@ px_find_cipher(const char *name, PX_Cipher **res)
782
755
if (i -> name == NULL )
783
756
return PXE_NO_CIPHER ;
784
757
785
- if (!cipher_resowner_callback_registered )
786
- {
787
- RegisterResourceReleaseCallback (cipher_free_callback , NULL );
788
- cipher_resowner_callback_registered = true;
789
- }
758
+ ResourceOwnerEnlarge (CurrentResourceOwner );
790
759
791
760
/*
792
761
* 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)
806
775
807
776
od -> evp_ctx = ctx ;
808
777
od -> owner = CurrentResourceOwner ;
809
- od -> next = open_ciphers ;
810
- od -> prev = NULL ;
811
- open_ciphers = od ;
778
+ ResourceOwnerRememberOSSLCipher (od -> owner , od );
812
779
813
780
if (i -> ciph -> cipher_func )
814
781
od -> evp_ciph = i -> ciph -> cipher_func ();
@@ -827,3 +794,11 @@ px_find_cipher(const char *name, PX_Cipher **res)
827
794
* res = c ;
828
795
return 0 ;
829
796
}
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