Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 29 Apr 2013 17:29:48 +0000 (UTC)
From:      Konstantin Belousov <kib@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-8@freebsd.org
Subject:   svn commit: r250051 - stable/8/libexec/rtld-elf
Message-ID:  <201304291729.r3THTmgP005651@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: kib
Date: Mon Apr 29 17:29:48 2013
New Revision: 250051
URL: http://svnweb.freebsd.org/changeset/base/250051

Log:
  MFC r249525:
  Rewrite origin_subst_one() to get rid of the wrong limit on the length
  of the resulting string.

Modified:
  stable/8/libexec/rtld-elf/rtld.c
Directory Properties:
  stable/8/libexec/rtld-elf/   (props changed)

Modified: stable/8/libexec/rtld-elf/rtld.c
==============================================================================
--- stable/8/libexec/rtld-elf/rtld.c	Mon Apr 29 17:00:26 2013	(r250050)
+++ stable/8/libexec/rtld-elf/rtld.c	Mon Apr 29 17:29:48 2013	(r250051)
@@ -135,9 +135,8 @@ static void unlink_object(Obj_Entry *);
 static void unload_object(Obj_Entry *);
 static void unref_dag(Obj_Entry *);
 static void ref_dag(Obj_Entry *);
-static int origin_subst_one(char **, const char *, const char *,
-  const char *, char *);
-static char *origin_subst(const char *, const char *);
+static char *origin_subst_one(char *, const char *, const char *, bool);
+static char *origin_subst(char *, const char *);
 static int  rtld_verify_versions(const Objlist *);
 static int  rtld_verify_object_versions(Obj_Entry *);
 static void object_add_name(Obj_Entry *, const char *);
@@ -661,79 +660,80 @@ basename(const char *name)
 
 static struct utsname uts;
 
-static int
-origin_subst_one(char **res, const char *real, const char *kw, const char *subst,
-    char *may_free)
+static char *
+origin_subst_one(char *real, const char *kw, const char *subst,
+    bool may_free)
 {
-    const char *p, *p1;
-    char *res1;
-    int subst_len;
-    int kw_len;
-
-    res1 = *res = NULL;
-    p = real;
-    subst_len = kw_len = 0;
-    for (;;) {
-	 p1 = strstr(p, kw);
-	 if (p1 != NULL) {
-	     if (subst_len == 0) {
-		 subst_len = strlen(subst);
-		 kw_len = strlen(kw);
-	     }
-	     if (*res == NULL) {
-		 *res = xmalloc(PATH_MAX);
-		 res1 = *res;
-	     }
-	     if ((res1 - *res) + subst_len + (p1 - p) >= PATH_MAX) {
-		 _rtld_error("Substitution of %s in %s cannot be performed",
-		     kw, real);
-		 if (may_free != NULL)
-		     free(may_free);
-		 free(res);
-		 return (false);
-	     }
-	     memcpy(res1, p, p1 - p);
-	     res1 += p1 - p;
-	     memcpy(res1, subst, subst_len);
-	     res1 += subst_len;
-	     p = p1 + kw_len;
-	 } else {
-	    if (*res == NULL) {
-		if (may_free != NULL)
-		    *res = may_free;
-		else
-		    *res = xstrdup(real);
-		return (true);
-	    }
-	    *res1 = '\0';
-	    if (may_free != NULL)
-		free(may_free);
-	    if (strlcat(res1, p, PATH_MAX - (res1 - *res)) >= PATH_MAX) {
-		free(res);
-		return (false);
-	    }
-	    return (true);
-	 }
-    }
+	char *p, *p1, *res, *resp;
+	int subst_len, kw_len, subst_count, old_len, new_len;
+
+	kw_len = strlen(kw);
+
+	/*
+	 * First, count the number of the keyword occurences, to
+	 * preallocate the final string.
+	 */
+	for (p = real, subst_count = 0;; p = p1 + kw_len, subst_count++) {
+		p1 = strstr(p, kw);
+		if (p1 == NULL)
+			break;
+	}
+
+	/*
+	 * If the keyword is not found, just return.
+	 */
+	if (subst_count == 0)
+		return (may_free ? real : xstrdup(real));
+
+	/*
+	 * There is indeed something to substitute.  Calculate the
+	 * length of the resulting string, and allocate it.
+	 */
+	subst_len = strlen(subst);
+	old_len = strlen(real);
+	new_len = old_len + (subst_len - kw_len) * subst_count;
+	res = xmalloc(new_len + 1);
+
+	/*
+	 * Now, execute the substitution loop.
+	 */
+	for (p = real, resp = res;;) {
+		p1 = strstr(p, kw);
+		if (p1 != NULL) {
+			/* Copy the prefix before keyword. */
+			memcpy(resp, p, p1 - p);
+			resp += p1 - p;
+			/* Keyword replacement. */
+			memcpy(resp, subst, subst_len);
+			resp += subst_len;
+			p = p1 + kw_len;
+		} else
+			break;
+	}
+
+	/* Copy to the end of string and finish. */
+	strcat(resp, p);
+	if (may_free)
+		free(real);
+	return (res);
 }
 
 static char *
-origin_subst(const char *real, const char *origin_path)
+origin_subst(char *real, const char *origin_path)
 {
-    char *res1, *res2, *res3, *res4;
+	char *res1, *res2, *res3, *res4;
 
-    if (uts.sysname[0] == '\0') {
-	if (uname(&uts) != 0) {
-	    _rtld_error("utsname failed: %d", errno);
-	    return (NULL);
-	}
-    }
-    if (!origin_subst_one(&res1, real, "$ORIGIN", origin_path, NULL) ||
-	!origin_subst_one(&res2, res1, "$OSNAME", uts.sysname, res1) ||
-	!origin_subst_one(&res3, res2, "$OSREL", uts.release, res2) ||
-	!origin_subst_one(&res4, res3, "$PLATFORM", uts.machine, res3))
-	    return (NULL);
-    return (res4);
+	if (uts.sysname[0] == '\0') {
+		if (uname(&uts) != 0) {
+			_rtld_error("utsname failed: %d", errno);
+			return (NULL);
+		}
+	}
+	res1 = origin_subst_one(real, "$ORIGIN", origin_path, false);
+	res2 = origin_subst_one(res1, "$OSNAME", uts.sysname, true);
+	res3 = origin_subst_one(res2, "$OSREL", uts.release, true);
+	res4 = origin_subst_one(res3, "$PLATFORM", uts.machine, true);
+	return (res4);
 }
 
 static void
@@ -1144,10 +1144,12 @@ find_library(const char *xname, const Ob
 	      xname);
 	    return NULL;
 	}
-	if (refobj != NULL && refobj->z_origin)
-	    return origin_subst(xname, refobj->origin_path);
-	else
-	    return xstrdup(xname);
+	if (refobj != NULL && refobj->z_origin) {
+		return (origin_subst(__DECONST(char *, xname),
+		    refobj->origin_path));
+	} else {
+		return (xstrdup(xname));
+	}
     }
 
     if (libmap_disable || (refobj == NULL) ||



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201304291729.r3THTmgP005651>