From nobody@FreeBSD.org  Thu Mar 20 05:09:58 2008
Return-Path: <nobody@FreeBSD.org>
Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34])
	by hub.freebsd.org (Postfix) with ESMTP id C7E0B106564A
	for <freebsd-gnats-submit@FreeBSD.org>; Thu, 20 Mar 2008 05:09:58 +0000 (UTC)
	(envelope-from nobody@FreeBSD.org)
Received: from www.freebsd.org (www.freebsd.org [IPv6:2001:4f8:fff6::21])
	by mx1.freebsd.org (Postfix) with ESMTP id AF48A8FC21
	for <freebsd-gnats-submit@FreeBSD.org>; Thu, 20 Mar 2008 05:09:58 +0000 (UTC)
	(envelope-from nobody@FreeBSD.org)
Received: from www.freebsd.org (localhost [127.0.0.1])
	by www.freebsd.org (8.14.2/8.14.2) with ESMTP id m2K59vlT036246
	for <freebsd-gnats-submit@FreeBSD.org>; Thu, 20 Mar 2008 05:09:57 GMT
	(envelope-from nobody@www.freebsd.org)
Received: (from nobody@localhost)
	by www.freebsd.org (8.14.2/8.14.1/Submit) id m2K59vIm036244;
	Thu, 20 Mar 2008 05:09:57 GMT
	(envelope-from nobody)
Message-Id: <200803200509.m2K59vIm036244@www.freebsd.org>
Date: Thu, 20 Mar 2008 05:09:57 GMT
From: Eric Schuele <e.schuele@computer.org>
To: freebsd-gnats-submit@FreeBSD.org
Subject: [PATCH] realpath(3) segmentation fault
X-Send-Pr-Version: www-3.1
X-GNATS-Notify:

>Number:         121897
>Category:       misc
>Synopsis:       [patch] realpath(3) segmentation fault
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    kib
>State:          closed
>Quarter:        
>Keywords:       
>Date-Required:  
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Thu Mar 20 05:10:01 UTC 2008
>Closed-Date:    Mon May 17 12:05:29 UTC 2010
>Last-Modified:  Mon May 17 12:05:29 UTC 2010
>Originator:     Eric Schuele
>Release:        FreeBSD 7.0-STABLE
>Organization:
>Environment:
FreeBSD fangorn.nxdomain.org 7.0-STABLE FreeBSD 7.0-STABLE #0: Wed Mar 12 12:50:03 CDT 2008     root@fangorn.nxdomain.org:/usr/obj/usr/src/sys/CUSTOM  i386
>Description:
The following code seems to behave a little better on linux than FreeBSD 7.0.

#include <stdio.h>
#include <stdlib.h>

main () 
{
  char buf[1024];
  char *s = realpath(NULL, buf);
}

On FreeBSD I get a segmentation fault, while linux gracefully sets errno
and goes on with its life.  Do note that changing the above NULL to
something a little more sane of course works.

The man page states:
"All but the last component of pathname must exist when realpath() is called."

So, on one hand maybe I was warned. Upon looking at the FreeBSD
implementation of realpath(3) its obvious that a null pointer is not
acceptable.

Now below is the first few lines of GNU libc's realpath implementation:

  if (name == NULL)
    {
      /* As per Single Unix Specification V2 we must return an error if
         either parameter is a null pointer.  We extend this to allow
         the RESOLVED parameter to be NULL in case the we are expected     	  to allocate the room for the return value.  */
      __set_errno (EINVAL);
      return NULL;
    }

  if (name[0] == '\0')
    {
      /* As per Single Unix Specification V2 we must return an error if
         the name argument points to an empty string.  */
      __set_errno (ENOENT);
      return NULL;
    }

Seems reasonable we should have a similar approach since SUS requests as
much.  I have attached a patch which fixes the issue.
>How-To-Repeat:
compile and run the following prog:

#include <stdio.h>
#include <stdlib.h>

