2018-06-23

classloader的一些问题

前段时间写个东西遇到个情况.

大致是java中,class A extends B的话.
原则上来说A isinstanceosf B应该是返回true的.
类似的isassinablefrom应该也是返回true的.

而实际上的结果却是不预期.

这是个比较有趣的设计.

因为在jvm的实现当中,class的namespace其实是以classloader和class name共同定义的.
类似与一个classloader::class_name的定义.

实现上是klass的lookup是在symboltable的dictionary中通过hash(class_name) & classloader_data定位的.

所以这里实际上是隐式的classloader的naming isolation问题.

从隔离角度来说,这么做也不算难理解.

而且在这种情况下来说,是可以做一些比较tricky的保护机制的.
比如一些受限的class的访问.

在classloader的隔离机制下,即使能够想办法初始化出一些forbidden的类.
然后在调用的时候还是可以通过类型检查拒绝掉一部分的.

但是这样就带来一个问题.

从语义上来说,A extends B是不带有这种隔离信息暗示的.
当A B由不同的classloader定义,或者是不同的classloader环境的时候,类型系统就比较混乱了.

因为字面上的qualified name并没有完全reveal出namespace的区别.

这样的话,在写程序的时候就有比较大的心智负担.
尤其当涉及不同的classloader的instane之间做交互的时候.

而这里又有另外一个诡异的情况.

考虑来自不同classloader的A和B,且名义上A extends B.

那么,如果做cast肯定是有问题的.

但是如果做method invoke/function call的时候,又可能是没问题的.
因为在运行时或者说bytecode层面是没有type check的.

而如果这两个不同classloader的关于B的bytecode是兼容的,或者说涉及到的signature是相同的话,是没问题的.
因为算出来的dispatch table/offset是一致的.

但是如果是不兼容的,自然就又会导致运行时错误.

而顺着这个思路,对于一些restrict的环境,如果能够构造跟protected的class兼容的dispatch table的话.
理论上来说就是绕过这些限制.

比如一些加密场景.
即使密钥是安全可靠的话,也可能可以通过替换的方式绕过校验.

尤其对于校验接口是传入non primitive类型的情况.
因为这种情况下,instance的method invoke也不算是reliable的.

反过来说,如果能够完全控制某些上下游的所有涉及instance的classloader情况的话.
那至少从语法/语义层面上不存在明显的漏洞.

但这是一个相对难覆盖的问题.

因为如果能够约束class以及其所属的classloader的情况的话,也就意味这runtime是一种可追踪的情况.
如若不是的话,则无法保证某个时间点不回存在classloader泄露/逃逸的情况.
所以,在这种情况下,其实本身就已经是又一个sandbox机制去保证audit了.

有没有classloader其实关系不大.

那么为什么要设计这么一种问题比较明显的机制呢?

一种可能就是为了保证builtin class的integrity.
毕竟有个bootstrap/system classloader.

但不提供这个机制的话,也并不是不能保证完整性.

因为问题的关键不是谁load,而是load的是什么.

核心是是什么怎么定义.

类似go的method receiver和protocol的定义就比较好.

实际上就是脱离了类型这种比较古板的定义.
而是通过具有什么行为来定义区别同类.

实际上,抛开类型检查的语法和一些编译期的检查之外,运行时也基本上就是这么做的.

如果去掉这种类型系统的话,代价就是类似动态类型语言,缺少编译期的约束提醒.
以及可能对java生态更重要的类型系统的可追溯性.

这个是很多IDE和工具链所依赖的.

而如果去掉classloader的绑定的话,又为一些malicious的应用提供了一些方便.

或者从纯粹语言的角度来说,这就意味着名义上同一类型的instance,可能有着不同的行为.

而如果从contract的层面去约束class定义的话,那就意味着对于同名的class具有不同行为的场景予以拒绝.

所以,允许这种怪异行为的原因是为了使这种场景合理化么?

大概是类似于jsp这种需要code hot reload的场景.

于是一个可能比较安全的做法就是尽量去做类型的cast和从属关系判断.

非要这么做的话,可能就是需要自己做字面的递归回溯比较了.

这样至少是遵从字面语意的.

没有评论:

发表评论

爽文

去看了好东西. 坦白说,多少是带着点挑刺的味道去的. 毕竟打着爱情神话和女性题材的气质,多多少少是热度为先了. 看完之后倒是有些新的想法. 某种程度上来说,现在的年轻人或者说声音就像小叶. 只要说点贴心的话就能哄好. 也是那种可以不用很努力了. 留在自己的舒适区避难所小圈子抱团就...