8173848: realpath is unsafe
Summary: Fix occurrences of realpath in hotspot to use safe POSIX.1-2008 form.
Reviewed-by: dsamersoff, dholmes, clanger
--- a/hotspot/src/os/aix/vm/os_aix.cpp Wed Mar 15 10:25:37 2017 -0400
+++ b/hotspot/src/os/aix/vm/os_aix.cpp Mon Mar 13 20:23:11 2017 +0100
@@ -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));
--- a/hotspot/src/os/bsd/vm/os_bsd.cpp Wed Mar 15 10:25:37 2017 -0400
+++ b/hotspot/src/os/bsd/vm/os_bsd.cpp Mon Mar 13 20:23:11 2017 +0100
@@ -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;
}
--- a/hotspot/src/os/linux/vm/os_linux.cpp Wed Mar 15 10:25:37 2017 -0400
+++ b/hotspot/src/os/linux/vm/os_linux.cpp Mon Mar 13 20:23:11 2017 +0100
@@ -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;
}
--- a/hotspot/src/os/posix/vm/os_posix.cpp Wed Mar 15 10:25:37 2017 -0400
+++ b/hotspot/src/os/posix/vm/os_posix.cpp Mon Mar 13 20:23:11 2017 +0100
@@ -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 overwrite 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.
--- a/hotspot/src/os/posix/vm/os_posix.hpp Wed Mar 15 10:25:37 2017 -0400
+++ b/hotspot/src/os/posix/vm/os_posix.hpp Mon Mar 13 20:23:11 2017 +0100
@@ -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);
+
};
/*
--- a/hotspot/src/os/solaris/vm/os_solaris.cpp Wed Mar 15 10:25:37 2017 -0400
+++ b/hotspot/src/os/solaris/vm/os_solaris.cpp Mon Mar 13 20:23:11 2017 +0100
@@ -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;
+ }
}
}
}