Today my headline sounds a bit like “Little Red Riding Hood and the Big Bad Wolf” – but there is a reason why I’d like to write about about OJVM and the Mitigation Patch – Things to know in 2020. We are working with a customer right now where preupgrade.jar gave a warning about the existence of the Mitigation patch in an 11.2.0.4 home – despite the fact that JAVAVM is not configured in this database. And this looked strange to us.

Photo by Šárka Jonášová on Unsplash
Mitigation Patch?
A quick search on my blog shows me that I wrote about the Mitigation Patch a while ago:
If you don’t want to read my post from September 2016, no worries. I summarize the details in brief:
- The Mitigation Patch allows you to disable (and enable) the Java subsystem
- It can be used where you have JAVAVM, don’t use it but can’t deinstall it
- This MOS Note:1929745.1 – Oracle JavaVM Component Database Patches gives you an overview about:
- What is the Mitigation Patch?
- Using the Mitigation Patch
- And it has two important details:
- “[..] has been reviewed each cycle from January 2015 through January 2017 [..]“
- “[..] Note: Patch 19721304 is now included in the following 12.1.0.2 and 11.2.0.4 patches and therefore, in the following steps, Step 1 should be skipped (otherwise OPatch will report Patch 19721304 as a Conflict/Subset):
- Database Patch Set Update
- [..]”
So at first, it is not 100% clear if the mitigation patch is still supported in 2020. And second, it is not obvious (at least to me) whether it gets delivered with a PSU for Oracle 11.2.0.4 in 2020, or not. It reads to me as if this is the case.
And this is the situation I’d like to examine.
Is the Mitigation Patch part of my PSU?
In my Oracle 11.2.0.4 environment I use the January 2020 PSU. In Oracle 11.2.0.4 there is no choice unless you have an Exadata. Otherwise I would use BPs and RUs.
Check:
$ORACLE_HOME/OPatch/opatch lsinventory > file.txt
And when I search for the patch number, 19721304, I get this result in the output:

Contents of 11.2.0.4 January 2020 PSU
The patch binary is installed.
Important: If you have a PSU or BP newer than late 2017, the Mitigation Patch should be included already. Hence, there is no need to install it separately.
Install the Mitigation Patch
Wait – didn’t I write there is no need to install it? When we speak about binaries, this is correct. But you need to install it in the database. And this important information is not included in MOS Note:1929745.1 – Oracle JavaVM Component Database Patches. But I mentioned this in my Part III: The Mitigation Patch blog post from 2016:
-
@?/rdbms/admin/dbmsjdev.sql
If you don’t run this script, you can’t execute the call do disable the Java subsystem:
-
exec dbms_java_dev.disable
If you didn’t run the above script, you will receive:
SQL> exec dbms_java_dev.disable BEGIN dbms_java_dev.disable; END; * ERROR at line 1: ORA-06550: line 1, column 7: PLS-00201: identifier 'DBMS_JAVA_DEV.DISABLE' must be declared ORA-06550: line 1, column 7: PL/SQL: Statement ignored
If you ran the above script, the above exec command will succeed – partially.
I run it in a database where I have no JAVAVM installed. And the script completes – see below.
dbmsjdev.sql Execution
Running dbmsjdev.sql
in my database with no JAVAVM gives the following output – and this is the reason why I copy the entire output here:
SQL> @?/rdbms/admin/dbmsjdev.sql
SQL> SET FEEDBACK 1
SQL> SET NUMWIDTH 10
SQL> SET LINESIZE 80
SQL> SET TRIMSPOOL ON
SQL> SET TAB OFF
SQL> SET PAGESIZE 100
SQL>
SQL> declare
2 role_exists exception;
3 pragma exception_init(role_exists, -1921);
4 begin
5 execute immediate 'create role oracle_java_dev';
6 exception
7 when role_exists then
8 null;
9 end;
10 /
PL/SQL procedure successfully completed.
SQL>
SQL> create or replace trigger sys.dbms_java_dev_trg before create
2 on database disable
3 begin
4 if (ora_dict_obj_type='JAVA')
5 then
6 raise_application_error(-20031,'Java Development Disabled');
7 end if;
8 end;
9 /
Trigger created.
SQL>
SQL> create or replace view sys.java_dev_status as
2 select decode(status,'ENABLED','NO','YES') JAVA_DEV_ALLOWED
3 from dba_triggers
4 where trigger_name='DBMS_JAVA_DEV_TRG'
5 and owner='SYS';
View created.
SQL>
SQL>
SQL> create or replace public synonym java_dev_status for sys.java_dev_status;
Synonym created.
SQL> grant select on java_dev_status to public;
Grant succeeded.
SQL>
SQL> declare
2 constraint_exists exception;
3 pragma exception_init(constraint_exists, -2264);
4 begin
5 execute immediate 'alter table sys.procedurejava$ add constraint
6 java_dev_disabled check (obj# = 0) disable';
7 exception
8 when constraint_exists then
9 null;
10 end;
11 /
PL/SQL procedure successfully completed.
SQL>
SQL> declare
2 constraint_exists exception;
3 pragma exception_init(constraint_exists, -2264);
4 begin
5 execute immediate 'alter table sys.javajar$ add constraint
6 java_dev_jars_disabled check (owner# = -1) disable';
7 exception
8 when constraint_exists then
9 null;
10 end;
11 /
declare
*
ERROR at line 1:
ORA-00942: table or view does not exist
ORA-06512: at line 5
SQL>
SQL>
SQL> create or replace package sys.dbms_java_dev authid definer is
2
3 procedure disable;
4
5 procedure enable;
6
7 end dbms_java_dev;
8 /
Package created.
SQL>
SQL> create or replace package body sys.dbms_java_dev is
2
3 procedure disable is
4 type grant_collection is table of sys.dba_tab_privs.table_name%type;
5 jdev_grants grant_collection;
6 type grantee_collection is table of sys.dba_tab_privs.grantee%type;
7 jdev_grantees grantee_collection;
8 pkg_name sys.dba_tab_privs.table_name%type;
9 grantee varchar2(130);
10 stmt varchar2(2000);
11 stmt2 varchar2(2000);
12 begin
13
14 select distinct owner, referenced_name bulk collect
15 into jdev_grantees, jdev_grants
16 from sys.dba_dependencies
17 where referenced_owner in ('SYS','PUBLIC') and owner != 'PUBLIC'
18 and owner != referenced_owner
19 and referenced_name in ('DBMS_JAVA','DBMS_JAVA_TEST','SQLJUTL',
20 'SQLJUTL2','JVMRJBCINV','DBMS_JAVA_MISC');
21
22 for i in 1..jdev_grants.count loop
23 pkg_name := dbms_assert.simple_sql_name(jdev_grants(i));
24 grantee := dbms_assert.enquote_name(jdev_grantees(i),FALSE);
25 stmt := 'grant execute on sys.' || pkg_name || ' to ' || grantee;
26 execute immediate stmt;
27 end loop;
28
29 select table_name bulk collect into jdev_grants from sys.dba_tab_privs
30 where grantee='PUBLIC' and owner='SYS' and privilege='EXECUTE'
31 and table_name in ('DBMS_JAVA','DBMS_JAVA_TEST','SQLJUTL','SQLJUTL2',
32 'JVMRJBCINV','DBMS_JAVA_MISC');
33
34 for i in 1..jdev_grants.count loop
35 pkg_name := dbms_assert.simple_sql_name(jdev_grants(i));
36 stmt := 'revoke execute on sys.' || pkg_name || ' from public';
37 stmt2 := 'grant execute on sys.' || pkg_name || ' to oracle_java_dev';
38 execute immediate stmt;
39 execute immediate stmt2;
40 end loop;
41
42 execute immediate 'alter trigger sys.dbms_java_dev_trg enable';
43
44 execute immediate 'alter table sys.procedurejava$ enable novalidate
45 constraint java_dev_disabled';
46 execute immediate 'alter table sys.javajar$ enable novalidate
47 constraint java_dev_jars_disabled';
48
49 end disable;
50
51 procedure enable is
52 type grant_collection is table of sys.dba_tab_privs.table_name%type;
53 jdev_grants grant_collection;
54 pkg_name sys.dba_tab_privs.table_name%type;
55 stmt varchar2(2000);
56 stmt2 varchar2(2000);
57 begin
58
59 execute immediate 'alter trigger sys.dbms_java_dev_trg disable';
60
61 execute immediate 'alter table sys.procedurejava$ disable constraint
62 java_dev_disabled';
63 execute immediate 'alter table sys.javajar$ disable constraint
64 java_dev_jars_disabled';
65
66 select table_name bulk collect into jdev_grants from sys.dba_tab_privs
67 where grantee='ORACLE_JAVA_DEV' and privilege='EXECUTE' and owner='SYS'
68 and table_name in ('DBMS_JAVA','DBMS_JAVA_TEST','SQLJUTL','SQLJUTL2',
69 'JVMRJBCINV','DBMS_JAVA_MISC');
70
71 for i in 1..jdev_grants.count loop
72 pkg_name := dbms_assert.simple_sql_name(jdev_grants(i));
73 stmt := 'grant execute on sys.' || pkg_name || ' to public';
74 stmt2 := 'revoke execute on sys.' || pkg_name || ' from oracle_java_dev';
75 execute immediate stmt;
76 execute immediate stmt2;
77 end loop;
78
79 end enable;
80 end dbms_java_dev;
81 /
Package body created.
Only one error – but most statements succeed despite the fact that my database does not have a JAVAVM.
See my DBA_REGISTRY:
column comp_id format a12 column status format a7 column version format a12 select comp_id, status, version from dba_registry order by 1; COMP_ID STATUS VERSION ------------ ------- ------------ CATALOG VALID 11.2.0.4.0 CATPROC VALID 11.2.0.4.0
Very strange.
The failure is: You can install the objects associated with the mitigation patch despite the fact that there is no JAVAVM present in this database.
How about preupgrade.jar?
Back to the customer scenario. Our customer saw a warning about the presence of the mitigation patch by preupgrade.jar.
The execution of the script will alert you now because it uses this check:
IF NOT select_has_rows('select null from sys.dba_triggers where trigger_name=''DBMS_JAVA_DEV_TRG'' and owner=''SYS'' and status=''ENABLED''') THEN RETURN c_success;
Let us check the trigger’s status:
SQL> select status from dba_triggers where trigger_name='DBMS_JAVA_DEV_TRG'; STATUS -------- DISABLED 1 row selected.
But when you call to disable the Java subsystem (see the next paragraph), the trigger will change its status to ENABLED
. And then preupgrade.jar
will give you an ERROR
condition.
We will add an additional check in a newer version of preupgrade.jar
, and of course in autoupgrade, too.
Can I disable the Java subsystem?
At first, I check what the package contains:
-
SQL> desc sys.dbms_java_dev PROCEDURE DISABLE PROCEDURE ENABLE
Let me try:
SQL> exec sys.DBMS_JAVA_DEV.DISABLE; BEGIN sys.DBMS_JAVA_DEV.DISABLE; END; * ERROR at line 1: ORA-00942: table or view does not exist ORA-06512: at "SYS.DBMS_JAVA_DEV", line 46 ORA-06512: at line 1
Fails.
But how about:
SQL> exec sys.DBMS_JAVA_DEV.ENABLE; BEGIN sys.DBMS_JAVA_DEV.ENABLE; END; * ERROR at line 1: ORA-00942: table or view does not exist ORA-06512: at "SYS.DBMS_JAVA_DEV", line 63 ORA-06512: at line 1
Fails too. And this makes sense as there is no JAVAMVM
. For instance, this table sys.javajar$
does not exist in my case.
No harm can be done – and I checked in addition, all objects in DBA_OBJECTS
are VALID
.
But why?
But the final question remains to me – and maybe to you, too:
How could this happen?
Of course, we are all in agreement, that the dbmsjdev.sql
should have a check at first. It shouldn’t create objects when there no JAVAVM
component present. And preupgrade.jar will get an additional one as well. But this is just a minor problem.
Simple answer – the readme of the PSUs is the reason why our customer executed dbmsjdev.sql
.
See here in the January 2020 PSU for 11.2.0.4 under:
1.3.3.2 Loading Modified SQL Files into the Database

11.2.0.3 January 2020 PSU – README – Section about Mitigation Patch
Argh! Now it is obvious. The sentence does not say: “Please check DBA_REGISTRY. If JAVAVM is not installed, ignore this paragraph.“.
Hence, no blame to the customer. It simply doesn’t get explained that the Mitigation Patch will make only sense when JAVAVM
is present in your database. In all other cases, it has no meaning, and therefore dbmsjdev.sql
don’t need to be run.
But this is exactly why we came across this issue. The customer followed the README, executed the dbmsjdev.sql
script and called the DBMS_JAVA_DEV.DISABLE
procedure.
Summary
The Mitigation Patch is included in all 11.2.0.4 and 12.1.0.2 patch bundles since at least late 2017. No extra installation is required. You can use it to disable the Java subsystem. This is helpful in cases where you have OJVM present in your database but can’t or don’t want to patch it. This way you can avoid getting exposed to the many security issues associated with OJVM.
But you do need neither the Mitigation Patch nor the activation script dbmsjdev.sql
which creates the necessary framework to disable the Java subsystem if JAVAVM
is not present in your database. Check DBA_REGISTRY
(or CDB_REGISTRY
from 12.1 on) whether you have a COMP_ID
with JAVAVM
.
Addition
Bug 31132048 – DBMSJDEV.SQL SHOULD BLOCK EXECUTION IF JAVAVM IS NOT PRESENT IN REGISTRY has been logged and fixed for this issue. As the code fix has been done for MAIN (which is 21c), you may please need to request a one-off on top of your RU as long as this isn’t included in an RU yet. Please upload your opatch lsinventory, too, in case you request a backport.
More Information and Links
- MOS Note:1929745.1 – Oracle JavaVM Component Database Patches
- The OJVM Patching Saga – And how to solve it – Part III: The Mitigation Patch
- Issues with Seed Databases, Patch Bundles and OJVM
–Mike
Mike,
I encountered the same error when I upgrade from 11.2 to 19.8, your analysis is very helpful for understanding the issue. This issue caused upgrade stoppped, how did you resolve the issue and continue upgrade?
Hi Shibin,
actually this has been fixed via a code fix.
Bug 31132048 – DBMSJDEV.SQL SHOULD BLOCK EXECUTION IF JAVAVM IS NOT PRESENT IN REGISTRY$
Can you please check via an SR whether there is a fix available on top of 19.8.0?
Otherwise you can request it via the same SR (upload opatch lsinventory to it please).
Cheers,
Mike
Hi Mike, just a short and maybe stupid question: is the mitigation patch resp. the deactivation of JAVAVM only relevant for the CDB$ROOT or also for the PDBs? I did not find any hint on that. Thinking about the post actions when applying an OJVM RU I would say yes, the deactivation must also be done for any PDB (if you expicitly want that 😉
Thanks & regards
Axel
Hi Axel,
JVM can be active in CDB$ROOT as well as in all PDBs unless you completely remove it.
Please check CDB_REGISTRY where COMP_ID=’JVM’.
Cheers,
Mike
Hi Mike, thanks for your answer. What if I exactly hit this situation: we have JAVAVM, we don’t use it but can’t deinstall it. I thought in such cases the mitigation patch is the right choice, isnt it?
Thanks & regards
Axel D.
Hi Axel,
when you run @?/rdbms/admin/dbmsjdev.sql, the call to disable the Java subsystem will be available only in the container you ran it into.
If you want it “everywhere”, you need to execute ?/rdbms/admin/dbmsjdev.sql with catcon.pl – and then you need to disable it in the PDB$SEED as well.
As I think this is documented anywhere (at least I didn’t), I will write a quick blog post and demo it. Actually a very good point.
Thanks!
Mike
Mike,
We have one for you. On our latest patching in June with Premium Support on our Exadata’s they told us we needed to run exec dbms_java_dev.enable since their pre-check scripts show we have java mitigation patch installed. We informed them that we don’t even have JAVAM installed so therefore why should we run that script. Well we went ahead and ran the exec dbms_java_dev.enable it then gives the error “PLS-00201: identifier ‘DBMS_JAVA_DEV.ENABLE’ must be declared”. Well we told them that we shouldn’t even have that installed and don’t know why it is there. The reason we know it shouldn’t is the fact that these Exadata’s just got installed last year and we created all the DBs first while leaving out JAVAM. Well I started looking into their scripts they run and found the pre-check script runs this “select count (1) from dba_objects where OBJECT_NAME=’JAVA_DEV_STATUS’ and OWNER=’SYS’;” and if it returns a 1 it will fail the pre-check datapatch script. I went and looked at this object and it has a created date of our last patching event in March. The two DBAs here didn’t run the dbmsjdev.sql in March and according to the timestamp on that object it was created at the same time that Oracle Support was running the cell patching part of the Exadata. Well now here we are stuck with these objects in our DB and no way to make Oracle Support happy when we want to patch again. My question in all of this is can we remove these objects from the dbmsjdev.sql installs without any issues? We have an SR in but thought I would ask you to see what you think. Thanks in advance.
Hi Kirk,
sorry to hear that – I feel really bad when I read this 🙁
I have seen this script somewhere, and I guess it has never been adjusted for such situations.
The result of:
select count (1) from dba_objects where OBJECT_NAME='JAVA_DEV_STATUS' and OWNER='SYS';
is supposed to be 0 when you have JAVAVM. See here:
SQL> select count (1) from dba_objects where OBJECT_NAME='JAVA_DEV_STATUS' and OWNER='SYS';
COUNT(1)
----------
0
SQL> select comp_id from dba_registry order by 1;
COMP_ID
------------------------------
CATALOG
CATJAVA
CATPROC
JAVAVM
OLS
ORDIM
OWM
RAC
XDB
XML
10 rows selected.
My db has JAVAVM, the script returns 0 – I’m on 19.14.0 right now.
Mike