main () 
{
  char buf[1024];
  char *s = realpath(NULL, buf);
}
>Fix:
See attached patch.

Patch attached with submission follows:

--- realpath.c.0	2008-03-19 23:50:39.000000000 -0500
+++ realpath.c	2008-03-19 23:50:57.000000000 -0500
@@ -59,6 +59,15 @@
 	int serrno, slen;
 	char left[PATH_MAX], next_token[PATH_MAX], symlink[PATH_MAX];
 
+        if (path == NULL) {
+		errno = EINVAL;
+		return (NULL);
+        }
+        if (path[0] == '\0') {
+		errno = ENOENT;
+		return (NULL);
+        }
+
 	serrno = errno;
 	symlinks = 0;
 	if (path[0] == '/') {


>Release-Note:
>Audit-Trail:

From: Eric Schuele <e.schuele@computer.org>
To: bug-followup@FreeBSD.org, e.schuele@computer.org
Cc:  
Subject: Re: bin/121897: [PATCH] realpath(3) segmentation fault
Date: Mon, 24 Mar 2008 23:14:26 -0500

 This is an OpenPGP/MIME signed message (RFC 2440 and 3156)
 --------------enig6C3177A74329CB3013986224
 Content-Type: text/plain; charset=ISO-8859-1
 Content-Transfer-Encoding: quoted-printable
 
 Somehow I managed to type in the wrong e-mail address when I submitted
 this bug.  I can be reached at:
 
   e.schuele@computer.org
 
 --=20
 Regards,
 Eric
 
 
 
 --------------enig6C3177A74329CB3013986224
 Content-Type: application/pgp-signature; name="signature.asc"
 Content-Description: OpenPGP digital signature
 Content-Disposition: attachment; filename="signature.asc"
 
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v2.0.8 (FreeBSD)
 
 iEYEARECAAYFAkfofCIACgkQngSDRM3IXUoCewCgv8omvhK+0yW972sk3Soj8u0K
 J00AoPRDeSoRzTyktDFNZ79Vvi4lHaKg
 =qiih
 -----END PGP SIGNATURE-----
 
 --------------enig6C3177A74329CB3013986224--

From: dfilter@FreeBSD.ORG (dfilter service)
To: bug-followup@FreeBSD.org
Cc:  
Subject: Re: kern/121897: commit references a PR
Date: Tue, 20 Apr 2010 10:16:58 +0000 (UTC)

 Author: kib
 Date: Tue Apr 20 10:16:44 2010
 New Revision: 206893
 URL: http://svn.freebsd.org/changeset/base/206893
 
 Log:
   Slightly modernize realpath(3).
   
   SUSv4 requires that implementation returns EINVAL if supplied path is NULL,
   and ENOENT if path is empty string [1].
   Bring prototype in conformance with SUSv4, adding restrict keywords.
   Allow the resolved path buffer pointer be NULL, in which case realpath(3)
   allocates storage with malloc().
   
   PR:	kern/121897 [1]
   MFC after:	2 weeks
 
 Modified:
   head/include/stdlib.h
   head/lib/libc/stdlib/realpath.3
   head/lib/libc/stdlib/realpath.c
 
 Modified: head/include/stdlib.h
 ==============================================================================
 --- head/include/stdlib.h	Tue Apr 20 08:51:21 2010	(r206892)
 +++ head/include/stdlib.h	Tue Apr 20 10:16:44 2010	(r206893)
 @@ -201,7 +201,7 @@ int	 posix_openpt(int);
  char	*ptsname(int);
  int	 putenv(char *);
  long	 random(void);
 -char	*realpath(const char *, char resolved_path[]);
 +char	*realpath(const char * __restrict, char * __restrict);
  unsigned short
  	*seed48(unsigned short[3]);
  #ifndef _SETKEY_DECLARED
 
 Modified: head/lib/libc/stdlib/realpath.3
 ==============================================================================
 --- head/lib/libc/stdlib/realpath.3	Tue Apr 20 08:51:21 2010	(r206892)
 +++ head/lib/libc/stdlib/realpath.3	Tue Apr 20 10:16:44 2010	(r206893)
 @@ -31,7 +31,7 @@
  .\"     @(#)realpath.3	8.2 (Berkeley) 2/16/94
  .\" $FreeBSD$
  .\"
 -.Dd February 16, 1994
 +.Dd April 19, 2010
  .Dt REALPATH 3
  .Os
  .Sh NAME
 @@ -43,7 +43,7 @@
  .In sys/param.h
  .In stdlib.h
  .Ft "char *"
 -.Fn realpath "const char *pathname" "char resolved_path[PATH_MAX]"
 +.Fn realpath "const char *pathname" "char *resolved_path"
  .Sh DESCRIPTION
  The
  .Fn realpath
 @@ -64,7 +64,8 @@ argument
  .Em must
  refer to a buffer capable of storing at least
  .Dv PATH_MAX
 -characters.
 +characters, or be
 +.Dv NULL .
  .Pp
  The
  .Fn realpath
 @@ -82,6 +83,13 @@ The
  function returns
  .Fa resolved_path
  on success.
 +If the function was supplied
 +.Dv NULL
 +as
 +.Fa resolved_path ,
 +and operation did not cause errors, the returned value is
 +a null-terminated string in a buffer allocated by a call to
 +.Fn malloc 3 .
  If an error occurs,
  .Fn realpath
  returns
 @@ -89,6 +97,11 @@ returns
  and
  .Fa resolved_path
  contains the pathname which caused the problem.
 +If
 +.Fa resolved_path
 +was
 +.Dv NULL ,
 +then information of the failed pathname component is lost.
  .Sh ERRORS
  The function
  .Fn realpath
 
 Modified: head/lib/libc/stdlib/realpath.c
 ==============================================================================
 --- head/lib/libc/stdlib/realpath.c	Tue Apr 20 08:51:21 2010	(r206892)
 +++ head/lib/libc/stdlib/realpath.c	Tue Apr 20 10:16:44 2010	(r206893)
 @@ -43,23 +43,37 @@ __FBSDID("$FreeBSD$");
  #include "un-namespace.h"
  
  /*
 - * char *realpath(const char *path, char resolved[PATH_MAX]);
 - *
   * Find the real name of path, by removing all ".", ".." and symlink
   * components.  Returns (resolved) on success, or (NULL) on failure,
   * in which case the path which caused trouble is left in (resolved).
   */
  char *
 -realpath(const char *path, char resolved[PATH_MAX])
 +realpath(const char * __restrict path, char * __restrict resolved)
  {
  	struct stat sb;
  	char *p, *q, *s;
  	size_t left_len, resolved_len;
  	unsigned symlinks;
 -	int serrno, slen;
 +	int serrno, slen, m;
  	char left[PATH_MAX], next_token[PATH_MAX], symlink[PATH_MAX];
  
 +	if (path == NULL) {
 +		errno = EINVAL;
 +		return (NULL);
 +	}
 +	if (path[0] == '\0') {
 +		errno = ENOENT;
 +		return (NULL);
 +	}
  	serrno = errno;
 +	if (resolved == NULL) {
 +		resolved = malloc(PATH_MAX);
 +		if (resolved == NULL)
 +			return (NULL);
 +		m = 1;
 +	} else
 +		m = 0;
 +
  	symlinks = 0;
  	if (path[0] == '/') {
  		resolved[0] = '/';
 @@ -71,12 +85,19 @@ realpath(const char *path, char resolved
  	} else {
  		if (getcwd(resolved, PATH_MAX) == NULL) {
  			strlcpy(resolved, ".", PATH_MAX);
 +			if (m) {
 +				serrno = errno;
 +				free(resolved);
 +				errno = serrno;
 +			}
  			return (NULL);
  		}
  		resolved_len = strlen(resolved);
  		left_len = strlcpy(left, path, sizeof(left));
  	}
  	if (left_len >= sizeof(left) || resolved_len >= PATH_MAX) {
 +		if (m)
 +			free(resolved);
  		errno = ENAMETOOLONG;
  		return (NULL);
  	}
 @@ -92,6 +113,8 @@ realpath(const char *path, char resolved
  		p = strchr(left, '/');
  		s = p ? p : left + left_len;
  		if (s - left >= sizeof(next_token)) {
 +			if (m)
 +				free(resolved);
  			errno = ENAMETOOLONG;
  			return (NULL);
  		}
 @@ -102,6 +125,8 @@ realpath(const char *path, char resolved
  			memmove(left, s + 1, left_len + 1);
  		if (resolved[resolved_len - 1] != '/') {
  			if (resolved_len + 1 >= PATH_MAX) {
 +				if (m)
 +					free(resolved);
  				errno = ENAMETOOLONG;
  				return (NULL);
  			}
 @@ -133,6 +158,8 @@ realpath(const char *path, char resolved
  		 */
  		resolved_len = strlcat(resolved, next_token, PATH_MAX);
  		if (resolved_len >= PATH_MAX) {
 +			if (m)
 +				free(resolved);
  			errno = ENAMETOOLONG;
  			return (NULL);
  		}
 @@ -141,16 +168,29 @@ realpath(const char *path, char resolved
  				errno = serrno;
  				return (resolved);
  			}
 +			if (m) {
 +				serrno = errno;
 +				free(resolved);
 +				errno = serrno;
 +			}
  			return (NULL);
  		}
  		if (S_ISLNK(sb.st_mode)) {
  			if (symlinks++ > MAXSYMLINKS) {
 +				if (m)
 +					free(resolved);
  				errno = ELOOP;
  				return (NULL);
  			}
  			slen = readlink(resolved, symlink, sizeof(symlink) - 1);
 -			if (slen < 0)
 +			if (slen < 0) {
 +				if (m) {
 +					serrno = errno;
 +					free(resolved);
 +					errno = serrno;
 +				}
  				return (NULL);
 +			}
  			symlink[slen] = '\0';
  			if (symlink[0] == '/') {
  				resolved[1] = 0;
 @@ -171,6 +211,8 @@ realpath(const char *path, char resolved
  			if (p != NULL) {
  				if (symlink[slen - 1] != '/') {
  					if (slen + 1 >= sizeof(symlink)) {
 +						if (m)
 +							free(resolved);
  						errno = ENAMETOOLONG;
  						return (NULL);
  					}
 @@ -179,6 +221,8 @@ realpath(const char *path, char resolved
  				}
  				left_len = strlcat(symlink, left, sizeof(left));
  				if (left_len >= sizeof(left)) {
 +					if (m)
 +						free(resolved);
  					errno = ENAMETOOLONG;
  					return (NULL);
  				}
 _______________________________________________
 svn-src-all@freebsd.org mailing list
 http://lists.freebsd.org/mailman/listinfo/svn-src-all
 To unsubscribe, send any mail to "svn-src-all-unsubscribe@freebsd.org"
 
Responsible-Changed-From-To: freebsd-bugs->kib 
Responsible-Changed-By: kib 
Responsible-Changed-When: Tue Apr 20 10:37:09 UTC 2010 
Responsible-Changed-Why:  
Take, reclassify. 

http://www.freebsd.org/cgi/query-pr.cgi?pr=121897 
State-Changed-From-To: open->patched 
State-Changed-By: linimon 
State-Changed-When: Tue Apr 20 14:23:14 UTC 2010 
State-Changed-Why:  
apparently a patch has been committed. 

http://www.freebsd.org/cgi/query-pr.cgi?pr=121897 
State-Changed-From-To: patched->closed 
State-Changed-By: kib 
State-Changed-When: Mon May 17 12:05:01 UTC 2010 
State-Changed-Why:  
Patch is in HEAD and RELENG_8. 

http://www.freebsd.org/cgi/query-pr.cgi?pr=121897 
>Unformatted:
