2013-12-11 9 views
9

Şu anda güvenilir kodun güvenilmeyen kodla birlikte çalıştırılması gereken küçük bir Java uygulaması geliştirmeye çalışıyorum. Bunu başarmak için, SecurityException s özelliğine izin verilen bir özel SecurityManager yükledim.Özel GüvenlikManager'ım neden Constructor.newInstance ile bir nesne oluşturduğumda 16. kez istisnalara neden oluyor?

Güvenilmeyen ve güvenilmeyen kod arasında bir köprü olarak, güvenilmeyen bir nesnenin nesnesini başlatmak için Constructor.newInstance() kullanan bir iş parçacığım var. Bu çağrıyı yaptığı sırada güvenlik yöneticisi her şeyi engellemek üzere yapılandırıldı. İlginç bir şekilde, Constructor.newInstance() kullanarak nesneler oluşturmaya çalıştığım ilk 15 kez, her şey iyi çalışıyor, ancak 16 kez SecurityException aldım.

Ben basit bir test programına bu aşağı almak başardınız:

import java.lang.reflect.*; 
import java.security.*; 

public class Main { 
    /* Track how many instances have been created so that we can see when the exception 
    * is thrown. 
    */ 
    private static int numInstances = 0; 
    public Main() { 
     System.out.println("Number created: " + ++numInstances); 
    } 

    public static void main(String[] args) { 
     /* Get the constructor for Main so that we can instantiate everything 
     * later on. 
     */ 
     Constructor<Main> ctor; 
     try { 
      ctor = Main.class.getConstructor(); 
     } catch (NoSuchMethodException e) { 
      e.printStackTrace(); 
      return; 
     } 

     /* Install a super prohibitive security manager that disallows all operations. */ 
     System.setSecurityManager(new SecurityManager() { 
      @Override 
      public void checkPermission(Permission p) { 
       /* Nothing is allowed - any permission check causes a  security 
       * exception. 
       */ 
       throw new SecurityException("Not permitted: " + p); 
      } 
     }); 

     /* Continuously create new Main objects. */ 
     try { 
      while (true) { 
       ctor.newInstance(); 
      } 
     } catch (Exception e) { 
      e.printStackTrace(); 
      return; 
     } 
    } 
} 

Bu program, checkPermission bağımsız olarak her zaman isteneni izni bir hata atan SecurityManager yükler. Daha sonra bir döngüde oturur ve bugüne kadar üretilen örneklerin sayısını yazdırmaya yarayan zararsız bir Main nesnesini başlatmak için ctor.newInstance() kullanır. aşağıdaki gibi bu programın çıktısı, benim sistemde, geçerli:

Bu hibe son derece tehlikeli bir izindir:

Number created: 1 
Number created: 2 
Number created: 3 
Number created: 4 
Number created: 5 
Number created: 6 
Number created: 7 
Number created: 8 
Number created: 9 
Number created: 10 
Number created: 11 
Number created: 12 
Number created: 13 
Number created: 14 
Number created: 15 
java.lang.SecurityException: Not permitted: ("java.lang.RuntimePermission" "createClassLoader") 
    at Main$1.checkPermission(Main.java:32) 
    at java.lang.SecurityManager.checkCreateClassLoader(SecurityManager.java:611) 
    at java.lang.ClassLoader.checkCreateClassLoader(ClassLoader.java:274) 
    at java.lang.ClassLoader.<init>(ClassLoader.java:316) 
    at sun.reflect.DelegatingClassLoader.<init>(ClassDefiner.java:72) 
    at sun.reflect.ClassDefiner$1.run(ClassDefiner.java:60) 
    at sun.reflect.ClassDefiner$1.run(ClassDefiner.java:58) 
    at java.security.AccessController.doPrivileged(Native Method) 
    at sun.reflect.ClassDefiner.defineClass(ClassDefiner.java:57) 
    at sun.reflect.MethodAccessorGenerator$1.run(MethodAccessorGenerator.java:399) 
    at sun.reflect.MethodAccessorGenerator$1.run(MethodAccessorGenerator.java:396) 
    at java.security.AccessController.doPrivileged(Native Method) 
    at sun.reflect.MethodAccessorGenerator.generate(MethodAccessorGenerator.java:395) 
    at sun.reflect.MethodAccessorGenerator.generateConstructor(MethodAccessorGenerator.java:94) 
    at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:48) 
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45) 
    at java.lang.reflect.Constructor.newInstance(Constructor.java:526) 
    at Main.main(Main.java:39) 

