Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8233726

A new Lookup::hasFullPrivilegeAccess method for testing full privilege access

    XMLWordPrintable

    Details

    • Type: CSR
    • Status: Closed
    • Priority: P3
    • Resolution: Approved
    • Fix Version/s: 14
    • Component/s: core-libs
    • Labels:
      None
    • Subcomponent:
    • Compatibility Kind:
      behavioral
    • Compatibility Risk:
      medium
    • Compatibility Risk Description:
      Hide
      `Lookup::hasPrivateAccess` will return false in JDK 14 on a Lookup object produced from `MethodHandles::privateLookupIn` when teleported from one module to another. `Lookup::hasPrivateAccess` was added in Java SE 9 and it is believed that not many libraries depend on this method. A more common pattern to check private access is using `Lookup::lookupModes` method e.g. `lookupModes() & PRIVATE != 0`
      Show
      `Lookup::hasPrivateAccess` will return false in JDK 14 on a Lookup object produced from `MethodHandles::privateLookupIn` when teleported from one module to another. `Lookup::hasPrivateAccess` was added in Java SE 9 and it is believed that not many libraries depend on this method. A more common pattern to check private access is using `Lookup::lookupModes` method e.g. `lookupModes() & PRIVATE != 0`
    • Interface Kind:
      Java API
    • Scope:
      SE

      Description

      Summary

      Add a new Lookup::hasFullPrivilegeAccess method to replace Lookup::hasPrivateAccess and also update Lookup::defineClass behavior if this Lookup has full privilege access.

      Problem

      This CSR is a follow-up due to the change by JDK-8226916

      Lookup::hasPrivateAccess intends to test if this lookup is a full-power lookup; that is created by the original caller class calling MethodHandles::lookup. The current specification for Lookup::hasPrivateAccess returns true if the lookup modes contain PRIVATE but it does not check MODULE bit.

      In addition, the Lookup class specification contains the Discussion of private access section and Security manager interactions which needs to be re-examined. Prior to Java SE 9, a Lookup with private access is equivalent to a Lookup with full-power access. The list of capabilities need re-examination to determine what capabilities a Lookup with full-power access or with private access (no module access) are allowed.

      Solution

      MODULE mode in Java SE 14 is used to represent a Lookup whose original creator is a member in the module of the lookup class. MODULE bit will be dropped if teleporting from another module via MethodHandles::privateLookupIn.

      A new correctly named method Lookup::hasFullPrivilegeAccess is introduced to test if the lookup modes contain PRIVATE and MODULE access. Deprecate Lookup::hasPrivateAccess while Lookup::hasPrivateAccess is updated to call Lookup::hasFullPrivilegeAccess to match the original intent of Lookup::hasPrivateAccess.

      MethodHandles::privateLookupIn provides a mechanism for a framework to do cross-module teleporting and perform deep reflection on private members of a package opened to the caller module. So Lookup with full-power access is needed only for the capability to create method handle for a caller-sensitive method. A Lookup with PRIVATE access possesses other capabilities listed in the Discussion of private access section.

      W.r.t. security manager interfaction, the security permission check is skipped for full power lookup. Lookup::defineClass is updated to perform security permission check if the security manager is present and this lookup refuses access, consistent with other Lookup operations.

      Specification

      (1) MethodHandles::privateLookupIn

           /**
            * Returns a {@link Lookup lookup object} with
            * full capabilities to emulate all supported bytecode behaviors of the caller.
      -     * These capabilities include <a href="MethodHandles.Lookup.html#privacc">private access</a> to the caller.
      +     * These capabilities include {@linkplain Lookup#hasFullPrivilegeAccess() full privilege access} to the caller.
            * Factory methods on the lookup object can create
            * <a href="MethodHandleInfo.html#directmh">direct method handles</a>
            * for any member that the caller has access to via bytecodes,
      @@ -210,6 +210,7 @@
            * @since 9
            * @spec JPMS
            * @see Lookup#dropLookupMode
      +     * @see Lookup#hasFullPrivilegeAccess()
            * @see <a href="MethodHandles.Lookup.html#cross-module-lookup">Cross-module lookups</a>
            */
           public static Lookup privateLookupIn(Class<?> targetClass, Lookup caller) throws IllegalAccessException {

      (2) Lookup class specification

            * <a id="privacc"></a>
      -     * <em>Discussion of private access:</em>
      +     * <em>Discussion of private and module access:</em>
            * We say that a lookup has <em>private access</em>
            * if its {@linkplain #lookupModes lookup modes}
            * include the possibility of accessing {@code private} members
      @@ -561,8 +560,6 @@
            * only lookups with private access possess the following capabilities:
            * <ul style="font-size:smaller;">
            * <li>access private fields, methods, and constructors of the lookup class and its nestmates
      -     * <li>create method handles which invoke <a href="MethodHandles.Lookup.html#callsens">caller sensitive</a> methods,
      -     *     such as {@code Class.forName}
            * <li>create method handles which {@link Lookup#findSpecial emulate invokespecial} instructions
            * <li>avoid <a href="MethodHandles.Lookup.html#secmgr">package access checks</a>
            *     for classes accessible to the lookup class
      @@ -570,6 +567,18 @@
            *     within the same package member
            * </ul>
            * <p style="font-size:smaller;">
      +     * Similarly, a lookup with module access ensures that the original lookup creator was
      +     * a member in the same module as the lookup class.
      +     * <p style="font-size:smaller;">
      +     * Private and module access are independently determined modes; a lookup may have
      +     * either or both or neither.  A lookup which possesses both access modes is said to
      +     * possess {@link #hasFullPrivilegeAccess() full privilege access}.  Such a lookup has
      +     * the following additional capability:
      +     * <ul style="font-size:smaller;">
      +     * <li>create method handles which invoke <a href="MethodHandles.Lookup.html#callsens">caller sensitive</a> methods,
      +     *     such as {@code Class.forName}
      +     * </ul>
      +     * <p style="font-size:smaller;">
            * Each of these permissions is a consequence of the fact that a lookup object
            * with private access can be securely traced back to an originating class,
            * whose <a href="MethodHandles.Lookup.html#equiv">bytecode behaviors</a> and Java language access permissions
      @@ -644,7 +653,7 @@
            * <p>
            * {@link MethodHandles#privateLookupIn(Class, Lookup) MethodHandles.privateLookupIn(T.class, lookup)}
            * can be used to teleport a {@code lookup} from class {@code C} to class {@code T}
      -     * and create a new {@code Lookup} with <a href="#privcc">private access</a>
      +     * and create a new {@code Lookup} with <a href="#privacc">private access</a>
            * if the lookup class is allowed to do <em>deep reflection</em> on {@code T}.
            * The {@code lookup} must have {@link #MODULE} and {@link #PRIVATE} access
            * to call {@code privateLookupIn}.
      @@ -1110,7 +1119,7 @@
            * the {@code refc} and {@code defc} values are the class itself.)
            * The value {@code lookc} is defined as <em>not present</em>
            * if the current lookup object does not have
      -     * <a href="MethodHandles.Lookup.html#privacc">private access</a>.
      +     * {@linkplain #hasFullPrivilegeAccess() full privilege access}.
            * The calls are made according to the following rules:
            * <ul>
            * <li><b>Step 1:</b>
      @@ -1141,6 +1150,12 @@
            * Therefore, the above rules presuppose a member or class that is public,
            * or else that is being accessed from a lookup class that has
            * rights to access the member or class.
      +     * <p>
      +     * If a security manager is present and the current lookup object does not have
      +     * {@linkplain #hasFullPrivilegeAccess() full privilege access}, then
      +     * {@link #defineClass(byte[]) defineClass}
      +     * calls {@link SecurityManager#checkPermission smgr.checkPermission}
      +     * with {@code RuntimePermission("defineClass")}.
            *
            * <h2><a id="callsens"></a>Caller sensitive methods</h2>
            * A small number of Java methods have a special property called caller sensitivity.
      @@ -1160,8 +1175,8 @@
            * <p>
            * In cases where the lookup object is
            * {@link MethodHandles#publicLookup() publicLookup()},
      -     * or some other lookup object without
      -     * <a href="MethodHandles.Lookup.html#privacc">private access</a>,
      +     * or some other lookup object without the
      +     * {@linkplain #hasFullPrivilegeAccess() full privilege access},
            * the lookup class is disregarded.
            * In such cases, no caller-sensitive method handle can be created,
            * access is forbidden, and the lookup fails with an

      (3) Lookup::defineClass

            * access is forbidden, and the lookup fails with an
      @@ -1514,7 +1525,8 @@
                * @apiNote
                * A lookup with {@code PACKAGE} but not {@code PRIVATE} mode can safely
                * delegate non-public access within the package of the lookup class without
      -         * conferring private access.  A lookup with {@code MODULE} but not
      +         * conferring  <a href="MethodHandles.Lookup.html#privacc"> private access</a>.
      +         * A lookup with {@code MODULE} but not
                * {@code PACKAGE} mode can safely delegate {@code PUBLIC} access within
                * the module of the lookup class without conferring package access.
                * A lookup with a {@linkplain #previousLookupClass() previous lookup class}
      @@ -1565,8 +1577,9 @@
                * run at a later time, as detailed in section 12.4 of the <em>The Java Language
                * Specification</em>. </p>
                *
      -         * <p> If there is a security manager, its {@code checkPermission} method is first called
      -         * to check {@code RuntimePermission("defineClass")}. </p>
      +         * <p> If there is a security manager and this lookup does not have {@linkplain
      +         * #hasPrivateAccess() full privilege access}, its {@code checkPermission} method
      +         * is first called to check {@code RuntimePermission("defineClass")}. </p>
                *
                * @param bytes the class bytes
                * @return the {@code Class} object for the class
      @@ -1575,7 +1588,8 @@
                * @throws IllegalAccessException if this lookup does not have {@code PACKAGE} access
                * @throws LinkageError if the class is malformed ({@code ClassFormatError}), cannot be
                * verified ({@code VerifyError}), is already defined, or another linkage error occurs
      -         * @throws SecurityException if denied by the security manager
      +         * @throws SecurityException if a security manager is present and it
      +         *                           <a href="MethodHandles.Lookup.html#secmgr">refuses access</a>
                * @throws NullPointerException if {@code bytes} is {@code null}
                * @since 9
                * @spec JPMS
      @@ -1584,12 +1598,13 @@
                * @see ClassLoader#defineClass(String,byte[],int,int,ProtectionDomain)

      (4) Lookup::hasPrivateAccess

               /**
      -         * Returns {@code true} if this lookup has {@code PRIVATE} access.
      -         * @return {@code true} if this lookup has {@code PRIVATE} access.
      +         * Returns {@code true} if this lookup has {@code PRIVATE} and {@code MODULE} access.
      +         * @return {@code true} if this lookup has {@code PRIVATE} and {@code MODULE} access.
      +         * @deprecated This method was originally designed to test {@code PRIVATE} access
      +         * that implies full privilege access but {@code MODULE} access has since become
      +         * independent of {@code PRIVATE} access.  It is recommended to call
      +         * {@link #hasFullPrivilegeAccess()} instead.
                * @since 9
                */
      +        @Deprecated(since="14")
               public boolean hasPrivateAccess() {

      (5) Lookup::hasFullPrivilegeAccess

      +        /**
      +         * Returns {@code true} if this lookup has <em>full privilege access</em>,
      +         * i.e. {@code PRIVATE} and {@code MODULE} access.
      +         * A {@code Lookup} object must have full privilege access in order to
      +         * access all members that are allowed to the {@linkplain #lookupClass() lookup class}.
      +         *
      +         * @return {@code true} if this lookup has full privilege access.
      +         * @since 14
      +         * @see <a href="MethodHandles.Lookup.html#privacc">private and module access</a>
      +         */
      +        public boolean hasFullPrivilegeAccess()

      (6) Lookup::findClass javadoc update is a spec clarification. Not a spec change.

               /**
      -         * Looks up a class by name from the lookup context defined by this {@code Lookup} object. The static
      -         * initializer of the class is not run.
      -         * <p>
      -         * The lookup context here is determined by the {@linkplain #lookupClass() lookup class}, its class
      -         * loader, and the {@linkplain #lookupModes() lookup modes}. In particular, the method first attempts to
      -         * load the requested class, and then determines whether the class is accessible to this lookup object.
      +         * Looks up a class by name from the lookup context defined by this {@code Lookup} object,
      +         * <a href="MethodHandles.Lookup.html#equiv">as if resolved</a> by an {@code ldc} instruction.
      +         * Such a resolution, as specified in JVMS 5.4.3.1 section, attempts to locate and load the class,
      +         * and then determines whether the class is accessible to this lookup object.
      +         * <p>
      +         * The lookup context here is determined by the {@linkplain #lookupClass() lookup class},
      +         * its class loader, and the {@linkplain #lookupModes() lookup modes}.
                *
                * @param targetName the fully qualified name of the class to be looked up.
                * @return the requested class.
      @@ -1948,9 +1968,8 @@
                * @throws ClassNotFoundException if the class cannot be loaded by the lookup class' loader.
                * @throws IllegalAccessException if the class is not accessible, using the allowed access
                * modes.
      -         * @throws    SecurityException if a security manager is present and it
      -         *                              <a href="MethodHandles.Lookup.html#secmgr">refuses access</a>
                * @since 9
      +         * @jvms 5.4.3.1 Class and Interface Resolution
                */

      See attached MethodHandles.Lookup-report-v4.html and MethodHandles-report.html specdiff.

        Attachments

          Issue Links

            Activity

              People

              Assignee:
              mchung Mandy Chung
              Reporter:
              mchung Mandy Chung
              Reviewed By:
              Alan Bateman
              Votes:
              0 Vote for this issue
              Watchers:
              2 Start watching this issue

                Dates

                Created:
                Updated:
                Resolved: