From 307872f71b357a3839fd037514a1c3dabfacc611 Mon Sep 17 00:00:00 2001
From: Panu Matilainen <pmatilai@redhat.com>
Date: Mon, 3 Feb 2020 14:54:16 +0200
Subject: [PATCH] Fix POPT_ARG_STRING memleaks in librpmbuild

popt always returned malloc'ed memory for POPT_ARG_STRING items, but
for whatever historical reason rpm systematically passed const char *
pointers as targets, making them look non-freeable. Besides changing
just the types and adding free()'s, const-correctness requires extra
tweaks as there's mixed use from string literals and poptGetArg() which
does return const pointers.
---
 build/parseDescription.c | 11 +++++++----
 build/parseFiles.c       |  5 +++--
 build/parsePolicies.c    |  5 +++--
 build/parsePrep.c        |  6 +++++-
 build/parseScript.c      | 11 +++++++----
 build/policies.c         |  8 ++++++--
 6 files changed, 31 insertions(+), 15 deletions(-)

diff --git a/build/parseDescription.c b/build/parseDescription.c
index c0737c0..72811f5 100644
--- a/build/parseDescription.c
+++ b/build/parseDescription.c
@@ -19,8 +19,8 @@ int parseDescription(rpmSpec spec)
     int rc, argc;
     int arg;
     const char **argv = NULL;
