Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Consistently load OpenSSL libraries among different platforms #884

Open
wants to merge 4 commits into
base: openj9
Choose a base branch
from

Conversation

KostasTsiounis
Copy link
Contributor

@KostasTsiounis KostasTsiounis commented Nov 12, 2024

As part of this pull request, these changes are performed:

  • Allow loading specific user-defined OpenSSL library using the -Djdk.native.openssl.lib option.
  • OpenSSL library loading is consolidated into a single file using ifdefs.
  • The platform-specific MD files are no longer needed and are thus deleted.
  • Additional traces are added to indicate the attempts and actual OpenSSL library loaded.
  • The location of the library loaded is printed.

Moreover, the order of preference for loading a library is updated to follow this order:

  1. Explicitly load what was specified via JVM property. Fail if loading fails.
  2. Search within the Semeru directories for a bundled version.
  3. Search the system for existing libraries and attempt to find the higher version.
  4. If all of the previous steps fail, revert to original Java implementation for crypto.

Co-authored by: Paritosh Kumar [email protected]
Co-authored by: Kostas Tsiounis [email protected]

Signed-off-by: Kostas Tsiounis [email protected]

@pshipton
Copy link
Member

The commit comment mentions jdk.openssl.libName

@pshipton pshipton requested a review from keithc-ca November 12, 2024 18:53
@pshipton
Copy link
Member

There is a typo as well - porperty

@KostasTsiounis KostasTsiounis force-pushed the ossl_load branch 2 times, most recently from df4519f to a25ccf8 Compare November 12, 2024 18:55
@KostasTsiounis
Copy link
Contributor Author

The commit comment mentions jdk.openssl.libName

Updated to what we discussed.

There is a typo as well - porperty

Fixed that.

Copy link
Member

@keithc-ca keithc-ca left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please apply formatting and style feedback throughout.

@KostasTsiounis KostasTsiounis force-pushed the ossl_load branch 2 times, most recently from 383df87 to 2b30272 Compare November 19, 2024 18:40
if (traceEnabled && (NULL != crypto_library)) {

#if defined(_AIX)
int rc = -1;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using 0 may be slightly cheaper (the value isn't used).

"libcrypto.3.dylib", /* 3.x library name */
"libcrypto.1.1.dylib", /* 1.1.x library name */
"libcrypto.1.0.0.dylib", /* 1.0.x library name */
/* "libcrypto.dylib" Apple no longer supports loading symlink. */
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it better to add it later if we find it's needed.

@@ -2563,7 +2904,7 @@ Java_jdk_crypto_jniprovider_NativeCrypto_ECGenerateKeyPair
goto cleanup;
}

// to translate the private key to java format, we need the private key BIGNUM
/* to translate the private key to java format, we need the private key BIGNUM */
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some C++-style comments remain; see lines 3622, 3628, 3664, etc.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Searched and replaced all C++-style comments.

@keithc-ca
Copy link
Member

keithc-ca commented Dec 2, 2024

At some point, this should be squashed and the commit message updated: some lines are too long. Bullet points should be continued with clarifying indentation, for example:

- Additional traces are added to indicate the attempts and actual
  OpenSSL library laoded.

The summary line should not end with a period.

@KostasTsiounis KostasTsiounis force-pushed the ossl_load branch 2 times, most recently from 149d822 to c422ba7 Compare December 3, 2024 15:17
@KostasTsiounis KostasTsiounis changed the title Consistently load OpenSSL libraries among different platforms. Consistently load OpenSSL libraries among different platforms Dec 3, 2024
@KostasTsiounis
Copy link
Contributor Author

KostasTsiounis commented Dec 3, 2024

At some point, this should be squashed and the commit message updated: some lines are too long. Bullet points should be continued with clarifying indentation, for example:

- Additional traces are added to indicate the attempts and actual
  OpenSSL library laoded.

The summary line should not end with a period.

I have squashed and updated the commit message according to suggestions.

@keithc-ca
Copy link
Member

Please rebase and resolve the merge conflict.

@KostasTsiounis
Copy link
Contributor Author

Please rebase and resolve the merge conflict.

Rebased to head.

"libcrypto.so.1.1", /* 1.1.x library name */
"libcrypto.so.1.0.0", /* 1.0.x library name */
#elif defined(__APPLE__) /* defined(_AIX) */
/* "libcrypto.dylib" Apple no longer supports loading symlink. */
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the entry for the symlink should be included as it was before this change.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moved to the end of the list.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's consistent with the old behavior, nor with the comment above (even if it were more than just a comment here).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you have a reference to support the claim that symbolic links are not supported on macOS?

Copy link
Contributor Author

@KostasTsiounis KostasTsiounis Dec 6, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We found in discussion like this, that Apple has disabled generic loads after MacOS 11. We tried ourselves too and were able to reproduce it.

Also, I'm confused. Do we want this in the beginning of the list, as it would be if we actually used it, or the end, like it was previously?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Apple's release notice at https://developer.apple.com/documentation/macos-release-notes/macos-big-sur-11_0_1-release-notes, says

check for library presence by attempting to dlopen() the path, which will correctly check for the library in the cache

Since we're using dlopen(), I don't see a problem. Have you observed otherwise? If listing the name of what is expected to by a symlink doesn't cause a problem, then it should be first to be consistent with other platforms.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you see this and this comments, you'll see what we did to test and the failure we were getting.

It was producing a warning that was turned to be fatal after MacOS 11. I think it's because the libcrypto.dylib is not a soft link by default (I've seen hacks where one would delete the existing one and create a soft link manually and it would work), but rather it's expected to produce a failure. It could work if someone has performed those extra steps, but a failure is produced if the default files are in place.

