Compare commits

...

10 Commits

Author SHA1 Message Date
Werner Koch
7a0e7f93f7 Handle modern keyserver output which may emit the fingerprint.
* src/engine-gpg.c (read_colon_line): Split preprocessed lines.
(gpg_keylist_preprocess): Limit keyid field and print fingerprint.
2014-08-12 18:54:16 +02:00
Werner Koch
998e454a32 Release 1.4.4
* configure.ac: Change LT version to C22/A11/R1.
2014-07-30 11:36:03 +02:00
Werner Koch
1755f33a47 Fix possible realloc overflow for gpgsm and uiserver engines.
* src/engine-gpgsm.c (status_handler):
* src/engine-uiserver.c (status_handler):
--

After a realloc (realloc is also used for initial alloc) the allocated
size if the buffer is not correctly recorded.  Thus an overflow can be
introduced by receiving data with different line lengths in a specific
order.  This is not easy exploitable because libassuan constructs the
line.  However a crash has been reported and thus it might be possible
to constructs an exploit.

CVE-id: CVE-2014-3564
Reported-by: Tomáš Trnka

Resolved conflicts:
	NEWS - removed
2014-07-30 11:17:41 +02:00
Werner Koch
eee89ffd01 w32: Fix another memleak on error.
* src/w32-io.c (create_reader): free CTX.
--

Found by Hans-Christoph Steiner with cppcheck.
2014-07-30 11:13:22 +02:00
Werner Koch
27f052b9df w32: Fix memleak in an error code paths.
* src/w32-io.c (create_writer): Free CTX in cased of bad FD.
* src/w32-util.c (_gpgme_mkstemp): Free TMPNAME in case of a failed
mkstemp.
--

Found by Hans-Christoph Steiner with cppcheck.
2014-07-30 11:13:15 +02:00
Werner Koch
1e488d3fd8 Fix possible zombie processes.
* src/posix-io.c (_gpgme_io_waitpid): Protect waitpid agains EINTR.
(_gpgme_io_dup): Likewise.
(_gpgme_io_connect): Likewise.
--

GnuPG-bug-id: 1630
2014-07-30 11:13:08 +02:00
Werner Koch
a175922f8a Avoid pointer arithmetic on void pointer.
* src/gpgme.c (gpgme_io_writen): Use new var buffer.
--

Reported-by: Albert Chin
2014-07-30 11:12:18 +02:00
Werner Koch
97f9bec6d0 Change implementation return type to match the definition.
* src/gpgme.c (gpgme_get_sub_protocol): Change return type to
gpgme_protocol_t.
--

Yet another enum/int mismatch.

Reported-by: Albert Chin.
2014-07-30 11:12:17 +02:00
Werner Koch
206bfb5a79 Fix type inconsistency between gpgme.h and gpgme.c.
* src/gpgme.c (gpgme_set_pinentry_mode): Fix type of MODE.
--

GnuPG-bug-id: 1617
2014-07-30 11:11:55 +02:00
Werner Koch
3150aeba40 Fix possible segv in the gpgme_op_card_edit.
* src/edit.c (gpgme_op_edit_start, gpgme_op_card_edit_start): Do not
deref a NULL KEY in TRACE_BEG.
2014-07-30 11:10:56 +02:00
10 changed files with 97 additions and 26 deletions

19
NEWS
View File

@ -1,5 +1,20 @@
Noteworthy changes in version 1.4.3 (2013-08-12) Noteworthy changes in version 1.4.4 (2014-07-30) [C22/A11/R1]
------------------------------------------------ -------------------------------------------------------------
Backported from 1.5.1:
* Fixed possible overflow in gpgsm and uiserver engines.
[CVE-2014-3564]
* Fixed possibled segv in gpgme_op_card_edit.
* Fixed minor memleaks and possible zombie processes.
* Fixed prototype inconsistencies and void pointer arithmetic.
Noteworthy changes in version 1.4.3 (2013-08-12) [C22/A11/R0]
-------------------------------------------------------------
* The default engine names are now taken from the output of gpgconf. * The default engine names are now taken from the output of gpgconf.
If gpgconf is not found the use of gpg 1 is assumed. If gpgconf is not found the use of gpg 1 is assumed.

View File