-    const char *name = NULL;
-    const char *lang = RPMBUILD_DEFAULT_LANG;
+    char *name = NULL;
+    char *lang = NULL;
     const char *descr = "";
     poptContext optCon = NULL;
     struct poptOption optionsTable[] = {
@@ -52,7 +52,7 @@ int parseDescription(rpmSpec spec)
 
     if (poptPeekArg(optCon)) {
 	if (name == NULL)
-	    name = poptGetArg(optCon);
+	    name = xstrdup(poptGetArg(optCon));
 	if (poptPeekArg(optCon)) {
 	    rpmlog(RPMLOG_ERR, _("line %d: Too many names: %s\n"),
 		     spec->lineNum,
@@ -75,12 +75,15 @@ int parseDescription(rpmSpec spec)
     }
 
     if (addLangTag(spec, pkg->header,
-		   RPMTAG_DESCRIPTION, descr, lang)) {
+		   RPMTAG_DESCRIPTION, descr,
+		   lang ? lang : RPMBUILD_DEFAULT_LANG)) {
 	nextPart = PART_ERROR;
     }
      
 exit:
     freeStringBuf(sb);
+    free(lang);
+    free(name);
     free(argv);
     poptFreeContext(optCon);
     return nextPart;
diff --git a/build/parseFiles.c b/build/parseFiles.c
index 69935d4..0dc1f17 100644
--- a/build/parseFiles.c
+++ b/build/parseFiles.c
@@ -17,7 +17,7 @@ int parseFiles(rpmSpec spec)
     int rc, argc;
     int arg;
     const char ** argv = NULL;
-    const char *name = NULL;
+    char *name = NULL;
     int flag = PART_SUBNAME;
     poptContext optCon = NULL;
     struct poptOption optionsTable[] = {
@@ -52,7 +52,7 @@ int parseFiles(rpmSpec spec)
 
     if (poptPeekArg(optCon)) {
 	if (name == NULL)
-	    name = poptGetArg(optCon);
+	    name = xstrdup(poptGetArg(optCon));
 	if (poptPeekArg(optCon)) {
 	    rpmlog(RPMLOG_ERR, _("line %d: Too many names: %s\n"),
 		     spec->lineNum,
@@ -89,6 +89,7 @@ int parseFiles(rpmSpec spec)
 exit:
     rpmPopMacro(NULL, "license");
     free(argv);
+    free(name);
     poptFreeContext(optCon);
 	
     return res;
diff --git a/build/parsePolicies.c b/build/parsePolicies.c
index 118b92c..64b95b1 100644
--- a/build/parsePolicies.c
+++ b/build/parsePolicies.c
@@ -19,7 +19,7 @@ int parsePolicies(rpmSpec spec)
     int rc, argc;
     int arg;
     const char **argv = NULL;
-    const char *name = NULL;
+    char *name = NULL;
     int flag = PART_SUBNAME;
     poptContext optCon = NULL;
 
@@ -50,7 +50,7 @@ int parsePolicies(rpmSpec spec)
 
     if (poptPeekArg(optCon)) {
 	if (name == NULL)
-	    name = poptGetArg(optCon);
+	    name = xstrdup(poptGetArg(optCon));
 	if (poptPeekArg(optCon)) {
 	    rpmlog(RPMLOG_ERR, _("line %d: Too many names: %s\n"),
 		   spec->lineNum, spec->line);
@@ -66,6 +66,7 @@ int parsePolicies(rpmSpec spec)
 
   exit:
     free(argv);
+    free(name);
     poptFreeContext(optCon);
 
     return res;
diff --git a/build/parsePrep.c b/build/parsePrep.c
index fe37575..cafb050 100644
--- a/build/parsePrep.c
+++ b/build/parsePrep.c
@@ -242,7 +242,7 @@ static int doSetupMacro(rpmSpec spec, const char *line)
     int leaveDirs = 0, skipDefaultAction = 0;
     int createDir = 0, quietly = 0;
     int buildInPlace = 0;
-    const char * dirName = NULL;
+    char * dirName = NULL;
     struct poptOption optionsTable[] = {
 	    { NULL, 'a', POPT_ARG_STRING, NULL, 'a',	NULL, NULL},
 	    { NULL, 'b', POPT_ARG_STRING, NULL, 'b',	NULL, NULL},
@@ -373,6 +373,7 @@ exit:
     freeStringBuf(before);
     freeStringBuf(after);
     poptFreeContext(optCon);
+    free(dirName);
     free(argv);
 
     return rc;
@@ -484,6 +485,9 @@ static rpmRC doPatchMacro(rpmSpec spec, const char *line)
 
 exit:
     argvFree(patchnums);
+    free(opt_b);
+    free(opt_d);
+    free(opt_o);
     free(argv);
     poptFreeContext(optCon);
     return rc;
diff --git a/build/parseScript.c b/build/parseScript.c
index bdf6ab3..e037bba 100644
--- a/build/parseScript.c
+++ b/build/parseScript.c
@@ -100,9 +100,9 @@ int parseScript(rpmSpec spec, int parsePart)
     int arg;
     const char **argv = NULL;
     poptContext optCon = NULL;
-    const char *name = NULL;
-    const char *prog = "/bin/sh";
-    const char *file = NULL;
+    char *name = NULL;
+    char *prog = xstrdup("/bin/sh");
+    char *file = NULL;
     int priority = 1000000;
     struct poptOption optionsTable[] = {
 	{ NULL, 'p', POPT_ARG_STRING, &prog, 'p',	NULL, NULL},
@@ -326,7 +326,7 @@ int parseScript(rpmSpec spec, int parsePart)
 
     if (poptPeekArg(optCon)) {
 	if (name == NULL)
-	    name = poptGetArg(optCon);
+	    name = xstrdup(poptGetArg(optCon));
 	if (poptPeekArg(optCon)) {
 	    rpmlog(RPMLOG_ERR, _("line %d: Too many names: %s\n"),
 		     spec->lineNum,
@@ -465,6 +465,9 @@ exit:
     free(reqargs);
     freeStringBuf(sb);
     free(progArgv);
+    free(prog);
+    free(name);
+    free(file);
     free(argv);
     poptFreeContext(optCon);
     
diff --git a/build/policies.c b/build/policies.c
index d3b1930..e92df19 100644
--- a/build/policies.c
+++ b/build/policies.c
@@ -276,16 +276,20 @@ static rpmRC processPolicies(rpmSpec spec, Package pkg, int test)
 	}
 
 	if (writeModuleToHeader(mod, pkg) != RPMRC_OK) {
-	    freeModule(mod);
 	    goto exit;
 	}
 
-	freeModule(mod);
+	mod = freeModule(mod);
+	name = _free(name);
+	types = _free(types);
     }
 
     rc = RPMRC_OK;
 
   exit:
+    freeModule(mod);
+    free(name);
+    free(types);
 
     return rc;
 }
-- 
2.27.0