Comment on lines 656 to 657
/* "libcrypto.dylib" In MacOS 11 or later, loading this symlink causes a
fatal warning and associated abort by default. */
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's better, but the */ of a multi-line comment should be on a line by itself.
Please correct the spelling of "macOS", and I think It should say "on" (a platform) rather than "in".
Another approach would be to mention the exception for macOS when explaining why symlinks are listed first.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You mean in the overall comment?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added wording as a note in the comment above the libraries.

Comment on lines 793 to 814
if (NULL != jlibname) {
clibname = (*env)->GetStringUTFChars(env, jlibname, NULL);
if ('\0' == clibname[0]) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is missing error handling: GetStringUTFChars() may return NULL. Suggest:

    if (NULL != jlibname) {
        const char *clibname = (*env)->GetStringUTFChars(env, jlibname, NULL);
        if (NULL == clibname) {
            if (traceEnabled) {
                fprintf(stderr, "Failed to get jdk.native.openssl.lib value.\n");
                fflush(stderr);
            }
            return -1;
        }
        if ('\0' == clibname[0]) {
            if (traceEnabled) {
                fprintf(stderr, "The jdk.native.openssl.lib property is not set.\n");
                fflush(stderr);
            }
        } else {
            crypto_library = load_crypto_library(traceEnabled, clibname);
            if (NULL == crypto_library) {
                if (traceEnabled) {
                    fprintf(stderr, "OpenSSL library specified in jdk.openssl.lib couldn't be loaded.\n");
                    fflush(stderr);
                }
                (*env)->ReleaseStringUTFChars(env, jlibname, clibname);
                return -1;
            }
        }
        (*env)->ReleaseStringUTFChars(env, jlibname, clibname);
    }

Notice the previously missing calls to ReleaseStringUTFChars() on failure paths.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed to suggestion.

Comment on lines 812 to 842
if (NULL != jhomepath) {
chomepath = (*env)->GetStringUTFChars(env, jhomepath, NULL);
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

More missing error handling:

    if (NULL != jhomepath) {
        chomepath = (*env)->GetStringUTFChars(env, jhomepath, NULL);
        if (NULL == chomepath) {
            if (traceEnabled) {
                fprintf(stderr, "Failed to get java.home value.\n");
                fflush(stderr);
            }
            return -1;
        }
    }

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed to suggestion.

Comment on lines 823 to 824
(*env)->ReleaseStringUTFChars(env, jlibname, clibname);
(*env)->ReleaseStringUTFChars(env, jhomepath, chomepath);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

clibname is released above (in my suggestions), chomepath cannot be released if jhomepath is NULL.

    if (NULL != jhomepath) {
        (*env)->ReleaseStringUTFChars(env, jhomepath, chomepath);
    }

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed to suggestion.

numOfLibs = sizeof(libNames) / sizeof(libNames[0]);
/* If JAVA_HOME is not null or empty and no library has been loaded yet, try there. */
if ((NULL != chomepath) && ('\0' != *chomepath) && (NULL == crypto_library)) {
char **libNamesWithPath = malloc(size * sizeof(char *));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some problems remain:

  • I don't see a definition of size which means this won't compile
  • only one entry in libNamesWithPath is used at a time, so there's no need for an array
  • libNamesWithPath and it's entries are not freed, nor is libPath
  • the hard-coded value 16 should be replaced by sizeof(suffix) where suffix is suitably defined:
#if defined(_WIN32)
    static const char pathSuffix[] = "\\bin\\";
#else /* defined(_WIN32) */
    static const char pathSuffix[] = "/lib/";
#endif /* defined(_WIN32) */
  • the static locals can be declared first, allowing non-static locals to be initialized directly
    const size_t numOfLibs = sizeof(libNames) / sizeof(libNames[0]);
#if defined(_AIX)
    const size_t num_of_generic = 4;
#elif defined(__linux__) /* defined(_AIX) */
    const size_t num_of_generic = 1;
#else /* defined(__linux__) */
    const size_t num_of_generic = 0;
#endif /* defined(_AIX) */

    void *result = NULL;
    void *prevResult = NULL;
    size_t i = 0;
    long tempVersion = 0;
    long previousVersion = 0;
  • this could do a single allocation for libPath that has sufficient room for chomepath, the subdirectory, and the longest library name, replacing the library name for each iteration (but that might be harder to understand)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Regarding the problems, here is what I did:

  • I renamed size to numOfLibs, but I missed that spot.
  • I avoid creating an array. I just use a single libNameWithPath variable in the loop.
  • I added free commands for both where appropriate.
  • I substituted the hardcoded value with appropriately calculated sizes.
  • I moved declarations around as suggested to have the non-static ones be initialized directly.
  • I think that would add complexity that wouldn't really get us much since this is only run in the beginning and the loop stops as soon as a library is found.

for (i = 0; i < numOfLibs; i++) {
size_t file_len = strlen(libNames[i]);
/* Allocate memory for the new file name with the path. */
char *libNameWithPath = (char *)malloc((libPath_len + file_len));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please remove the redundant parentheses and add 1 for the NUL terminator.

            char *libNameWithPath = (char *)malloc(path_len + file_len + 1);

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed parentheses and added 1.

Comment on lines 716 to 718
if (NULL != libNameWithPath) {
free(libNameWithPath);
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

libNameWithPath cannot be NULL here (see lines 700-705).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, makes sense. Removed check and free.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Line 717 must stay (it was just checking for NULL that was unnecessary).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, my bad. Re-added free.

paritkum and others added 3 commits December 9, 2024 15:48
As part of this pull request, these changes are performed:
- Allow loading specific user-defined OpenSSL library using the
  -Djdk.native.openssl.lib option.
- OpenSSL library loading is consolidated into a single file using
  ifdefs.
- The platform-specific MD files are no longer needed and are thus
  deleted.
- Additional traces are added to indicate the attempts and actual
  OpenSSL library loaded.
- The location of the library loaded is printed.

Moreover, the order of preference for loading a library is updated to
follow this order:

1. Explicitly load what was specified via JVM property. Fail if loading
   fails.
2. Search within the Semeru directories for a bundled version.
3. Search the system for existing libraries and attempt to find the
   higher version.
4. If all of the previous steps fail, revert to original Java
   implementation for crypto.

Co-authored by: Paritosh Kumar <[email protected]>
Co-authored by: Kostas Tsiounis <[email protected]>

Signed-off-by: Kostas Tsiounis <[email protected]>
#else /* defined(_WIN32) */
static const char pathSuffix[] = "/lib/";
#endif /* defined(_WIN32) */
size_t path_len = strlen(chomepath) + sizeof(pathSuffix) - 1;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A blank line before lines 683 and 685 would be welcome (and consistent with lines 660 and 669).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Blank lines added.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants