VYPR
High severityNVD Advisory· Published Feb 12, 2020· Updated Aug 4, 2024

CVE-2020-8945

CVE-2020-8945

Description

Use-after-free in the proglottis Go wrapper for GPGME library can cause a crash or code execution during GPG signature verification, notably during container image pulls.

AI Insight

LLM-synthesized narrative grounded in this CVE's description and references.

Use-after-free in the proglottis Go wrapper for GPGME library can cause a crash or code execution during GPG signature verification, notably during container image pulls.

CVE-2020-8945 is a use-after-free vulnerability in the proglottis Go wrapper for the GPGME library, affecting versions before 0.1.1 [1]. The root cause is that Go finalizers could deallocate GPGME objects while underlying C code still uses them, leading to memory corruption [2][4].

Exploitation occurs during GPG signature verification, particularly when container image pulls are performed by Docker or CRI-O. An attacker could provide a malicious container image with crafted GPG signatures to trigger the vulnerability [1].

Successful exploitation could lead to a crash or potential arbitrary code execution in the context of the process performing signature verification [3]. In container environments, this could compromise the integrity of image verification processes. Red Hat rated this vulnerability as Moderate severity for OpenShift Container Platform [3].

The flaw is fixed in proglottis/gpgme version 0.1.1 [4]. Red Hat released an advisory (RHSA-2020:0689) providing updated packages for OpenShift Container Platform 4.2.22 and related components like skopeo [3]. Users should upgrade to the patched version to mitigate the risk.

AI Insight generated on May 21, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
github.com/proglottis/gpgmeGo
< 0.1.10.1.1

Affected products

2

Patches

2
4c7a23f82ef0

Update to github.com/mtrmac/gpgme@v0.1.1

https://github.com/containers/imageMiloslav TrmačJan 18, 2020via ghsa
2 files changed · +6 1
  • go.mod+1 1 modified
    @@ -24,7 +24,7 @@ require (
     	github.com/konsorten/go-windows-terminal-sequences v1.0.2 // indirect
     	github.com/kr/pretty v0.1.0 // indirect
     	github.com/mattn/go-isatty v0.0.4 // indirect
    -	github.com/mtrmac/gpgme v0.0.0-20170102180018-b2432428689c
    +	github.com/mtrmac/gpgme v0.1.1
     	github.com/opencontainers/go-digest v1.0.0-rc1
     	github.com/opencontainers/image-spec v1.0.2-0.20190823105129-775207bd45b6
     	github.com/opencontainers/selinux v1.3.0
    
  • go.sum+5 0 modified
    @@ -115,6 +115,10 @@ github.com/mistifyio/go-zfs v2.1.1+incompatible h1:gAMO1HM9xBRONLHHYnu5iFsOJUiJd
     github.com/mistifyio/go-zfs v2.1.1+incompatible/go.mod h1:8AuVvqP/mXw1px98n46wfvcGfQ4ci2FwoAjKYxuo3Z4=
     github.com/mtrmac/gpgme v0.0.0-20170102180018-b2432428689c h1:xa+eQWKuJ9MbB9FBL/eoNvDFvveAkz2LQoz8PzX7Q/4=
     github.com/mtrmac/gpgme v0.0.0-20170102180018-b2432428689c/go.mod h1:GhAqVMEWnTcW2dxoD/SO3n2enrgWl3y6Dnx4m59GvcA=
    +github.com/mtrmac/gpgme v0.0.0-20200118211431-ce00817b8a3f h1:Td/Gr8BXYbQ0vXQUHhkleCzd7f+WTDQdVCmlqOUwMKo=
    +github.com/mtrmac/gpgme v0.0.0-20200118211431-ce00817b8a3f/go.mod h1:GYYHnGSuS7HK3zVS2n3y73y0okK/BeKzwnn5jgiVFNI=
    +github.com/mtrmac/gpgme v0.1.1 h1:a5ISnvahzTzBH0m/klhehN68N+9+/jLwhpPFtH3oPAQ=
    +github.com/mtrmac/gpgme v0.1.1/go.mod h1:GYYHnGSuS7HK3zVS2n3y73y0okK/BeKzwnn5jgiVFNI=
     github.com/opencontainers/go-digest v0.0.0-20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
     github.com/opencontainers/go-digest v1.0.0-rc1 h1:WzifXhOVOEOuFYOJAW6aQqW0TooG2iki3E3Ii+WN7gQ=
     github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
    @@ -220,6 +224,7 @@ golang.org/x/sys v0.0.0-20191127021746-63cb32ae39b2 h1:/J2nHFg1MTqaRLFO7M+J78ASN
     golang.org/x/sys v0.0.0-20191127021746-63cb32ae39b2/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
     golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
     golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
    +golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
     golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
     golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
     golang.org/x/tools v0.0.0-20180810170437-e96c4e24768d/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
    
92153bcb59bd

Merge pull request #23 from mtrmac/lifetimes

https://github.com/proglottis/gpgmeJames FargherJan 15, 2020via ghsa
2 files changed · +202 60
  • data.go+9 3 modified
    @@ -62,13 +62,13 @@ func gogpgme_seekfunc(handle unsafe.Pointer, offset C.gpgme_off_t, whence C.int)
     
     // The Data buffer used to communicate with GPGME
     type Data struct {
    -	dh  C.gpgme_data_t
    +	dh  C.gpgme_data_t // WARNING: Call runtime.KeepAlive(d) after ANY passing of d.dh to C
     	buf []byte
     	cbs C.struct_gpgme_data_cbs
     	r   io.Reader
     	w   io.Writer
     	s   io.Seeker
    -	cbc uintptr
    +	cbc uintptr // WARNING: Call runtime.KeepAlive(d) after ANY use of d.cbc in C (typically via d.dh)
     }
     
     func newData() *Data {
    @@ -154,12 +154,14 @@ func (d *Data) Close() error {
     		callbackDelete(d.cbc)
     	}
     	_, err := C.gpgme_data_release(d.dh)
    +	runtime.KeepAlive(d)
     	d.dh = nil
     	return err
     }
     
     func (d *Data) Write(p []byte) (int, error) {
     	n, err := C.gpgme_data_write(d.dh, unsafe.Pointer(&p[0]), C.size_t(len(p)))
    +	runtime.KeepAlive(d)
     	if err != nil {
     		return 0, err
     	}
    @@ -171,6 +173,7 @@ func (d *Data) Write(p []byte) (int, error) {
     
     func (d *Data) Read(p []byte) (int, error) {
     	n, err := C.gpgme_data_read(d.dh, unsafe.Pointer(&p[0]), C.size_t(len(p)))
    +	runtime.KeepAlive(d)
     	if err != nil {
     		return 0, err
     	}
    @@ -182,10 +185,13 @@ func (d *Data) Read(p []byte) (int, error) {
     
     func (d *Data) Seek(offset int64, whence int) (int64, error) {
     	n, err := C.gogpgme_data_seek(d.dh, C.gpgme_off_t(offset), C.int(whence))
    +	runtime.KeepAlive(d)
     	return int64(n), err
     }
     
     // Name returns the associated filename if any
     func (d *Data) Name() string {
    -	return C.GoString(C.gpgme_data_get_file_name(d.dh))
    +	res := C.GoString(C.gpgme_data_get_file_name(d.dh))
    +	runtime.KeepAlive(d)
    +	return res
     }
    
  • gpgme.go+193 57 modified
    @@ -164,39 +164,60 @@ func EngineCheckVersion(p Protocol) error {
     }
     
     type EngineInfo struct {
    -	info C.gpgme_engine_info_t
    +	next            *EngineInfo
    +	protocol        Protocol
    +	fileName        string
    +	homeDir         string
    +	version         string
    +	requiredVersion string
     }
     
    -func (e *EngineInfo) Next() *EngineInfo {
    -	if e.info.next == nil {
    -		return nil
    +func copyEngineInfo(info C.gpgme_engine_info_t) *EngineInfo {
    +	res := &EngineInfo{
    +		next:            nil,
    +		protocol:        Protocol(info.protocol),
    +		fileName:        C.GoString(info.file_name),
    +		homeDir:         C.GoString(info.home_dir),
    +		version:         C.GoString(info.version),
    +		requiredVersion: C.GoString(info.req_version),
     	}
    -	return &EngineInfo{info: e.info.next}
    +	if info.next != nil {
    +		res.next = copyEngineInfo(info.next)
    +	}
    +	return res
    +}
    +
    +func (e *EngineInfo) Next() *EngineInfo {
    +	return e.next
     }
     
     func (e *EngineInfo) Protocol() Protocol {
    -	return Protocol(e.info.protocol)
    +	return e.protocol
     }
     
     func (e *EngineInfo) FileName() string {
    -	return C.GoString(e.info.file_name)
    +	return e.fileName
     }
     
     func (e *EngineInfo) Version() string {
    -	return C.GoString(e.info.version)
    +	return e.version
     }
     
     func (e *EngineInfo) RequiredVersion() string {
    -	return C.GoString(e.info.req_version)
    +	return e.requiredVersion
     }
     
     func (e *EngineInfo) HomeDir() string {
    -	return C.GoString(e.info.home_dir)
    +	return e.homeDir
     }
     
     func GetEngineInfo() (*EngineInfo, error) {
    -	info := &EngineInfo{}
    -	return info, handleError(C.gpgme_get_engine_info(&info.info))
    +	var cInfo C.gpgme_engine_info_t
    +	err := handleError(C.gpgme_get_engine_info(&cInfo))
    +	if err != nil {
    +		return nil, err
    +	}
    +	return copyEngineInfo(cInfo), nil // It is up to the caller not to invalidate cInfo concurrently until this is done.
     }
     
     func SetEngineInfo(proto Protocol, fileName, homeDir string) error {
    @@ -257,9 +278,9 @@ type Context struct {
     	KeyError error
     
     	callback Callback
    -	cbc      uintptr
    +	cbc      uintptr // WARNING: Call runtime.KeepAlive(c) after ANY use of c.cbc in C (typically via c.ctx)
     
    -	ctx C.gpgme_ctx_t
    +	ctx C.gpgme_ctx_t // WARNING: Call runtime.KeepAlive(c) after ANY passing of c.ctx to C
     }
     
     func New() (*Context, error) {
    @@ -277,47 +298,66 @@ func (c *Context) Release() {
     		callbackDelete(c.cbc)
     	}
     	C.gpgme_release(c.ctx)
    +	runtime.KeepAlive(c)
     	c.ctx = nil
     }
     
     func (c *Context) SetArmor(yes bool) {
     	C.gpgme_set_armor(c.ctx, cbool(yes))
    +	runtime.KeepAlive(c)
     }
     
     func (c *Context) Armor() bool {
    -	return C.gpgme_get_armor(c.ctx) != 0
    +	res := C.gpgme_get_armor(c.ctx) != 0
    +	runtime.KeepAlive(c)
    +	return res
     }
     
     func (c *Context) SetTextMode(yes bool) {
     	C.gpgme_set_textmode(c.ctx, cbool(yes))
    +	runtime.KeepAlive(c)
     }
     
     func (c *Context) TextMode() bool {
    -	return C.gpgme_get_textmode(c.ctx) != 0
    +	res := C.gpgme_get_textmode(c.ctx) != 0
    +	runtime.KeepAlive(c)
    +	return res
     }
     
     func (c *Context) SetProtocol(p Protocol) error {
    -	return handleError(C.gpgme_set_protocol(c.ctx, C.gpgme_protocol_t(p)))
    +	err := handleError(C.gpgme_set_protocol(c.ctx, C.gpgme_protocol_t(p)))
    +	runtime.KeepAlive(c)
    +	return err
     }
     
     func (c *Context) Protocol() Protocol {
    -	return Protocol(C.gpgme_get_protocol(c.ctx))
    +	res := Protocol(C.gpgme_get_protocol(c.ctx))
    +	runtime.KeepAlive(c)
    +	return res
     }
     
     func (c *Context) SetKeyListMode(m KeyListMode) error {
    -	return handleError(C.gpgme_set_keylist_mode(c.ctx, C.gpgme_keylist_mode_t(m)))
    +	err := handleError(C.gpgme_set_keylist_mode(c.ctx, C.gpgme_keylist_mode_t(m)))
    +	runtime.KeepAlive(c)
    +	return err
     }
     
     func (c *Context) KeyListMode() KeyListMode {
    -	return KeyListMode(C.gpgme_get_keylist_mode(c.ctx))
    +	res := KeyListMode(C.gpgme_get_keylist_mode(c.ctx))
    +	runtime.KeepAlive(c)
    +	return res
     }
     
     func (c *Context) SetPinEntryMode(m PinEntryMode) error {
    -	return handleError(C.gpgme_set_pinentry_mode(c.ctx, C.gpgme_pinentry_mode_t(m)))
    +	err := handleError(C.gpgme_set_pinentry_mode(c.ctx, C.gpgme_pinentry_mode_t(m)))
    +	runtime.KeepAlive(c)
    +	return err
     }
     
     func (c *Context) PinEntryMode() PinEntryMode {
    -	return PinEntryMode(C.gpgme_get_pinentry_mode(c.ctx))
    +	res := PinEntryMode(C.gpgme_get_pinentry_mode(c.ctx))
    +	runtime.KeepAlive(c)
    +	return res
     }
     
     func (c *Context) SetCallback(callback Callback) error {
    @@ -334,11 +374,17 @@ func (c *Context) SetCallback(callback Callback) error {
     		c.cbc = 0
     		_, err = C.gogpgme_set_passphrase_cb(c.ctx, nil, 0)
     	}
    +	runtime.KeepAlive(c)
     	return err
     }
     
     func (c *Context) EngineInfo() *EngineInfo {
    -	return &EngineInfo{info: C.gpgme_ctx_get_engine_info(c.ctx)}
    +	cInfo := C.gpgme_ctx_get_engine_info(c.ctx)
    +	runtime.KeepAlive(c)
    +	// NOTE: c must be live as long as we are accessing cInfo.
    +	res := copyEngineInfo(cInfo)
    +	runtime.KeepAlive(c) // for accesses to cInfo
    +	return res
     }
     
     func (c *Context) SetEngineInfo(proto Protocol, fileName, homeDir string) error {
    @@ -351,19 +397,23 @@ func (c *Context) SetEngineInfo(proto Protocol, fileName, homeDir string) error
     		chome = C.CString(homeDir)
     		defer C.free(unsafe.Pointer(chome))
     	}
    -	return handleError(C.gpgme_ctx_set_engine_info(c.ctx, C.gpgme_protocol_t(proto), cfn, chome))
    +	err := handleError(C.gpgme_ctx_set_engine_info(c.ctx, C.gpgme_protocol_t(proto), cfn, chome))
    +	runtime.KeepAlive(c)
    +	return err
     }
     
     func (c *Context) KeyListStart(pattern string, secretOnly bool) error {
     	cpattern := C.CString(pattern)
     	defer C.free(unsafe.Pointer(cpattern))
    -	err := C.gpgme_op_keylist_start(c.ctx, cpattern, cbool(secretOnly))
    -	return handleError(err)
    +	err := handleError(C.gpgme_op_keylist_start(c.ctx, cpattern, cbool(secretOnly)))
    +	runtime.KeepAlive(c)
    +	return err
     }
     
     func (c *Context) KeyListNext() bool {
     	c.Key = newKey()
     	err := handleError(C.gpgme_op_keylist_next(c.ctx, &c.Key.k))
    +	runtime.KeepAlive(c) // implies runtime.KeepAlive(c.Key)
     	if err != nil {
     		if e, ok := err.(Error); ok && e.Code() == ErrorEOF {
     			c.KeyError = nil
    @@ -377,15 +427,21 @@ func (c *Context) KeyListNext() bool {
     }
     
     func (c *Context) KeyListEnd() error {
    -	return handleError(C.gpgme_op_keylist_end(c.ctx))
    +	err := handleError(C.gpgme_op_keylist_end(c.ctx))
    +	runtime.KeepAlive(c)
    +	return err
     }
     
     func (c *Context) GetKey(fingerprint string, secret bool) (*Key, error) {
     	key := newKey()
     	cfpr := C.CString(fingerprint)
     	defer C.free(unsafe.Pointer(cfpr))
     	err := handleError(C.gpgme_get_key(c.ctx, cfpr, &key.k, cbool(secret)))
    -	if e, ok := err.(Error); key.k == nil && ok && e.Code() == ErrorEOF {
    +	runtime.KeepAlive(c)
    +	runtime.KeepAlive(key)
    +	keyKIsNil := key.k == nil
    +	runtime.KeepAlive(key)
    +	if e, ok := err.(Error); keyKIsNil && ok && e.Code() == ErrorEOF {
     		return nil, fmt.Errorf("key %q not found", fingerprint)
     	}
     	if err != nil {
    @@ -395,11 +451,19 @@ func (c *Context) GetKey(fingerprint string, secret bool) (*Key, error) {
     }
     
     func (c *Context) Decrypt(ciphertext, plaintext *Data) error {
    -	return handleError(C.gpgme_op_decrypt(c.ctx, ciphertext.dh, plaintext.dh))
    +	err := handleError(C.gpgme_op_decrypt(c.ctx, ciphertext.dh, plaintext.dh))
    +	runtime.KeepAlive(c)
    +	runtime.KeepAlive(ciphertext)
    +	runtime.KeepAlive(plaintext)
    +	return err
     }
     
     func (c *Context) DecryptVerify(ciphertext, plaintext *Data) error {
    -	return handleError(C.gpgme_op_decrypt_verify(c.ctx, ciphertext.dh, plaintext.dh))
    +	err := handleError(C.gpgme_op_decrypt_verify(c.ctx, ciphertext.dh, plaintext.dh))
    +	runtime.KeepAlive(c)
    +	runtime.KeepAlive(ciphertext)
    +	runtime.KeepAlive(plaintext)
    +	return err
     }
     
     type Signature struct {
    @@ -426,10 +490,20 @@ func (c *Context) Verify(sig, signedText, plain *Data) (string, []Signature, err
     		plainPtr = plain.dh
     	}
     	err := handleError(C.gpgme_op_verify(c.ctx, sig.dh, signedTextPtr, plainPtr))
    +	runtime.KeepAlive(c)
    +	runtime.KeepAlive(sig)
    +	if signedText != nil {
    +		runtime.KeepAlive(signedText)
    +	}
    +	if plain != nil {
    +		runtime.KeepAlive(plain)
    +	}
     	if err != nil {
     		return "", nil, err
     	}
     	res := C.gpgme_op_verify_result(c.ctx)
    +	runtime.KeepAlive(c)
    +	// NOTE: c must be live as long as we are accessing res.
     	sigs := []Signature{}
     	for s := res.signatures; s != nil; s = s.next {
     		sig := Signature{
    @@ -449,7 +523,9 @@ func (c *Context) Verify(sig, signedText, plain *Data) (string, []Signature, err
     		}
     		sigs = append(sigs, sig)
     	}
    -	return C.GoString(res.file_name), sigs, nil
    +	fileName := C.GoString(res.file_name)
    +	runtime.KeepAlive(c) // for all accesses to res above
    +	return fileName, sigs, nil
     }
     
     func (c *Context) Encrypt(recipients []*Key, flags EncryptFlag, plaintext, ciphertext *Data) error {
    @@ -461,18 +537,31 @@ func (c *Context) Encrypt(recipients []*Key, flags EncryptFlag, plaintext, ciphe
     		*ptr = recipients[i].k
     	}
     	err := C.gpgme_op_encrypt(c.ctx, (*C.gpgme_key_t)(recp), C.gpgme_encrypt_flags_t(flags), plaintext.dh, ciphertext.dh)
    +	runtime.KeepAlive(c)
    +	runtime.KeepAlive(recipients)
    +	runtime.KeepAlive(plaintext)
    +	runtime.KeepAlive(ciphertext)
     	return handleError(err)
     }
     
     func (c *Context) Sign(signers []*Key, plain, sig *Data, mode SigMode) error {
     	C.gpgme_signers_clear(c.ctx)
    +	runtime.KeepAlive(c)
     	for _, k := range signers {
    -		if err := handleError(C.gpgme_signers_add(c.ctx, k.k)); err != nil {
    +		err := handleError(C.gpgme_signers_add(c.ctx, k.k))
    +		runtime.KeepAlive(c)
    +		runtime.KeepAlive(k)
    +		if err != nil {
     			C.gpgme_signers_clear(c.ctx)
    +			runtime.KeepAlive(c)
     			return err
     		}
     	}
    -	return handleError(C.gpgme_op_sign(c.ctx, plain.dh, sig.dh, C.gpgme_sig_mode_t(mode)))
    +	err := handleError(C.gpgme_op_sign(c.ctx, plain.dh, sig.dh, C.gpgme_sig_mode_t(mode)))
    +	runtime.KeepAlive(c)
    +	runtime.KeepAlive(plain)
    +	runtime.KeepAlive(sig)
    +	return err
     }
     
     type AssuanDataCallback func(data []byte) error
    @@ -501,6 +590,7 @@ func (c *Context) AssuanSend(
     		C.uintptr_t(statusPtr),
     		&operr,
     	)
    +	runtime.KeepAlive(c)
     
     	if handleError(operr) != nil {
     		return handleError(operr)
    @@ -553,7 +643,10 @@ const (
     func (c *Context) Export(pattern string, mode ExportModeFlags, data *Data) error {
     	pat := C.CString(pattern)
     	defer C.free(unsafe.Pointer(pat))
    -	return handleError(C.gpgme_op_export(c.ctx, pat, C.gpgme_export_mode_t(mode), data.dh))
    +	err := handleError(C.gpgme_op_export(c.ctx, pat, C.gpgme_export_mode_t(mode), data.dh))
    +	runtime.KeepAlive(c)
    +	runtime.KeepAlive(data)
    +	return err
     }
     
     // ImportStatusFlags describes the type of ImportStatus.Status. The C API in gpgme.h simply uses "unsigned".
    @@ -592,10 +685,14 @@ type ImportResult struct {
     
     func (c *Context) Import(keyData *Data) (*ImportResult, error) {
     	err := handleError(C.gpgme_op_import(c.ctx, keyData.dh))
    +	runtime.KeepAlive(c)
    +	runtime.KeepAlive(keyData)
     	if err != nil {
     		return nil, err
     	}
     	res := C.gpgme_op_import_result(c.ctx)
    +	runtime.KeepAlive(c)
    +	// NOTE: c must be live as long as we are accessing res.
     	imports := []ImportStatus{}
     	for s := res.imports; s != nil; s = s.next {
     		imports = append(imports, ImportStatus{
    @@ -604,7 +701,7 @@ func (c *Context) Import(keyData *Data) (*ImportResult, error) {
     			Status:      ImportStatusFlags(s.status),
     		})
     	}
    -	return &ImportResult{
    +	importResult := &ImportResult{
     		Considered:      int(res.considered),
     		NoUserID:        int(res.no_user_id),
     		Imported:        int(res.imported),
    @@ -619,11 +716,13 @@ func (c *Context) Import(keyData *Data) (*ImportResult, error) {
     		SecretUnchanged: int(res.secret_unchanged),
     		NotImported:     int(res.not_imported),
     		Imports:         imports,
    -	}, nil
    +	}
    +	runtime.KeepAlive(c) // for all accesses to res above
    +	return importResult, nil
     }
     
     type Key struct {
    -	k C.gpgme_key_t
    +	k C.gpgme_key_t // WARNING: Call Runtime.KeepAlive(k) after ANY passing of k.k to C
     }
     
     func newKey() *Key {
    @@ -634,85 +733,122 @@ func newKey() *Key {
     
     func (k *Key) Release() {
     	C.gpgme_key_release(k.k)
    +	runtime.KeepAlive(k)
     	k.k = nil
     }
     
     func (k *Key) Revoked() bool {
    -	return C.key_revoked(k.k) != 0
    +	res := C.key_revoked(k.k) != 0
    +	runtime.KeepAlive(k)
    +	return res
     }
     
     func (k *Key) Expired() bool {
    -	return C.key_expired(k.k) != 0
    +	res := C.key_expired(k.k) != 0
    +	runtime.KeepAlive(k)
    +	return res
     }
     
     func (k *Key) Disabled() bool {
    -	return C.key_disabled(k.k) != 0
    +	res := C.key_disabled(k.k) != 0
    +	runtime.KeepAlive(k)
    +	return res
     }
     
     func (k *Key) Invalid() bool {
    -	return C.key_invalid(k.k) != 0
    +	res := C.key_invalid(k.k) != 0
    +	runtime.KeepAlive(k)
    +	return res
     }
     
     func (k *Key) CanEncrypt() bool {
    -	return C.key_can_encrypt(k.k) != 0
    +	res := C.key_can_encrypt(k.k) != 0
    +	runtime.KeepAlive(k)
    +	return res
     }
     
     func (k *Key) CanSign() bool {
    -	return C.key_can_sign(k.k) != 0
    +	res := C.key_can_sign(k.k) != 0
    +	runtime.KeepAlive(k)
    +	return res
     }
     
     func (k *Key) CanCertify() bool {
    -	return C.key_can_certify(k.k) != 0
    +	res := C.key_can_certify(k.k) != 0
    +	runtime.KeepAlive(k)
    +	return res
     }
     
     func (k *Key) Secret() bool {
    -	return C.key_secret(k.k) != 0
    +	res := C.key_secret(k.k) != 0
    +	runtime.KeepAlive(k)
    +	return res
     }
     
     func (k *Key) CanAuthenticate() bool {
    -	return C.key_can_authenticate(k.k) != 0
    +	res := C.key_can_authenticate(k.k) != 0
    +	runtime.KeepAlive(k)
    +	return res
     }
     
     func (k *Key) IsQualified() bool {
    -	return C.key_is_qualified(k.k) != 0
    +	res := C.key_is_qualified(k.k) != 0
    +	runtime.KeepAlive(k)
    +	return res
     }
     
     func (k *Key) Protocol() Protocol {
    -	return Protocol(k.k.protocol)
    +	res := Protocol(k.k.protocol)
    +	runtime.KeepAlive(k)
    +	return res
     }
     
     func (k *Key) IssuerSerial() string {
    -	return C.GoString(k.k.issuer_serial)
    +	res := C.GoString(k.k.issuer_serial)
    +	runtime.KeepAlive(k)
    +	return res
     }
     
     func (k *Key) IssuerName() string {
    -	return C.GoString(k.k.issuer_name)
    +	res := C.GoString(k.k.issuer_name)
    +	runtime.KeepAlive(k)
    +	return res
     }
     
     func (k *Key) ChainID() string {
    -	return C.GoString(k.k.chain_id)
    +	res := C.GoString(k.k.chain_id)
    +	runtime.KeepAlive(k)
    +	return res
     }
     
     func (k *Key) OwnerTrust() Validity {
    -	return Validity(k.k.owner_trust)
    +	res := Validity(k.k.owner_trust)
    +	runtime.KeepAlive(k)
    +	return res
     }
     
     func (k *Key) SubKeys() *SubKey {
    -	if k.k.subkeys == nil {
    +	subKeys := k.k.subkeys
    +	runtime.KeepAlive(k)
    +	if subKeys == nil {
     		return nil
     	}
    -	return &SubKey{k: k.k.subkeys, parent: k}
    +	return &SubKey{k: subKeys, parent: k} // The parent: k reference ensures subKeys remains valid
     }
     
     func (k *Key) UserIDs() *UserID {
    -	if k.k.uids == nil {
    +	uids := k.k.uids
    +	runtime.KeepAlive(k)
    +	if uids == nil {
     		return nil
     	}
    -	return &UserID{u: k.k.uids, parent: k}
    +	return &UserID{u: uids, parent: k} // The parent: k reference ensures uids remains valid
     }
     
     func (k *Key) KeyListMode() KeyListMode {
    -	return KeyListMode(k.k.keylist_mode)
    +	res := KeyListMode(k.k.keylist_mode)
    +	runtime.KeepAlive(k)
    +	return res
     }
     
     type SubKey struct {
    

Vulnerability mechanics

Generated on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

19

News mentions

0

No linked articles in our index yet.