the Javadoc for RuntimePermission göre, createClassLoader izni vermek için riskli bir tanesidir. Kendi sınıf yükleyicilerini başlatabilecek kötü niyetli uygulamalar, kendi haydut sınıflarını sisteme yükleyebilir. Bu yeni yüklenen sınıflar, sınıf yükleyici tarafından herhangi bir koruma alanına yerleştirilebilir, böylece sınıflar otomatik olarak o alan için izinleri verir.

  1. özellikle bu hataya neden olduğunu Ne:

iki soru var? Neden 16'ncı saatte bir sınıf yükleyicisi için istek aldım? Bunun, nesnenin doğrudan örneğini oluşturmak için bayt kodu oluşturarak yansımayı optimize etmeye çalışan Java ile ilgili olması gerektiğinden şüpheleniyorum, fakat emin değilim.

  • Tehlikeli olan createClassLoader ayrıcalığını beyaz listeye almaksızın güvenilmeyen koddan güvenilmeyen nesneleri başlatmanın bir yolu var mı? Temel olarak bu yanlış yola yaklaşıyor muyum?

  • Teşekkürler!

    +0

    Kodunuzu aynı davranışta denedim. Throw özel durumunu kaldırırsanız ve bir print ifadesi eklerseniz, 16 örneğini oluşturmadan önce 'checkPermission '3 kez çağrılır. –

    cevap

    11

    Kontrol dışarı this at GrepCode:

    47 if (++numInvocations > ReflectionFactory. inflationThreshold()) {
    48 ConstructorAccessorImpl acc = (ConstructorAccessorImpl)
    49 newMethodAccessorGenerator().
    50 generateConstructor (c. getDeclaringClass(),
    51 c. getParameterTypes(),
    52 c. getExceptionTypes(),
    53 c. getModifiers());
    54 parent. setDelegate (acc);

    Ve o belirli:

    72 privatestaticint  inflationThreshold = 15;

    15 enflasyon eşiği, daha agresif bir optimizasyon NativeConstructorAccessorImpl eklenmeden önce yansıtıcı aramaların sayısı için varsayılan değerdir kod, yeni bir sınıf yükleyicinin başlatılmasına neden olur, bu da 16. yinelemede istisnayla sonuçlanır.Hala hangi vermek, dikkatle kodu için bir koruma alanını oluşturan seçeneğine sahip anlamına izni verilmesine gelince

    387 // Load class
    388 vec. trim();
    389 finalbyte[] bytes = vec. getData();
    390 // Note: the class loader is the only thing that really matters
    391 // here -- it's important to get the generated code into the
    392 // same namespace as the target class. Since the generated code
    393 // is privileged anyway, the protection domain probably doesn't
    394 // matter.
    395 return AccessController. doPrivileged (
    396 newPrivilegedAction < MagicAccessorImpl >() {
    397 publicMagicAccessorImpl run() {
    398 try {
    399 return (MagicAccessorImpl)
    400 ClassDefiner. defineClass
    401 (generatedName,
    402 bytes,
    403 0,
    404 bytes.length,
    405 declaringClass. getClassLoader()). newInstance();
    406 } catch (InstantiationException e) {
    407 throw (InternalError)
    408 newInternalError(). initCause (e);
    409 } catch (IllegalAccessException e) {
    410 throw (InternalError)
    411 newInternalError(). initCause (e);
    412 }
    413 }
    414 });

    : Bytecode nesil MethodAccessorGenerator sınıfında olur ve bu en ilginç bit Yabancı kodlara izin vermeden izin.

    +0

    Dedektif Marko Topolnik, davada! –

    +0

    Muhtemelen direnmiş olabilir bir günaha :) –

    +0

    Bu harika. Koruma alanlarını öğreniyorum ve bu aptalca bir soru olmasından dolayı özür dilerim, ancak güvenilen kodumun newInstance çağrısı için kullanılmasına izin verirken güvenilmeyen kodun sınıf yükleyicilerini kullanmasını önlemek için etki alanını nasıl yapılandırabilirim? Ya da her şeyi, sınıf yükleyici ayrıcalıklarının iptal edildiği bir koruma alanına yerleştirmek iç uygulamanın inflamasyona uğramayacağına neden olur mu? – templatetypedef

    İlgili konular