@ -29,7 +29,7 @@ min_automake_version="1.11"
# for the LT versions. # for the LT versions.
m4_define(mym4_version_major, [1]) m4_define(mym4_version_major, [1])
m4_define(mym4_version_minor, [4]) m4_define(mym4_version_minor, [4])
m4_define(mym4_version_micro, [3]) m4_define(mym4_version_micro, [4])
# Below is m4 magic to extract and compute the revision number, the # Below is m4 magic to extract and compute the revision number, the
# decimalized short revision number, a beta version string, and a flag # decimalized short revision number, a beta version string, and a flag
@ -59,7 +59,7 @@ LIBGPGME_LT_CURRENT=22
# Subtract 2 from this value if you want to make the LFS transition an # Subtract 2 from this value if you want to make the LFS transition an
# ABI break. [Note to self: Remove this comment with the next regular break.] # ABI break. [Note to self: Remove this comment with the next regular break.]
LIBGPGME_LT_AGE=11 LIBGPGME_LT_AGE=11
LIBGPGME_LT_REVISION=0 LIBGPGME_LT_REVISION=1
# If the API is changed in an incompatible way: increment the next counter. # If the API is changed in an incompatible way: increment the next counter.
GPGME_CONFIG_API_VERSION=1 GPGME_CONFIG_API_VERSION=1

View File

@ -143,7 +143,7 @@ gpgme_op_edit_start (gpgme_ctx_t ctx, gpgme_key_t key,
TRACE_BEG5 (DEBUG_CTX, "gpgme_op_edit_start", ctx, TRACE_BEG5 (DEBUG_CTX, "gpgme_op_edit_start", ctx,
"key=%p (%s), fnc=%p fnc_value=%p, out=%p", key, "key=%p (%s), fnc=%p fnc_value=%p, out=%p", key,
(key->subkeys && key->subkeys->fpr) ? (key && key->subkeys && key->subkeys->fpr) ?
key->subkeys->fpr : "invalid", fnc, fnc_value, out); key->subkeys->fpr : "invalid", fnc, fnc_value, out);
if (!ctx) if (!ctx)
@ -164,7 +164,7 @@ gpgme_op_edit (gpgme_ctx_t ctx, gpgme_key_t key,
TRACE_BEG5 (DEBUG_CTX, "gpgme_op_edit", ctx, TRACE_BEG5 (DEBUG_CTX, "gpgme_op_edit", ctx,
"key=%p (%s), fnc=%p fnc_value=%p, out=%p", key, "key=%p (%s), fnc=%p fnc_value=%p, out=%p", key,
(key->subkeys && key->subkeys->fpr) ? (key && key->subkeys && key->subkeys->fpr) ?
key->subkeys->fpr : "invalid", fnc, fnc_value, out); key->subkeys->fpr : "invalid", fnc, fnc_value, out);
if (!ctx) if (!ctx)
@ -187,7 +187,7 @@ gpgme_op_card_edit_start (gpgme_ctx_t ctx, gpgme_key_t key,
TRACE_BEG5 (DEBUG_CTX, "gpgme_op_card_edit_start", ctx, TRACE_BEG5 (DEBUG_CTX, "gpgme_op_card_edit_start", ctx,
"key=%p (%s), fnc=%p fnc_value=%p, out=%p", key, "key=%p (%s), fnc=%p fnc_value=%p, out=%p", key,
(key->subkeys && key->subkeys->fpr) ? (key && key->subkeys && key->subkeys->fpr) ?
key->subkeys->fpr : "invalid", fnc, fnc_value, out); key->subkeys->fpr : "invalid", fnc, fnc_value, out);
if (!ctx) if (!ctx)
@ -208,7 +208,7 @@ gpgme_op_card_edit (gpgme_ctx_t ctx, gpgme_key_t key,
TRACE_BEG5 (DEBUG_CTX, "gpgme_op_card_edit", ctx, TRACE_BEG5 (DEBUG_CTX, "gpgme_op_card_edit", ctx,
"key=%p (%s), fnc=%p fnc_value=%p, out=%p", key, "key=%p (%s), fnc=%p fnc_value=%p, out=%p", key,
(key->subkeys && key->subkeys->fpr) ? (key && key->subkeys && key->subkeys->fpr) ?
key->subkeys->fpr : "invalid", fnc, fnc_value, out); key->subkeys->fpr : "invalid", fnc, fnc_value, out);
if (!ctx) if (!ctx)

View File

@ -896,6 +896,10 @@ build_argv (engine_gpg_t gpg)
close_notify_handler, close_notify_handler,
gpg)) gpg))
{ {
/* We leak fd_data_map and the fds. This is not easy
to avoid and given that we reach this here only
after a malloc failure for a small object, it is
probably better not to do anything. */
return gpg_error (GPG_ERR_GENERAL); return gpg_error (GPG_ERR_GENERAL);
} }
/* If the data_type is FD, we have to do a dup2 here. */ /* If the data_type is FD, we have to do a dup2 here. */
@ -1233,10 +1237,26 @@ read_colon_line (engine_gpg_t gpg)
} }
assert (gpg->colon.fnc); assert (gpg->colon.fnc);
gpg->colon.fnc (gpg->colon.fnc_value, line ? line : buffer);
if (line) if (line)
{
char *linep = line;
char *endp;
do
{
endp = strchr (linep, '\n');
if (endp)
*endp++ = 0;
gpg->colon.fnc (gpg->colon.fnc_value, linep);
linep = endp;
}
while (linep && *linep);
free (line); free (line);
} }
else
gpg->colon.fnc (gpg->colon.fnc_value, buffer);
}
/* To reuse the buffer for the next line we have to /* To reuse the buffer for the next line we have to
shift the remaining data to the buffer start and shift the remaining data to the buffer start and
@ -2055,6 +2075,7 @@ gpg_keylist_preprocess (char *line, char **r_line)
#define NR_FIELDS 16 #define NR_FIELDS 16
char *field[NR_FIELDS]; char *field[NR_FIELDS];
int fields = 0; int fields = 0;
size_t n;
*r_line = NULL; *r_line = NULL;
@ -2090,16 +2111,34 @@ gpg_keylist_preprocess (char *line, char **r_line)
pub:<keyid>:<algo>:<keylen>:<creationdate>:<expirationdate>:<flags> pub:<keyid>:<algo>:<keylen>:<creationdate>:<expirationdate>:<flags>
as defined in 5.2. Machine Readable Indexes of the OpenPGP as defined in 5.2. Machine Readable Indexes of the OpenPGP
HTTP Keyserver Protocol (draft). HTTP Keyserver Protocol (draft). Modern versions of the SKS
keyserver return the fingerprint instead of the keyid. We
detect this here and use the v4 fingerprint format to convert
it to a key id.
We want: We want:
pub:o<flags>:<keylen>:<algo>:<keyid>:<creatdate>:<expdate>:::::::: pub:o<flags>:<keylen>:<algo>:<keyid>:<creatdate>:<expdate>::::::::
*/ */
if (asprintf (r_line, "pub:o%s:%s:%s:%s:%s:%s::::::::", n = strlen (field[1]);
if (n > 16)
{
if (asprintf (r_line,
"pub:o%s:%s:%s:%s:%s:%s::::::::\n"
"fpr:::::::::%s:",
field[6], field[3], field[2], field[1] + n - 16,
field[4], field[5], field[1]) < 0)
return gpg_error_from_syserror ();
}
else
{
if (asprintf (r_line,
"pub:o%s:%s:%s:%s:%s:%s::::::::",
field[6], field[3], field[2], field[1], field[6], field[3], field[2], field[1],
field[4], field[5]) < 0) field[4], field[5]) < 0)
return gpg_error_from_syserror (); return gpg_error_from_syserror ();
}
return 0; return 0;
case RT_UID: case RT_UID:

