Browse Source

Recent Single Unix will malloc memory if the second argument of realpath()

is NULL, and third-party software is starting to rely upon this.
Adapted from FreeBSD via Jona Joachim (jaj ; hcl-club , .lu), with minor
tweaks from nicm@ and yours truly.
OPENBSD_5_0
miod 13 years ago
parent
commit
3f8c480969
2 changed files with 52 additions and 17 deletions
  1. +17
    -4
      src/lib/libc/stdlib/realpath.3
  2. +35
    -13
      src/lib/libc/stdlib/realpath.c

+ 17
- 4
src/lib/libc/stdlib/realpath.3 View File

@ -28,9 +28,9 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE. .\" SUCH DAMAGE.
.\" .\"
.\" $OpenBSD: realpath.3,v 1.15 2007/07/06 15:42:04 millert Exp $
.\" $OpenBSD: realpath.3,v 1.16 2011/07/24 21:03:00 miod Exp $
.\" .\"
.Dd $Mdocdate: July 6 2007 $
.Dd $Mdocdate: July 24 2011 $
.Dt REALPATH 3 .Dt REALPATH 3
.Os .Os
.Sh NAME .Sh NAME
@ -40,7 +40,7 @@
.Fd #include <limits.h> .Fd #include <limits.h>
.Fd #include <stdlib.h> .Fd #include <stdlib.h>
.Ft "char *" .Ft "char *"
.Fn realpath "const char *pathname" "char resolved[PATH_MAX]"
.Fn realpath "const char *pathname" "char *resolved"
.Sh DESCRIPTION .Sh DESCRIPTION
The The
.Fn realpath .Fn realpath
@ -60,7 +60,8 @@ argument
.Em must .Em must
refer to a buffer capable of storing at least refer to a buffer capable of storing at least
.Dv PATH_MAX .Dv PATH_MAX
characters.
characters, or be
.Dv NULL .
.Pp .Pp
The The
.Fn realpath .Fn realpath
@ -78,6 +79,13 @@ The
function returns function returns
.Fa resolved .Fa resolved
on success. on success.
If
.Fa resolved
is
.Dv NULL
and no error occured, then
.Fa realpath
returns a NUL-terminated string in a newly allocated buffer.
If an error occurs, If an error occurs,
.Fn realpath .Fn realpath
returns returns
@ -98,6 +106,11 @@ and
.Sh SEE ALSO .Sh SEE ALSO
.Xr readlink 1 , .Xr readlink 1 ,
.Xr getcwd 3 .Xr getcwd 3
.Sh STANDARDS
The
.Fn realpath
function conforms to
.St -p1003.1-2008 .
.Sh HISTORY .Sh HISTORY
The The
.Fn realpath .Fn realpath


+ 35
- 13
src/lib/libc/stdlib/realpath.c View File

