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 220.127.116.11 home – despite the fact that JAVAVM is not configured in this database. And this looked strange to us.
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 18.104.22.168 and 22.214.171.124 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 126.96.36.199 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 188.8.131.52 environment I use the January 2020 PSU. In Oracle 184.108.40.206 there is no choice unless you have an Exadata. Otherwise I would use BPs and RUs.
$ORACLE_HOME/OPatch/opatch lsinventory > file.txt
And when I search for the patch number, 19721304, I get this result in the output:
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:
If you don’t run this script, you can’t execute the call do disable the Java subsystem:
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 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 220.127.116.11.0 CATPROC VALID 18.104.22.168.0
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
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
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
does not exist in my case.
No harm can be done – and I checked in addition, all objects in
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
See here in the January 2020 PSU for 22.214.171.124 under:
126.96.36.199 Loading Modified SQL Files into the Database
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
The Mitigation Patch is included in all 188.8.131.52 and 184.108.40.206 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
CDB_REGISTRY from 12.1 on) whether you have a
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