View File

@ -837,7 +837,7 @@ status_handler (void *opaque, int fd)
else else
{ {
*aline = newline; *aline = newline;
gpgsm->colon.attic.linesize += linelen + 1; gpgsm->colon.attic.linesize = *alinelen + linelen + 1;
} }
} }
if (!err) if (!err)

View File

@ -698,7 +698,7 @@ status_handler (void *opaque, int fd)
else else
{ {
*aline = newline; *aline = newline;
uiserver->colon.attic.linesize += linelen + 1; uiserver->colon.attic.linesize = *alinelen + linelen + 1;
} }
} }
if (!err) if (!err)

View File

@ -357,7 +357,7 @@ gpgme_set_sub_protocol (gpgme_ctx_t ctx, gpgme_protocol_t protocol)
} }
gpgme_error_t gpgme_protocol_t
gpgme_get_sub_protocol (gpgme_ctx_t ctx) gpgme_get_sub_protocol (gpgme_ctx_t ctx)
{ {
TRACE2 (DEBUG_CTX, "gpgme_get_sub_protocol", ctx, TRACE2 (DEBUG_CTX, "gpgme_get_sub_protocol", ctx,
@ -514,7 +514,7 @@ gpgme_get_keylist_mode (gpgme_ctx_t ctx)
/* Set the pinentry mode for CTX to MODE. */ /* Set the pinentry mode for CTX to MODE. */
gpgme_error_t gpgme_error_t
gpgme_set_pinentry_mode (gpgme_ctx_t ctx, gpgme_keylist_mode_t mode) gpgme_set_pinentry_mode (gpgme_ctx_t ctx, gpgme_pinentry_mode_t mode)
{ {
TRACE1 (DEBUG_CTX, "gpgme_set_pinentry_mode", ctx, "pinentry_mode=%u", TRACE1 (DEBUG_CTX, "gpgme_set_pinentry_mode", ctx, "pinentry_mode=%u",
(unsigned int)mode); (unsigned int)mode);
@ -678,8 +678,9 @@ gpgme_io_write (int fd, const void *buffer, size_t count)
written or an error is return. Returns: 0 on success or -1 on written or an error is return. Returns: 0 on success or -1 on
error and the sets errno. */ error and the sets errno. */
int int
gpgme_io_writen (int fd, const void *buffer, size_t count) gpgme_io_writen (int fd, const void *buffer_arg, size_t count)
{ {
const char *buffer = buffer_arg;
int ret = 0; int ret = 0;
TRACE_BEG2 (DEBUG_GLOBAL, "gpgme_io_writen", fd, TRACE_BEG2 (DEBUG_GLOBAL, "gpgme_io_writen", fd,
"buffer=%p, count=%u", buffer, count); "buffer=%p, count=%u", buffer, count);

View File

@ -340,10 +340,15 @@ int
_gpgme_io_waitpid (int pid, int hang, int *r_status, int *r_signal) _gpgme_io_waitpid (int pid, int hang, int *r_status, int *r_signal)
{ {
int status; int status;
pid_t ret;
*r_status = 0; *r_status = 0;
*r_signal = 0; *r_signal = 0;
if (_gpgme_ath_waitpid (pid, &status, hang? 0 : WNOHANG) == pid) do
ret = _gpgme_ath_waitpid (pid, &status, hang? 0 : WNOHANG);
while (ret == (pid_t)(-1) && errno == EINTR);
if (ret == pid)
{ {
if (WIFSIGNALED (status)) if (WIFSIGNALED (status))
{ {
@ -714,7 +719,11 @@ _gpgme_io_sendmsg (int fd, const struct msghdr *msg, int flags)
int int
_gpgme_io_dup (int fd) _gpgme_io_dup (int fd)
{ {
int new_fd = dup (fd); int new_fd;
do
new_fd = dup (fd);
while (new_fd == -1 && errno == EINTR);
TRACE1 (DEBUG_SYSIO, "_gpgme_io_dup", fd, "new fd==%i", new_fd); TRACE1 (DEBUG_SYSIO, "_gpgme_io_dup", fd, "new fd==%i", new_fd);
@ -744,7 +753,9 @@ _gpgme_io_connect (int fd, struct sockaddr *addr, int addrlen)
TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_connect", fd, TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_connect", fd,
"addr=%p, addrlen=%i", addr, addrlen); "addr=%p, addrlen=%i", addr, addrlen);
do
res = ath_connect (fd, addr, addrlen); res = ath_connect (fd, addr, addrlen);
while (res == -1 && errno == EINTR);
return TRACE_SYSRES (res); return TRACE_SYSRES (res);
} }

View File

@ -425,6 +425,7 @@ create_reader (int fd)
if (fd < 0 || fd >= MAX_SLAFD || !fd_table[fd].used) if (fd < 0 || fd >= MAX_SLAFD || !fd_table[fd].used)
{ {
TRACE_SYSERR (EIO); TRACE_SYSERR (EIO);
free (ctx);
return NULL; return NULL;
} }
TRACE_LOG4 ("fd=%d -> handle=%p socket=%d dupfrom=%d", TRACE_LOG4 ("fd=%d -> handle=%p socket=%d dupfrom=%d",
@ -794,6 +795,7 @@ create_writer (int fd)
if (fd < 0 || fd >= MAX_SLAFD || !fd_table[fd].used) if (fd < 0 || fd >= MAX_SLAFD || !fd_table[fd].used)
{ {
TRACE_SYSERR (EIO); TRACE_SYSERR (EIO);
free (ctx);
return NULL; return NULL;
} }
TRACE_LOG4 ("fd=%d -> handle=%p socket=%d dupfrom=%d", TRACE_LOG4 ("fd=%d -> handle=%p socket=%d dupfrom=%d",

View File

@ -660,7 +660,10 @@ _gpgme_mkstemp (int *fd, char **name)
strcpy (stpcpy (tmpname, tmp), "\\gpgme-XXXXXX"); strcpy (stpcpy (tmpname, tmp), "\\gpgme-XXXXXX");
*fd = mkstemp (tmpname); *fd = mkstemp (tmpname);
if (fd < 0) if (fd < 0)
{
free (tmpname);
return -1; return -1;
}
*name = tmpname; *name = tmpname;
return 0; return 0;