core: Fix arg counting in enginge-gpg

* src/engine-gpg.c (build_argv): Properly check for all
arguments and allocate memory for them.

--
This fixes a potential buffer overflow which could be created
by using unusual and partially contradictory options.
Like offline and auto-key-locate together while
using ignore-mdc-error.
As the list of arguments should not be user controlled the
impact of this is very low.

To ensure that this does not happen in the future an
assert is also added with this patch.
This commit is contained in:
Andre Heinecke 2019-07-16 11:39:29 +02:00
parent 36428d8cf1
commit 6f4a886b30
No known key found for this signature in database
GPG Key ID: 2978E9D40CBABA5C

View File

@ -860,7 +860,7 @@ build_argv (engine_gpg_t gpg, const char *pgmname)
gpgme_error_t err; gpgme_error_t err;
struct arg_and_data_s *a; struct arg_and_data_s *a;
struct fd_data_map_s *fd_data_map; struct fd_data_map_s *fd_data_map;
size_t datac=0, argc=0; size_t datac=0, argc=0, allocated_argc=0;
char **argv; char **argv;
int need_special = 0; int need_special = 0;
int use_agent = 0; int use_agent = 0;
@ -908,18 +908,33 @@ build_argv (engine_gpg_t gpg, const char *pgmname)
/* fprintf (stderr, "build_argv: arg=`%s'\n", a->arg );*/ /* fprintf (stderr, "build_argv: arg=`%s'\n", a->arg );*/
} }
} }
if (need_special) if (need_special)
argc++; argc++;
if (use_agent) if (use_agent)
argc++; argc++;
if (*gpg->request_origin)
argc++;
if (gpg->auto_key_locate)
argc++;
if (gpg->trust_model)
argc++;
if (gpg->flags.no_symkey_cache)
argc++;
if (gpg->flags.ignore_mdc_error)
argc++;
if (gpg->flags.offline)
argc++;
if (gpg->pinentry_mode) if (gpg->pinentry_mode)
argc++; argc++;
if (!gpg->cmd.used) if (!gpg->cmd.used)
argc++; /* --batch */ argc++; /* --batch */
argc += 4; /* --no-sk-comments, --request-origin, --no-symkey-cache */
/* --disable-dirmngr */ argc++; /* --no-sk-comments */
argv = calloc (argc + 1, sizeof *argv); argv = calloc (argc + 1, sizeof *argv);
allocated_argc = argc;
if (!argv) if (!argv)
return gpg_error_from_syserror (); return gpg_error_from_syserror ();
fd_data_map = calloc (datac + 1, sizeof *fd_data_map); fd_data_map = calloc (datac + 1, sizeof *fd_data_map);
@ -964,6 +979,8 @@ build_argv (engine_gpg_t gpg, const char *pgmname)
} }
argc++; argc++;
} }
/* NOTE: If you add a new argument here. Ensure that
argc is counted up above to allocate enough memory. */
if (*gpg->request_origin) if (*gpg->request_origin)
{ {
@ -1191,6 +1208,11 @@ build_argv (engine_gpg_t gpg, const char *pgmname)
argc++; argc++;
} }
} }
/* Saveguard against adding a new argument without properly
counting up the argc used for allocation at the beginning
of this function. It would be better to use a dynamically
allocated array like ccparray in gnupg. */
assert (argc <= allocated_argc);
gpg->argv = argv; gpg->argv = argv;
gpg->fd_data_map = fd_data_map; gpg->fd_data_map = fd_data_map;