@ -1,4 +1,4 @@
/* $OpenBSD: realpath.c,v 1.13 2005/08/08 08:05:37 espie Exp $ */
/* $OpenBSD: realpath.c,v 1.14 2011/07/24 21:03:00 miod Exp $ */
/* /*
* Copyright (c) 2003 Constantin S. Svintsoff <kostik@iclub.nsu.ru> * Copyright (c) 2003 Constantin S. Svintsoff <kostik@iclub.nsu.ru>
* *
@ -43,16 +43,30 @@
* in which case the path which caused trouble is left in (resolved). * in which case the path which caused trouble is left in (resolved).
*/ */
char * char *
realpath(const char *path, char resolved[PATH_MAX])
realpath(const char *path, char *resolved)
{ {
struct stat sb; struct stat sb;
char *p, *q, *s; char *p, *q, *s;
size_t left_len, resolved_len; size_t left_len, resolved_len;
unsigned symlinks; unsigned symlinks;
int serrno, slen;
int serrno, slen, mem_allocated;
char left[PATH_MAX], next_token[PATH_MAX], symlink[PATH_MAX]; char left[PATH_MAX], next_token[PATH_MAX], symlink[PATH_MAX];
if (path[0] == '\0') {
errno = ENOENT;
return (NULL);
}
serrno = errno; serrno = errno;
if (resolved == NULL) {
resolved = malloc(PATH_MAX);
if (resolved == NULL)
return (NULL);
mem_allocated = 1;
} else
mem_allocated = 0;
symlinks = 0; symlinks = 0;
if (path[0] == '/') { if (path[0] == '/') {
resolved[0] = '/'; resolved[0] = '/';
@ -63,7 +77,10 @@ realpath(const char *path, char resolved[PATH_MAX])
left_len = strlcpy(left, path + 1, sizeof(left)); left_len = strlcpy(left, path + 1, sizeof(left));
} else { } else {
if (getcwd(resolved, PATH_MAX) == NULL) { if (getcwd(resolved, PATH_MAX) == NULL) {
strlcpy(resolved, ".", PATH_MAX);
if (mem_allocated)
free(resolved);
else
strlcpy(resolved, ".", PATH_MAX);
return (NULL); return (NULL);
} }
resolved_len = strlen(resolved); resolved_len = strlen(resolved);
@ -71,7 +88,7 @@ realpath(const char *path, char resolved[PATH_MAX])
} }
if (left_len >= sizeof(left) || resolved_len >= PATH_MAX) { if (left_len >= sizeof(left) || resolved_len >= PATH_MAX) {
errno = ENAMETOOLONG; errno = ENAMETOOLONG;
return (NULL);
goto err;
} }
/* /*
@ -86,7 +103,7 @@ realpath(const char *path, char resolved[PATH_MAX])
s = p ? p : left + left_len; s = p ? p : left + left_len;
if (s - left >= sizeof(next_token)) { if (s - left >= sizeof(next_token)) {
errno = ENAMETOOLONG; errno = ENAMETOOLONG;
return (NULL);
goto err;
} }
memcpy(next_token, left, s - left); memcpy(next_token, left, s - left);
next_token[s - left] = '\0'; next_token[s - left] = '\0';
@ -96,7 +113,7 @@ realpath(const char *path, char resolved[PATH_MAX])
if (resolved[resolved_len - 1] != '/') { if (resolved[resolved_len - 1] != '/') {
if (resolved_len + 1 >= PATH_MAX) { if (resolved_len + 1 >= PATH_MAX) {
errno = ENAMETOOLONG; errno = ENAMETOOLONG;
return (NULL);
goto err;
} }
resolved[resolved_len++] = '/'; resolved[resolved_len++] = '/';
resolved[resolved_len] = '\0'; resolved[resolved_len] = '\0';
@ -127,23 +144,23 @@ realpath(const char *path, char resolved[PATH_MAX])
resolved_len = strlcat(resolved, next_token, PATH_MAX); resolved_len = strlcat(resolved, next_token, PATH_MAX);
if (resolved_len >= PATH_MAX) { if (resolved_len >= PATH_MAX) {
errno = ENAMETOOLONG; errno = ENAMETOOLONG;
return (NULL);
goto err;
} }
if (lstat(resolved, &sb) != 0) { if (lstat(resolved, &sb) != 0) {
if (errno == ENOENT && p == NULL) { if (errno == ENOENT && p == NULL) {
errno = serrno; errno = serrno;
return (resolved); return (resolved);
} }
return (NULL);
goto err;
} }
if (S_ISLNK(sb.st_mode)) { if (S_ISLNK(sb.st_mode)) {
if (symlinks++ > MAXSYMLINKS) { if (symlinks++ > MAXSYMLINKS) {
errno = ELOOP; errno = ELOOP;
return (NULL);
goto err;
} }
slen = readlink(resolved, symlink, sizeof(symlink) - 1); slen = readlink(resolved, symlink, sizeof(symlink) - 1);
if (slen < 0) if (slen < 0)
return (NULL);
goto err;
symlink[slen] = '\0'; symlink[slen] = '\0';
if (symlink[0] == '/') { if (symlink[0] == '/') {
resolved[1] = 0; resolved[1] = 0;
@ -165,7 +182,7 @@ realpath(const char *path, char resolved[PATH_MAX])
if (symlink[slen - 1] != '/') { if (symlink[slen - 1] != '/') {
if (slen + 1 >= sizeof(symlink)) { if (slen + 1 >= sizeof(symlink)) {
errno = ENAMETOOLONG; errno = ENAMETOOLONG;
return (NULL);
goto err;
} }
symlink[slen] = '/'; symlink[slen] = '/';
symlink[slen + 1] = 0; symlink[slen + 1] = 0;
@ -173,7 +190,7 @@ realpath(const char *path, char resolved[PATH_MAX])
left_len = strlcat(symlink, left, sizeof(left)); left_len = strlcat(symlink, left, sizeof(left));
if (left_len >= sizeof(left)) { if (left_len >= sizeof(left)) {
errno = ENAMETOOLONG; errno = ENAMETOOLONG;
return (NULL);
goto err;
} }
} }
left_len = strlcpy(left, symlink, sizeof(left)); left_len = strlcpy(left, symlink, sizeof(left));
@ -187,4 +204,9 @@ realpath(const char *path, char resolved[PATH_MAX])
if (resolved_len > 1 && resolved[resolved_len - 1] == '/') if (resolved_len > 1 && resolved[resolved_len - 1] == '/')
resolved[resolved_len - 1] = '\0'; resolved[resolved_len - 1] = '\0';
return (resolved); return (resolved);
err:
if (mem_allocated)
free(resolved);
return (NULL);
} }

Loading…
Cancel
Save