# HG changeset patch # User stuefe # Date 1489432991 -3600 # Node ID 9fbfb16993a5f868bfaaf1a6dcc68ac473382c18 # Parent 316b82947d140c6343988f590accdb8a77e24040 8173848: realpath is unsafe Summary: Fix occurrences of realpath in hotspot to use safe POSIX.1-2008 form. Reviewed-by: dsamersoff, dholmes, clanger diff --git a/src/os/aix/vm/os_aix.cpp b/src/os/aix/vm/os_aix.cpp --- a/src/os/aix/vm/os_aix.cpp +++ b/src/os/aix/vm/os_aix.cpp @@ -1576,7 +1576,7 @@ Dl_info dlinfo; int ret = dladdr(CAST_FROM_FN_PTR(void *, os::jvm_path), &dlinfo); assert(ret != 0, "cannot locate libjvm"); - char* rp = realpath((char *)dlinfo.dli_fname, buf); + char* rp = os::Posix::realpath((char *)dlinfo.dli_fname, buf, buflen); assert(rp != NULL, "error in realpath(): maybe the 'path' argument is too long?"); strncpy(saved_jvm_path, buf, sizeof(saved_jvm_path)); diff --git a/src/os/bsd/vm/os_bsd.cpp b/src/os/bsd/vm/os_bsd.cpp --- a/src/os/bsd/vm/os_bsd.cpp +++ b/src/os/bsd/vm/os_bsd.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1754,7 +1754,7 @@ assert(ret, "cannot locate libjvm"); char *rp = NULL; if (ret && dli_fname[0] != '\0') { - rp = realpath(dli_fname, buf); + rp = os::Posix::realpath(dli_fname, buf, buflen); } if (rp == NULL) { return; @@ -1786,7 +1786,7 @@ p = strrchr(buf, '/'); assert(strstr(p, "/libjvm") == p, "invalid library name"); - rp = realpath(java_home_var, buf); + rp = os::Posix::realpath(java_home_var, buf, buflen); if (rp == NULL) { return; } @@ -1820,7 +1820,7 @@ snprintf(buf + len, buflen-len, "/libjvm%s", JNI_LIB_SUFFIX); } else { // Fall back to path of current library - rp = realpath(dli_fname, buf); + rp = os::Posix::realpath(dli_fname, buf, buflen); if (rp == NULL) { return; } diff --git a/src/os/linux/vm/os_linux.cpp b/src/os/linux/vm/os_linux.cpp --- a/src/os/linux/vm/os_linux.cpp +++ b/src/os/linux/vm/os_linux.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -2318,7 +2318,7 @@ assert(ret, "cannot locate libjvm"); char *rp = NULL; if (ret && dli_fname[0] != '\0') { - rp = realpath(dli_fname, buf); + rp = os::Posix::realpath(dli_fname, buf, buflen); } if (rp == NULL) { return; @@ -2352,7 +2352,7 @@ } assert(strstr(p, "/libjvm") == p, "invalid library name"); - rp = realpath(java_home_var, buf); + rp = os::Posix::realpath(java_home_var, buf, buflen); if (rp == NULL) { return; } @@ -2373,7 +2373,7 @@ snprintf(buf + len, buflen-len, "/hotspot/libjvm.so"); } else { // Go back to path of .so - rp = realpath(dli_fname, buf); + rp = os::Posix::realpath(dli_fname, buf, buflen); if (rp == NULL) { return; } diff --git a/src/os/posix/vm/os_posix.cpp b/src/os/posix/vm/os_posix.cpp --- a/src/os/posix/vm/os_posix.cpp +++ b/src/os/posix/vm/os_posix.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1105,6 +1105,48 @@ return buf; } +char* os::Posix::realpath(const char* filename, char* outbuf, size_t outbuflen) { + + if (filename == NULL || outbuf == NULL || outbuflen < 1) { + assert(false, "os::Posix::realpath: invalid arguments."); + errno = EINVAL; + return NULL; + } + + char* result = NULL; + + // This assumes platform realpath() is implemented according to POSIX.1-2008. + // POSIX.1-2008 allows to specify NULL for the output buffer, in which case + // output buffer is dynamically allocated and must be ::free()'d by the caller. + char* p = ::realpath(filename, NULL); + if (p != NULL) { + if (strlen(p) < outbuflen) { + strcpy(outbuf, p); + result = outbuf; + } else { + errno = ENAMETOOLONG; + } + ::free(p); // *not* os::free + } else { + // Fallback for platforms struggling with modern Posix standards (AIX 5.3, 6.1). If realpath + // returns EINVAL, this may indicate that realpath is not POSIX.1-2008 compatible and + // that it complains about the NULL we handed down as user buffer. + // In this case, use the user provided buffer but at least check whether realpath caused + // a memory overwrite. + if (errno == EINVAL) { + outbuf[outbuflen - 1] = '\0'; + p = ::realpath(filename, outbuf); + if (p != NULL) { + guarantee(outbuf[outbuflen - 1] == '\0', "realpath buffer overwriter detected."); + result = p; + } + } + } + return result; + +} + + // Check minimum allowable stack sizes for thread creation and to initialize // the java system classes, including StackOverflowError - depends on page // size. diff --git a/src/os/posix/vm/os_posix.hpp b/src/os/posix/vm/os_posix.hpp --- a/src/os/posix/vm/os_posix.hpp +++ b/src/os/posix/vm/os_posix.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -96,6 +96,13 @@ // to buf with len buflen; buf is returned. static char* describe_pthread_attr(char* buf, size_t buflen, const pthread_attr_t* attr); + // A safe implementation of realpath which will not cause a buffer overflow if the resolved path + // is longer than PATH_MAX. + // On success, returns 'outbuf', which now contains the path. + // On error, it will return NULL and set errno. The content of 'outbuf' is undefined. + // On truncation error ( 'outbuf' too small), it will return NULL and set errno to ENAMETOOLONG. + static char* realpath(const char* filename, char* outbuf, size_t outbuflen); + }; /* diff --git a/src/os/solaris/vm/os_solaris.cpp b/src/os/solaris/vm/os_solaris.cpp --- a/src/os/solaris/vm/os_solaris.cpp +++ b/src/os/solaris/vm/os_solaris.cpp @@ -2034,7 +2034,9 @@ int ret = dladdr(CAST_FROM_FN_PTR(void *, os::jvm_path), &dlinfo); assert(ret != 0, "cannot locate libjvm"); if (ret != 0 && dlinfo.dli_fname != NULL) { - realpath((char *)dlinfo.dli_fname, buf); + if (os::Posix::realpath((char *)dlinfo.dli_fname, buf, buflen) == NULL) { + return; + } } else { buf[0] = '\0'; return; @@ -2065,7 +2067,9 @@ p = strrchr(buf, '/'); assert(strstr(p, "/libjvm") == p, "invalid library name"); - realpath(java_home_var, buf); + if (os::Posix::realpath(java_home_var, buf, buflen) == NULL) { + return; + } // determine if this is a legacy image or modules image // modules image doesn't have "jre" subdirectory len = strlen(buf); @@ -2082,7 +2086,9 @@ snprintf(buf + len, buflen-len, "/hotspot/libjvm.so"); } else { // Go back to path of .so - realpath((char *)dlinfo.dli_fname, buf); + if (os::Posix::realpath((char *)dlinfo.dli_fname, buf, buflen) == NULL) { + return; + } } } }