Package org.apache.commons.weaver.privilizer

Source Code of org.apache.commons.weaver.privilizer.PrivilizingVisitor

/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.commons.weaver.privilizer;

import java.lang.reflect.Modifier;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
import java.util.LinkedHashMap;
import java.util.Map;

import org.apache.commons.lang3.ArrayUtils;
import org.objectweb.asm.AnnotationVisitor;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.FieldVisitor;
import org.objectweb.asm.Label;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
import org.objectweb.asm.commons.GeneratorAdapter;
import org.objectweb.asm.commons.Method;
import org.objectweb.asm.commons.StaticInitMerger;

/**
* ASM {@link ClassVisitor} to privilize {@link Privileged} methods.
*/
class PrivilizingVisitor extends Privilizer.PrivilizerClassVisitor {
    final Map<Method, String> privilegedMethods = new LinkedHashMap<Method, String>();
    boolean annotated;
    final Policy policy;
    final AccessLevel accessLevel;

    /**
     * Create a new {@link PrivilizingVisitor}.
     * @param privilizer owner
     * @param cv next
     */
    PrivilizingVisitor(final Privilizer privilizer, final ClassVisitor cv) { //NOPMD
        privilizer.super();
        this.policy = privilizer.policy;
        this.accessLevel = privilizer.accessLevel;
        this.cv =
            new InlineNestedPrivilegedCalls(privilizer, privilegedMethods, new StaticInitMerger(
                privilizer.generateName("clinit"), cv));
    }

    private void annotate() {
        if (!annotated) {
            annotated = true;
            final AnnotationVisitor privilizedVisitor =
                super.visitAnnotation(Type.getType(Privilized.class).getDescriptor(), false);
            privilizedVisitor.visit("value", policy.name());
            privilizedVisitor.visitEnd();
        }
    }

    @Override
    public void visitInnerClass(final String name, final String outerName, final String innerName, final int access) {
        annotate();
        super.visitInnerClass(name, outerName, innerName, access);
    }

    @Override
    public FieldVisitor visitField(final int access, final String name, final String desc, final String signature,
        final Object value) {
        annotate();
        return super.visitField(access, name, desc, signature, value);
    }

