📄 bytecoderewriter.java
字号:
logger.debug("Checking bytecode for permission : "+permissionName); if(methodsToCheck!=null && methodsToCheck.size()!=0) //check the bytecode and add security hooks StackPermissionsRespected=stackPerm.checkSipPermissions(methodsToCheck,permissionTag.getName()); } return StackPermissionsRespected; } /** * Add runtime bytecode security hooks to the class * @param method - the original method to modify * @param handles - the handles which allows to know where to add the code * @param cp - the constantPoolGen needed to create any piece of code * @param permissionName - the permission name(URI or Domain or wildcard) to test against at runtime * @param methodTag - the method tag, of the method we want to check, extracted from the permissions.xml file * (needed to configure automatically the bytecode rewriting stuff) * @param argumentChecking - If we have to check a permission before runtime * We don't need to check the arguments of the permission otherwise we need to check them * @return the new Method with our bytecode added */ public MethodGen addSecurityHooks( MethodGen method, InstructionHandle[] handles, ConstantPoolGen cp, String permissionName, MethodTag methodTag, boolean argumentChecking){ int instructionCount=0; //Get the instruction List from the bytecode method InstructionList il = method.getInstructionList(); // Factory to create new instructions InstructionFactory factory = new InstructionFactory(cp); //New InstructionList that will be some of the bytecode added to the service InstructionList newInstructionList = new InstructionList(); //We get the bytecode tag from the method tag to configure //the bytecode rewriting stuff ByteCodeTag byteCodeTag=methodTag.getByteCodeTag(); //Get the arguments of the method to invoke Vector bc_args=byteCodeTag.getArguments(); //Get the vector of arguments of the method we want to check Vector arguments=methodTag.getArguments(); newInstructionList.append(factory.createFieldAccess( mainClass, "__"+byteCodeTag.getClassToInvoke().replace('.','_'), new ObjectType(byteCodeTag.getClassToInvoke()), Constants.GETSTATIC)); //If we have to check a permission before runtime //We just create a Permission of the type needed //and put it in the service's bytecode if(!argumentChecking){ newInstructionList.append(factory.createNew(methodTag.getPermissionName())); newInstructionList.append(InstructionConstants.DUP); newInstructionList.append(new PUSH(cp,methodTag.getPermissionAction())); newInstructionList.append(factory.createInvoke( methodTag.getPermissionName(), "<init>", Type.VOID, new Type[]{new ObjectType("java.lang.String")}, Constants.INVOKESPECIAL)); } else{ //Load the value of the arguments of the method to check InstructionList argsInstructionList=new InstructionList(); InstructionHandle handle=handles[handles.length -1]; //logger.debug(handle.getInstruction().toString()); //For each argument of the permissions.xml file //we check the instruction until we found the following instructions : //ldc(load a string), aload(load the value of an attribute), //getstatic(load a static value either by an attribute or by a method), //sipush(load an integer) //or new(init a new field) but this is a special case //when you do a new : the instructions in the bytecode are //starting with an invokespecial <init> and finishing with a new instruction //so this is why it's a little bit tricky //In theory those are the only instructions that load a value on the stack for(int i=0;i<bc_args.size();i++){ boolean found=false; boolean foundInvokeSpecialInit=false; while(!found){ handle=handle.getPrev(); instructionCount++; Instruction instruction=handle.getInstruction(); //logger.debug(instruction.toString()); if(!foundInvokeSpecialInit){ if(handle.toString().indexOf("ldc")!=-1 || handle.toString().indexOf("aload")!=-1 || handle.toString().indexOf("sipush")!=-1 || handle.toString().indexOf("getstatic")!=-1){ found=true; } if(handle.toString().indexOf("invokespecial")!=-1 && handle.toString().indexOf("<init>")!=-1){ foundInvokeSpecialInit=true; } } else{ if(handle.toString().indexOf("new")!=-1){ found=true; foundInvokeSpecialInit=false; } } //Add the instruction to load the value of the argument //of the method to check on the java Stack argsInstructionList.insert(instruction); } } //Add the List of instructions to load the arguments of the method //to the list of instructions that will be added to the bytecode newInstructionList.append(argsInstructionList); } //Specify the types of the method's arguments //through the ByteCode Tag extracted from the permissions.xml file Type[] args_types=new Type[bc_args.size()]; for(int i=0;i<bc_args.size();i++) args_types[i]=getBCELType(((ByteCodeArgumentTag)bc_args.get(i)).getClassName()); //Create a call to the method which will do the check newInstructionList.append(factory.createInvoke( byteCodeTag.getClassToInvoke(), byteCodeTag.getMethod(), Type.VOID, args_types, org.apache.bcel.Constants.INVOKEVIRTUAL)); //Insert a test to check if the call to the method //is true. If yes, we go out of the method in throwing an AccessControlException //else we continue the normal execution and so we go just at the instuction //loading the first parameter of the method we want to check /*newInstructionList.append(new IFNE(getPreviousInstruction(handles[handles.length -1],arguments.size()))); newInstructionList.append(factory.createNew("java.security.AccessControlException")); newInstructionList.append(InstructionConstants.DUP); newInstructionList.append(new PUSH(cp,"User has not the rigths")); newInstructionList.append(factory.createInvoke( "java.security.AccessControlException", "<init>", Type.VOID, new Type[]{new ObjectType("java.lang.String")}, org.apache.bcel.Constants.INVOKESPECIAL)); newInstructionList.append(new ATHROW());*/ //insert our runtime security check code into the user's service //just before the arguments of the method we want to check are loaded il.insert(getPreviousInstruction(handles[handles.length -1],instructionCount),newInstructionList); return method; } /** * get the BCEL type of the type in parameter * if the type is an Object Type or a basic type(int, float,...) * @param argumentType - the string which stands for the type * @return the BCEL Type */ public static Type getBCELType(String argumentType){ if(argumentType.equals("int")) return Type.INT; if(argumentType.equals("boolean")) return Type.BOOLEAN; if(argumentType.equals("byte")) return Type.BYTE; if(argumentType.equals("char")) return Type.CHAR; if(argumentType.equals("double")) return Type.DOUBLE; if(argumentType.equals("float")) return Type.FLOAT; if(argumentType.equals("long")) return Type.LONG; if(argumentType.equals("short")) return Type.SHORT; return new ObjectType(argumentType); } /** Get the Nth previous instructions of the instruction handle in parameter * @param instructionHandle - he instruction handle of which we want to know the Nth previous instruction * (example : if N=5, we want to know the 5th previous instruction before the instructionhandle * in parameter) * @param N - the number of previous instruction * @return the Nth previous instruction */ public static InstructionHandle getPreviousInstruction(InstructionHandle instructionHandle,int N){ InstructionHandle previousHandle=instructionHandle; for(int i=0; i<N; i++) previousHandle=previousHandle.getPrev(); return previousHandle; } /** * We are looking for piece of code we added in the method addSecurityHooks * the ifne offset will be positioned on the first argument of the method to check * But if added many piece of code they will be all * positioned on the first argument of the method to check * And so only the first check will be made, all the others will be skipped * we want to fix that * @param the original method to modify * @param the handles which allows to know where to add the code * @param the constantPoolGen needed to create a piece of code * @param the permission name(URI or Domain or wildcard) to test against at runtime * @param the method tag, of the method we want to check, extracted from the permissions.xml file * (needed to configure automatically the bytecode rewriting stuff) * @return the new Method with our bytecode added */ /*public org.apache.bcel.classfile.Method checkMultipleCheckOnMethod( MethodGen method, InstructionHandle[] handles, ConstantPoolGen cp, String permissionName, MethodTag methodTag, boolean argumentChecking){ boolean stop=false; int count=0; //Get the vector of arguments of the method we want to check Vector arguments=methodTag.getArguments(); InstructionHandle handle=findFirstArgument(handles[handles.length -1],arguments.size()); InstructionHandle startHandle=handle; //We are looking for piece of code we added //the ifne offset will be positioned on the //first argument of the method to check //But if added many piece of code they will be all //positioned on the first argument of the method to check try{ while(!stop){ handle=handle.getPrev(); count++; //if just before the handle we do not find a athrow instruction //we can stop the process because //there is no or no more piece of code added if(count==1){ if(handle.getInstruction().toString().indexOf("athrow")==-1) stop=true; } //If it's the fifth previous instruction and //if it's not the good one we stop the process if(count==5){ if(handle.getInstruction().toString(cp.getConstantPool()).indexOf("new java/security/AccessControlException")==-1) stop=true; } //If it's the sixth previous instruction and //if it's the ifne instruction we affect the new offset target //to the start handle
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -