JEP415: FilterInThread Example

Roger Riggs roger.riggs at oracle.com
Mon Feb 6 14:48:34 UTC 2023


Thanks, I'd planned to file a bug too.

If you think of any improvements, let me know.

On 2/6/23 8:26 AM, Dr Heinz M. Kabutz wrote:
>
> FWIW, I've also submitted this as a bug report:
>
> https://bugs.java.com/bugdatabase/view_bug.do?bug_id=JDK-8301863
>
>
> Regards
>
> Heinz
> -- 
> Dr Heinz M. Kabutz (PhD CompSci)
> Author of "The Java™ Specialists' Newsletter" -www.javaspecialists.eu
> Java Champion -www.javachampions.org
> JavaOne Rock Star Speaker
> Tel: +30 69 75 595 262
> Skype: kabutz
> On 2023/02/06 06:55, Roger Riggs wrote:
>> Hi Heinz,
>>
>> Indeed, this example is not intuitive and does not do what was 
>> intended and could use a better explanation.
>>
>> The interaction of three filters gets complicated and their 
>> combination depends on the ordering and intention of each filter and 
>> the particular filter factory goal. The FilterInThread example 
>> provides only one of many possible functions.
>>
>> The FilterInThread example uses the JVM-wide filter, thread filter, 
>> and stream filter for different purposes.
>>
>> The JVM-wide filter has a particular role in that it can be set on 
>> the command line via a system property.
>> It is typically used as a backstop after the application is deployed 
>> to patch in additional rejection of classes.
>> The property value syntax allows for either allowing or rejecting 
>> classes, and an otherwise unmentioned class is left UNDECIDED, 
>> possibly with some risk exposure.
>>
>> The thread filter is used to more focus de-serialization on a group 
>> of classes, either to narrow it or expand it.
>>
>> The FilterInThread example takes the position that any UNDECIDED in 
>> the thread's filter and the JVM-wide filter should be rejected even 
>> if the pattern does not explicitly do so.  This keeps an oversight in 
>> filter construction from becoming a risk.
>>
>> The stream filter is included mostly for backward compatibility, 
>> introduced in JDK 9 via JEP 290. The stream filter is set by the code 
>> creating the ObjectInputStream and part of its design and purpose. In 
>> the FilterInThread example, if it returns UNDECIDED, the result is 
>> determined by a merge of the other two filters and further rejecting 
>> UNDECIDED.
>>
>> The bug in the example, that individually rejects UNDECIDED in the 
>> JVM-wide and thread filters respectively, should instead reject only 
>> if both return UNDECIDED.
>>
>> The revised example is:
>>
>> *// Returns a composite filter of the static JVM-wide filter, a 
>> thread-specific filter, *// and the stream-specific filter. *public 
>> ObjectInputFilter apply(ObjectInputFilter curr, ObjectInputFilter 
>> next) { *if (curr == null) { *// Called from the OIS constructor or 
>> perhaps OIS.setObjectInputFilter with no current filter *var filter = 
>> filterThreadLocal.get(); *if (filter != null) { *// Merge to invoke 
>> the thread local filter and then the JVM-wide filter (if any) *filter 
>> = ObjectInputFilter.merge(filter, next); *return 
>> ObjectInputFilter.rejectUndecidedClass(filter); *} *return (next == 
>> null) ? null : ObjectInputFilter.rejectUndecidedClass(next); *} else 
>> { *// Called from OIS.setObjectInputFilter with a current filter and 
>> a stream-specific filter. *// The curr filter already incorporates 
>> the thread filter and static JVM-wide filter *// and rejection of 
>> undecided classes *// If there is a stream-specific filter merge to 
>> invoke it and then the current filter. *if (next != null) { *return 
>> ObjectInputFilter.merge(next, curr); *} *return curr; *} *}
>>
>> The filters are evaluated as:
>> merge(restrictLargeArrays,rejectUndecidedClass(merge(allowInteger,allowArrayList)))
>>
>> The first call to the factory returns a filter:  `var f1 = 
>> rejectUndecidedClass(merge(allowInteger,allowArrayList))`
>> The second call to the factory returns filter: `var f2 = 
>> merge(restrictLargeArrays, f1)`
>>
>> The filters are evaluated in order, until an accept or reject is 
>> returned:
>>   1) restrictLargeArrays  (stream)
>>   2) allowInteger            (thread filter)
>>   3) allowArrayList         (JVM-wide filter)
>>
>> This has the same value as your ideal but without an extra 
>> RejectUndecidedClass.
>>
>> Note that in this composition, the choice by a filter to accept or 
>> reject can not be overridden by a subsequent filter.
>>
>> Thank you for the comments and suggestions, Roger
>>
>> On 2/3/23 1:20 PM, Dr Heinz M. Kabutz wrote:
>>> I was trying to get my head around the FilterInThread example in JEP 
>>> 415 (https://openjdk.org/jeps/415) and the JavaDoc for the 
>>> ObjectInputFilter 
>>> (https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/io/ObjectInputFilter.html)
>>>
>>> For example, let's assume we have three filters. The first allow 
>>> ArrayList, the second allows Integer, the third restricts arrays to 
>>> not be larger than 1000.
>>>
>>>     ObjectInputFilter allowArrayList = ObjectInputFilter.allowFilter(
>>>             Set.of(ArrayList.class, Object.class)::contains, UNDECIDED
>>>     );
>>>     ObjectInputFilter allowInteger = ObjectInputFilter.allowFilter(
>>>             Set.of(Number.class, Integer.class)::contains, UNDECIDED
>>>     );
>>>     ObjectInputFilter restrictLargeArrays =
>>> ObjectInputFilter.Config.createFilter("maxarray=1000");
>>>
>>> Let's say that we create a FilterInThread instance and install that 
>>> as our factory. Furthermore, we set the allowArrayList as the global 
>>> serial filter. When we call filterInThread.doWithSerialFilter() we 
>>> pass in the allowInteger filter. Lastly, during the actual 
>>> deserialization, we call setObjectInputFilter() on the 
>>> ObjectInputStream with the restrictLargeArrays filter. Ideally, I 
>>> would want the final filter to look like this:
>>>
>>> rejectUndecidedClass(merge(restrictLargeArrays,merge(allowInteger,allowArrayList))) 
>>>
>>>
>>> However, in the FilterInThread example, we add the 
>>> rejectUndecidedClass() wrapper around each of the steps. Thus we 
>>> would get something like:
>>>
>>> rejectUndecidedClass(merge(restrictLargeArrays,rejectUndecidedClass(merge(allowInteger,rejectUndecidedClass(allowArrayList))))) 
>>>
>>>
>>> Thus we could never allow any classes except for ArrayList.
>>>
>>>
>>> Regards
>>>
>>> Heinz
>>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/core-libs-dev/attachments/20230206/c6b2e3a4/attachment-0001.htm>


More information about the core-libs-dev mailing list