    @Override
    public MethodVisitor visitMethod(final int access, final String name, final String desc, final String signature,
        final String[] exceptions) {
        annotate();
        final MethodVisitor originalMethod = super.visitMethod(access, name, desc, signature, exceptions);
        final Method methd = new Method(name, desc);

        return new GeneratorAdapter(Opcodes.ASM4, originalMethod, access, name, desc) {

            @Override
            public AnnotationVisitor visitAnnotation(final String desc, final boolean visible) {
                if (Type.getType(Privileged.class).getDescriptor().equals(desc)) {
                    final AccessLevel localAccessLevel = AccessLevel.of(access);
                    if (accessLevel.compareTo(localAccessLevel) > 0) {
                        throw new RuntimeException(new IllegalAccessException("Method " + className + "#" + methd
                            + " must have maximum access level '" + accessLevel + "' but is defined wider ('"
                            + localAccessLevel + "')"));
                    }
                    if (AccessLevel.PACKAGE.compareTo(accessLevel) > 0) {
                        privilizer().env.warn("Possible security leak: granting privileges to %s method %s.%s",
                            localAccessLevel, className, methd);
                    }
                    privilegedMethods.put(methd, privilizer().generateName(name));
                }
                return super.visitAnnotation(desc, visible);
            }

            @Override
            public void visitCode() {
                super.visitCode();
                if (!privilegedMethods.containsKey(methd)) {
                    return;
                }
                final String impl = privilegedMethods.get(methd);
                final boolean instanceMethod = !Modifier.isStatic(access);

                if (policy.isConditional()) {
                    privilizer().env.debug("setting up conditional execution due to policy %s", policy);
                    // test, loading boolean
                    if (policy == Policy.ON_INIT) {
                        getStatic(target, privilizer().generateName("hasSecurityManager"), Type.BOOLEAN_TYPE);
                    } else if (policy == Policy.DYNAMIC) {
                        checkSecurityManager(this);
                    }
                    final Label doPrivileged = new Label();

                    // if true, goto doPrivileged:
                    ifZCmp(NE, doPrivileged);

                    final Method implMethod = new Method(impl, desc);
                    if (instanceMethod) {
                        loadThis();
                        loadArgs();
                        invokeVirtual(target, implMethod);
                    } else {
                        loadArgs();
                        invokeStatic(target, implMethod);
                    }
                    returnValue();
                    mark(doPrivileged);
                } else {
                    privilizer().env.debug("setting up unconditional privileged execution due to policy %s", policy);
                }

                // generate action:
                final Type[] ctorArgs;
                if (instanceMethod) {
                    ctorArgs = ArrayUtils.add(methd.getArgumentTypes(), 0, target);
                } else {
                    ctorArgs = methd.getArgumentTypes();
                }
                final Type actionType = new ActionGenerator(access, methd, exceptions, PrivilizingVisitor.this).build();
                newInstance(actionType);
                dup();
                if (instanceMethod) {
                    loadThis();
                }
                loadArgs();
                invokeConstructor(actionType, new Method("<init>", Type.VOID_TYPE, ctorArgs));

                final boolean exc = ArrayUtils.isNotEmpty(exceptions);
                // mark try if needed
                final Label privTry = exc ? mark() : null;

                // execute action
                final Type arg =
                    exc ? Type.getType(PrivilegedExceptionAction.class) : Type.getType(PrivilegedAction.class);
                final Method doPrivileged = new Method("doPrivileged", Type.getType(Object.class), new Type[] { arg });
                invokeStatic(Type.getType(AccessController.class), doPrivileged);

                unbox(methd.getReturnType());
                returnValue();

                if (exc) {
                    final Type caught = Type.getType(PrivilegedActionException.class);
                    // end try
                    final Label privCatch = mark();
                    // catch
                    catchException(privTry, privCatch, caught);
                    // unwrap
                    invokeVirtual(caught, new Method("getException", Type.getType(Exception.class),
                        Privilizer.EMPTY_TYPE_ARRAY));
                    // throw
                    throwException();
                }

                // end original method
                endMethod();

                // substitute an impl visitor and continue
                mv = cv.visitMethod(AccessLevel.PRIVATE.merge(access), impl, desc, signature, exceptions);
                mv.visitCode();
            }
        };

    }

    @Override
    public void visitEnd() {
        annotate();
        if (privilizer().policy == Policy.ON_INIT) {
            final String fieldName = privilizer().generateName("hasSecurityManager");

            visitField(Opcodes.ACC_PRIVATE + Opcodes.ACC_STATIC + Opcodes.ACC_FINAL, fieldName,
                Type.BOOLEAN_TYPE.getDescriptor(), null, null).visitEnd();

            final GeneratorAdapter mgen =
                new GeneratorAdapter(Opcodes.ACC_STATIC, new Method("<clinit>", "()V"), null,
                    Privilizer.EMPTY_TYPE_ARRAY, this);
            checkSecurityManager(mgen);
            mgen.putStatic(target, fieldName, Type.BOOLEAN_TYPE);
            mgen.returnValue();
            mgen.endMethod();
        }
        super.visitEnd();
    }

    /**
     * Generates the instructions to push onto the stack whether there is a
     * security manager available.
     * @param mgen to control
     */
    private static void checkSecurityManager(final GeneratorAdapter mgen) {
        final Label setFalse = new Label();
        final Label done = new Label();
        mgen.invokeStatic(Type.getType(System.class),
            new Method("getSecurityManager", Type.getType(SecurityManager.class), Privilizer.EMPTY_TYPE_ARRAY));
        mgen.ifNull(setFalse);
        mgen.push(true);
        mgen.goTo(done);
        mgen.mark(setFalse);
        mgen.push(false);
        mgen.mark(done);
    }
}
TOP

Related Classes of org.apache.commons.weaver.privilizer.PrivilizingVisitor

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.