Skip to content

Commit cd694f6

Browse files
committed
Change pgcrypto to use the new ResourceOwner mechanism.
This is a nice example of how extensions can now use ResourceOwners to track extension-specific resource kinds Reviewed-by: Peter Eisentraut, Andres Freund Discussion: https://www.postgresql.org/message-id/d746cead-a1ef-7efe-fb47-933311e876a3%40iki.fi
1 parent 954e435 commit cd694f6

File tree

1 file changed

+78
-103
lines changed

1 file changed

+78
-103
lines changed

contrib/pgcrypto/openssl.c

Lines changed: 78 additions & 103 deletions
Original file line numberDiff line numberDiff line change
@@ -50,64 +50,48 @@
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
*/
5756
typedef 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-
*/
8688
static 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

11397
static 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
*/
273261
typedef 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-
*/
307298
static 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

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy