Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
openanolis
dragonwell8_jdk
提交
cec0509b
D
dragonwell8_jdk
项目概览
openanolis
/
dragonwell8_jdk
通知
4
Star
2
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
D
dragonwell8_jdk
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
提交
cec0509b
编写于
9月 28, 2010
作者:
S
skoppar
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
6559775: Race allows defaultReadObject to be invoked instead of readFields during deserialization
Reviewed-by: hawtin
上级
652c6717
变更
8
隐藏空白更改
内联
并排
Showing
8 changed file
with
310 addition
and
62 deletion
+310
-62
make/java/java/FILES_java.gmk
make/java/java/FILES_java.gmk
+1
-0
src/share/classes/java/io/ObjectInputStream.java
src/share/classes/java/io/ObjectInputStream.java
+5
-43
src/share/classes/java/io/ObjectOutputStream.java
src/share/classes/java/io/ObjectOutputStream.java
+21
-19
src/share/classes/java/io/SerialCallbackContext.java
src/share/classes/java/io/SerialCallbackContext.java
+58
-0
test/java/io/Serializable/6559775/README
test/java/io/Serializable/6559775/README
+29
-0
test/java/io/Serializable/6559775/SerialRace.java
test/java/io/Serializable/6559775/SerialRace.java
+86
-0
test/java/io/Serializable/6559775/SerialVictim.java
test/java/io/Serializable/6559775/SerialVictim.java
+31
-0
test/java/io/Serializable/6559775/Test6559775.sh
test/java/io/Serializable/6559775/Test6559775.sh
+79
-0
未找到文件。
make/java/java/FILES_java.gmk
浏览文件 @
cec0509b
...
...
@@ -400,6 +400,7 @@ JAVA_JAVA_java = \
java/io/FilePermission.java \
java/io/Serializable.java \
java/io/Externalizable.java \
java/io/SerialCallbackContext.java \
java/io/Bits.java \
java/io/ObjectInput.java \
java/io/ObjectInputStream.java \
...
...
src/share/classes/java/io/ObjectInputStream.java
浏览文件 @
cec0509b
/*
* Copyright (c) 1996, 20
08
, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1996, 20
10
, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
...
...
@@ -265,7 +265,7 @@ public class ObjectInputStream
* object currently being deserialized and descriptor for current class.
* Null when not during readObject upcall.
*/
private
CallbackContext
curContext
;
private
Serial
CallbackContext
curContext
;
/**
* Creates an ObjectInputStream that reads from the specified InputStream.
...
...
@@ -1798,7 +1798,7 @@ public class ObjectInputStream
private
void
readExternalData
(
Externalizable
obj
,
ObjectStreamClass
desc
)
throws
IOException
{
CallbackContext
oldContext
=
curContext
;
Serial
CallbackContext
oldContext
=
curContext
;
curContext
=
null
;
try
{
boolean
blocked
=
desc
.
hasBlockExternalData
();
...
...
@@ -1857,10 +1857,10 @@ public class ObjectInputStream
slotDesc
.
hasReadObjectMethod
()
&&
handles
.
lookupException
(
passHandle
)
==
null
)
{
CallbackContext
oldContext
=
curContext
;
Serial
CallbackContext
oldContext
=
curContext
;
try
{
curContext
=
new
CallbackContext
(
obj
,
slotDesc
);
curContext
=
new
Serial
CallbackContext
(
obj
,
slotDesc
);
bin
.
setBlockDataMode
(
true
);
slotDesc
.
invokeReadObject
(
obj
,
this
);
...
...
@@ -3505,42 +3505,4 @@ public class ObjectInputStream
}
}
/**
* Context that during upcalls to class-defined readObject methods; holds
* object currently being deserialized and descriptor for current class.
* This context keeps a boolean state to indicate that defaultReadObject
* or readFields has already been invoked with this context or the class's
* readObject method has returned; if true, the getObj method throws
* NotActiveException.
*/
private
static
class
CallbackContext
{
private
final
Object
obj
;
private
final
ObjectStreamClass
desc
;
private
final
AtomicBoolean
used
=
new
AtomicBoolean
();
public
CallbackContext
(
Object
obj
,
ObjectStreamClass
desc
)
{
this
.
obj
=
obj
;
this
.
desc
=
desc
;
}
public
Object
getObj
()
throws
NotActiveException
{
checkAndSetUsed
();
return
obj
;
}
public
ObjectStreamClass
getDesc
()
{
return
desc
;
}
private
void
checkAndSetUsed
()
throws
NotActiveException
{
if
(!
used
.
compareAndSet
(
false
,
true
))
{
throw
new
NotActiveException
(
"not in readObject invocation or fields already read"
);
}
}
public
void
setUsed
()
{
used
.
set
(
true
);
}
}
}
src/share/classes/java/io/ObjectOutputStream.java
浏览文件 @
cec0509b
/*
* Copyright (c) 1996, 20
06
, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1996, 20
10
, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
...
...
@@ -35,6 +35,7 @@ import java.util.List;
import
java.util.concurrent.ConcurrentHashMap
;
import
java.util.concurrent.ConcurrentMap
;
import
static
java
.
io
.
ObjectStreamClass
.
processQueue
;
import
java.io.SerialCallbackContext
;
/**
* An ObjectOutputStream writes primitive data types and graphs of Java objects
...
...
@@ -191,10 +192,12 @@ public class ObjectOutputStream
private
boolean
enableReplace
;
// values below valid only during upcalls to writeObject()/writeExternal()
/** object currently being serialized */
private
Object
curObj
;
/** descriptor for current class (null if in writeExternal()) */
private
ObjectStreamClass
curDesc
;
/**
* Context during upcalls to class-defined writeObject methods; holds
* object currently being serialized and descriptor for current class.
* Null when not during writeObject upcall.
*/
private
SerialCallbackContext
curContext
;
/** current PutField object */
private
PutFieldImpl
curPut
;
...
...
@@ -426,9 +429,11 @@ public class ObjectOutputStream
* <code>OutputStream</code>
*/
public
void
defaultWriteObject
()
throws
IOException
{
if
(
curObj
==
null
||
curDesc
==
null
)
{
if
(
curContext
==
null
)
{
throw
new
NotActiveException
(
"not in call to writeObject"
);
}
Object
curObj
=
curContext
.
getObj
();
ObjectStreamClass
curDesc
=
curContext
.
getDesc
();
bout
.
setBlockDataMode
(
false
);
defaultWriteFields
(
curObj
,
curDesc
);
bout
.
setBlockDataMode
(
true
);
...
...
@@ -446,9 +451,11 @@ public class ObjectOutputStream
*/
public
ObjectOutputStream
.
PutField
putFields
()
throws
IOException
{
if
(
curPut
==
null
)
{
if
(
cur
Obj
==
null
||
curDesc
==
null
)
{
if
(
cur
Context
==
null
)
{
throw
new
NotActiveException
(
"not in call to writeObject"
);
}
Object
curObj
=
curContext
.
getObj
();
ObjectStreamClass
curDesc
=
curContext
.
getDesc
();
curPut
=
new
PutFieldImpl
(
curDesc
);
}
return
curPut
;
...
...
@@ -1420,17 +1427,15 @@ public class ObjectOutputStream
* writeExternal() method.
*/
private
void
writeExternalData
(
Externalizable
obj
)
throws
IOException
{
Object
oldObj
=
curObj
;
ObjectStreamClass
oldDesc
=
curDesc
;
PutFieldImpl
oldPut
=
curPut
;
curObj
=
obj
;
curDesc
=
null
;
curPut
=
null
;
if
(
extendedDebugInfo
)
{
debugInfoStack
.
push
(
"writeExternal data"
);
}
SerialCallbackContext
oldContext
=
curContext
;
try
{
curContext
=
null
;
if
(
protocol
==
PROTOCOL_VERSION_1
)
{
obj
.
writeExternal
(
this
);
}
else
{
...
...
@@ -1440,13 +1445,12 @@ public class ObjectOutputStream
bout
.
writeByte
(
TC_ENDBLOCKDATA
);
}
}
finally
{
curContext
=
oldContext
;
if
(
extendedDebugInfo
)
{
debugInfoStack
.
pop
();
}
}
curObj
=
oldObj
;
curDesc
=
oldDesc
;
curPut
=
oldPut
;
}
...
...
@@ -1461,12 +1465,9 @@ public class ObjectOutputStream
for
(
int
i
=
0
;
i
<
slots
.
length
;
i
++)
{
ObjectStreamClass
slotDesc
=
slots
[
i
].
desc
;
if
(
slotDesc
.
hasWriteObjectMethod
())
{
Object
oldObj
=
curObj
;
ObjectStreamClass
oldDesc
=
curDesc
;
PutFieldImpl
oldPut
=
curPut
;
curObj
=
obj
;
curDesc
=
slotDesc
;
curPut
=
null
;
SerialCallbackContext
oldContext
=
curContext
;
if
(
extendedDebugInfo
)
{
debugInfoStack
.
push
(
...
...
@@ -1474,18 +1475,19 @@ public class ObjectOutputStream
slotDesc
.
getName
()
+
"\")"
);
}
try
{
curContext
=
new
SerialCallbackContext
(
obj
,
slotDesc
);
bout
.
setBlockDataMode
(
true
);
slotDesc
.
invokeWriteObject
(
obj
,
this
);
bout
.
setBlockDataMode
(
false
);
bout
.
writeByte
(
TC_ENDBLOCKDATA
);
}
finally
{
curContext
.
setUsed
();
curContext
=
oldContext
;
if
(
extendedDebugInfo
)
{
debugInfoStack
.
pop
();
}
}
curObj
=
oldObj
;
curDesc
=
oldDesc
;
curPut
=
oldPut
;
}
else
{
defaultWriteFields
(
obj
,
slotDesc
);
...
...
src/share/classes/java/io/SerialCallbackContext.java
0 → 100644
浏览文件 @
cec0509b
/*
* %W% %E%
*
* Copyright (c) 2006, 2010 Oracle and/or its affiliates. All rights reserved.
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
*/
package
java.io
;
/**
* Context during upcalls from object stream to class-defined
* readObject/writeObject methods.
* Holds object currently being deserialized and descriptor for current class.
*
* This context keeps track of the thread it was constructed on, and allows
* only a single call of defaultReadObject, readFields, defaultWriteObject
* or writeFields which must be invoked on the same thread before the class's
* readObject/writeObject method has returned.
* If not set to the current thread, the getObj method throws NotActiveException.
*/
final
class
SerialCallbackContext
{
private
final
Object
obj
;
private
final
ObjectStreamClass
desc
;
/**
* Thread this context is in use by.
* As this only works in one thread, we do not need to worry about thread-safety.
*/
private
Thread
thread
;
public
SerialCallbackContext
(
Object
obj
,
ObjectStreamClass
desc
)
{
this
.
obj
=
obj
;
this
.
desc
=
desc
;
this
.
thread
=
Thread
.
currentThread
();
}
public
Object
getObj
()
throws
NotActiveException
{
checkAndSetUsed
();
return
obj
;
}
public
ObjectStreamClass
getDesc
()
{
return
desc
;
}
private
void
checkAndSetUsed
()
throws
NotActiveException
{
if
(
thread
!=
Thread
.
currentThread
())
{
throw
new
NotActiveException
(
"not in readObject invocation or fields already read"
);
}
thread
=
null
;
}
public
void
setUsed
()
{
thread
=
null
;
}
}
test/java/io/Serializable/6559775/README
0 → 100644
浏览文件 @
cec0509b
The testcase works well on dual core machines.
The below output indicates a successful fix:
Exception in thread "Thread-0" java.lang.NullPointerException
at java.io.ObjectInputStream.defaultReadObject(ObjectInputStream.java:476)
at SerialRace$1.run(SerialRace.java:33)
at java.lang.Thread.run(Thread.java:595)
When the vulnerability exists, the output of the tescase is something like this:
Available processors: 2
Iteration 1
java.io.NotActiveException: not in readObject invocation or fields already read
at java.io.ObjectInputStream$CallbackContext.checkAndSetUsed(ObjectInputStream.java:3437)
at java.io.ObjectInputStream$CallbackContext.getObj(ObjectInputStream.java:3427)
at java.io.ObjectInputStream.readFields(ObjectInputStream.java:514)
at SerialVictim.readObject(SerialVictim.java:19)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:585)
at java.io.ObjectStreamClass.invokeReadObject(ObjectStreamClass.java:946)
at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:1809)
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1719)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1305)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:348)
at SerialRace.main(SerialRace.java:65)
Victim: ?
Victim: $
test/java/io/Serializable/6559775/SerialRace.java
0 → 100644
浏览文件 @
cec0509b
/*
* @test %W% %E%
* @bug 6559775
* @summary Race allows defaultReadObject to be invoked instead of readFields during deserialization
* @run shell Test6559775.sh
*/
import
java.io.*
;
public
class
SerialRace
{
public
static
void
main
(
String
[]
args
)
throws
Exception
{
System
.
err
.
println
(
"Available processors: "
+
Runtime
.
getRuntime
().
availableProcessors
()
);
final
int
perStream
=
10000
;
// Construct attack data.
ByteArrayOutputStream
byteOut
=
new
ByteArrayOutputStream
();
{
ObjectOutputStream
out
=
new
ObjectOutputStream
(
byteOut
);
char
[]
value
=
new
char
[]
{
'?'
};
out
.
writeObject
(
value
);
for
(
int
i
=
0
;
i
<
perStream
;
++
i
)
{
SerialVictim
orig
=
new
SerialVictim
(
value
);
out
.
writeObject
(
orig
);
}
out
.
flush
();
}
byte
[]
data
=
byteOut
.
toByteArray
();
ByteArrayInputStream
byteIn
=
new
ByteArrayInputStream
(
data
);
final
ObjectInputStream
in
=
new
ObjectInputStream
(
byteIn
);
final
char
[]
value
=
(
char
[])
in
.
readObject
();
Thread
thread
=
new
Thread
(
new
Runnable
()
{
public
void
run
()
{
for
(;;)
{
try
{
// Attempt to interlope on other thread.
in
.
defaultReadObject
();
// Got it.
// Let other thread reach known state.
Thread
.
sleep
(
1000
);
// This is the reference usually
// read in extended data.
SerialVictim
victim
=
(
SerialVictim
)
in
.
readObject
();
System
.
err
.
println
(
"Victim: "
+
victim
);
value
[
0
]
=
'$'
;
System
.
err
.
println
(
"Victim: "
+
victim
);
return
;
}
catch
(
java
.
io
.
NotActiveException
exc
)
{
// Not ready yet...
}
catch
(
java
.
lang
.
InterruptedException
exc
)
{
throw
new
Error
(
exc
);
}
catch
(
IOException
exc
)
{
throw
new
Error
(
exc
);
}
catch
(
ClassNotFoundException
exc
)
{
throw
new
Error
(
exc
);
}
}
}});
thread
.
start
();
Thread
.
yield
();
// Normal reading from object stream.
// We hope the other thread catches us out between
// setting up the call to SerialVictim.readObject and
// the AtomicBoolean acquisition in readFields.
for
(
int
i
=
0
;
i
<
perStream
;
++
i
)
{
try
{
SerialVictim
victim
=
(
SerialVictim
)
in
.
readObject
();
}
catch
(
Exception
exc
)
{
synchronized
(
System
.
err
)
{
System
.
err
.
println
(
"Iteration "
+
i
);
exc
.
printStackTrace
();
}
// Allow atack thread to do it's business before close.
Thread
.
sleep
(
2000
);
break
;
}
}
// Stop the other thread.
in
.
close
();
}
}
test/java/io/Serializable/6559775/SerialVictim.java
0 → 100644
浏览文件 @
cec0509b
/**
* Instances of this class created through deserialization
* should, in theory, be immutable.
* Instances created through the public constructor
* are only to ease creation of the binary attack data.
*/
public
class
SerialVictim
implements
java
.
io
.
Serializable
{
private
char
[]
value
;
public
SerialVictim
(
char
[]
value
)
{
this
.
value
=
value
;
}
//@Override
public
String
toString
()
{
return
new
String
(
value
);
}
private
void
readObject
(
java
.
io
.
ObjectInputStream
in
)
throws
java
.
io
.
IOException
,
java
.
lang
.
ClassNotFoundException
{
java
.
io
.
ObjectInputStream
.
GetField
fields
=
in
.
readFields
();
// Clone before write should, in theory, make instance safe.
this
.
value
=
(
char
[])((
char
[])
fields
.
get
(
"value"
,
null
)).
clone
();
in
.
readObject
();
}
private
void
writeObject
(
java
.
io
.
ObjectOutputStream
out
)
throws
java
.
io
.
IOException
{
out
.
defaultWriteObject
();
out
.
writeObject
(
this
);
}
}
test/java/io/Serializable/6559775/Test6559775.sh
0 → 100644
浏览文件 @
cec0509b
#!/bin/sh
if
[
"
${
TESTSRC
}
"
=
""
]
then
TESTSRC
=
.
fi
if
[
"
${
TESTJAVA
}
"
=
""
]
then
PARENT
=
`
dirname
\`
which java
\`
`
TESTJAVA
=
`
dirname
${
PARENT
}
`
echo
"TESTJAVA not set, selecting "
${
TESTJAVA
}
echo
"If this is incorrect, try setting the variable manually."
fi
if
[
"
${
TESTCLASSES
}
"
=
""
]
then
echo
"TESTCLASSES not set. Test cannot execute. Failed."
exit
1
fi
BIT_FLAG
=
""
# set platform-dependent variables
OS
=
`
uname
-s
`
case
"
$OS
"
in
SunOS
|
Linux
)
NULL
=
/dev/null
PS
=
":"
FS
=
"/"
## for solaris, linux it's HOME
FILE_LOCATION
=
$HOME
if
[
-f
${
FILE_LOCATION
}${
FS
}
JDK64BIT
-a
${
OS
}
=
"SunOS"
]
then
BIT_FLAG
=
`
cat
${
FILE_LOCATION
}${
FS
}
JDK64BIT |
grep
-v
'^#'
`
fi
;;
Windows_
*
)
NULL
=
NUL
PS
=
";"
FS
=
"
\\
"
;;
*
)
echo
"Unrecognized system!"
exit
1
;
;;
esac
JEMMYPATH
=
${
CPAPPEND
}
CLASSPATH
=
.
${
PS
}${
TESTCLASSES
}${
PS
}${
JEMMYPATH
}
;
export
CLASSPATH
THIS_DIR
=
`
pwd
`
${
TESTJAVA
}${
FS
}
bin
${
FS
}
java
${
BIT_FLAG
}
-version
cp
${
TESTSRC
}${
FS
}*
.java
.
chmod
777
*
.java
${
TESTJAVA
}${
FS
}
bin
${
FS
}
javac SerialRace.java
${
TESTJAVA
}${
FS
}
bin
${
FS
}
java
${
BIT_FLAG
}
SerialRace
>
test.out 2>&1
cat
test.out
STATUS
=
0
egrep
"java.io.NotActiveException|not in readObject invocation or fields already read|^Victim"
test.out
if
[
$?
=
0
]
then
STATUS
=
1
else
grep
"java.lang.NullPointerException"
test.out
if
[
$?
!=
0
]
;
then
STATUS
=
1
fi
fi
exit
$STATUS
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录