From aa15372140b6b509a26742fd85fe78dd77d9a642 Mon Sep 17 00:00:00 2001 From: Andy Fiddaman Date: Sat, 27 Feb 2021 00:47:49 +0000 Subject: 13586 getcwd() should accept a 0 length argument Reviewed by: Jason King Reviewed by: Dan McDonald Reviewed by: Gordon Ross Reviewed by: Robert Mustacchi Approved by: Rich Lowe --- usr/src/lib/libc/port/gen/getcwd.c | 50 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 48 insertions(+), 2 deletions(-) (limited to 'usr/src/lib/libc') diff --git a/usr/src/lib/libc/port/gen/getcwd.c b/usr/src/lib/libc/port/gen/getcwd.c index d832d798d7..62f12e027e 100644 --- a/usr/src/lib/libc/port/gen/getcwd.c +++ b/usr/src/lib/libc/port/gen/getcwd.c @@ -22,10 +22,9 @@ /* * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. + * Copyright 2021 OmniOS Community Edition (OmniOSce) Association. */ -#pragma ident "%Z%%M% %I% %E% SMI" - /* * getcwd() returns the pathname of the current working directory. * On error, a NULL pointer is returned and errno is set. @@ -34,16 +33,63 @@ #pragma weak _getcwd = getcwd #include "lint.h" +#include #include #include #include +#include #include +#include +#include char * getcwd(char *pathname, size_t size) { int alloc = 0; + if (size == 0 && pathname == NULL) { + /* + * If no size was provided, start with a buffer that should + * accommodate any normal path and, if it is not big enough, + * keep doubling it to try and make enough space. + * + * Any non-global zone path is longer when observed from the + * global zone, and some filesystems, including ZFS, support + * paths much longer than MAXPATHLEN/_PC_PATH_MAX. + * + * To protect against unbounded memory usage, cap to 128KiB. + * This is an arbitrary limit which is far bigger than the + * length of any practical path on the system. + */ + if ((size = pathconf(".", _PC_PATH_MAX)) == -1) + size = MAXPATHLEN; + + while (size <= 0x20000) { + if ((pathname = reallocf(pathname, size)) == NULL) { + errno = ENOMEM; + return (NULL); + } + if (syscall(SYS_getcwd, pathname, size) == 0) { + char *ret; + + /* + * Shrink the buffer to the length actually + * required to hold the final path. + */ + ret = realloc(pathname, strlen(pathname) + 1); + if (ret == NULL) + return (pathname); + + return (ret); + } + if (errno != ERANGE) + break; + size <<= 1; + } + free(pathname); + return (NULL); + } + if (size == 0) { errno = EINVAL; return (NULL); -- cgit v1.2.3