Index ¦ Archives ¦ Atom ¦ RSS

cx_Oracle and System Integrity Protection (El Capitan)

With the relase of El Capitan, Apple has enabled a new default security feature named System Integrity Protection, also called rootless. This may cause some apps, utilities, and scripts to not function at all, even with sudo privelege, root user enabled, or admin access. Oracle drivers seems one the these.

Not interest in the long story? Here the trick !!!

System Integrity Protection

System Integrity Protection is aimed at preventing Mac OS X compromise by malicious code, whether intentionally or accidentally, and essentially what SIP does is lock down specific system level locations in the file system while simultaneously preventing certain processes from attaching to system-level processes.

For System Integrity Protection locks down the following system level directories:

  • /System
  • /sbin
  • /usr (with the exception of /usr/local)

There are a lot of infos how to disable rootless, what we want to achieve is to let cx_Oracle works without disable SIP.

Let try to see what happen when we try to use cx_Oracle.

$ ./manage.py inspectdb --database=pasport
Traceback (most recent call last):
  File "./manage.py", line 12, in <module>
    execute_from_command_line(sys.argv)
  ...
  ...
  File "TEST_VIRTUALENV/lib/python2.7/site-packages/django/db/backends/oracle/base.py", line 47, in <module>
    raise ImproperlyConfigured("Error loading cx_Oracle module: %s" % e)
django.core.exceptions.ImproperlyConfigured: Error loading cx_Oracle module: dlopen(TEST_VIRTUALENV/lib/python2.7/site-packages/cx_Oracle.so, 2): Library not loaded: /ade/b/3071542110/oracle/rdbms/lib/libclntsh.dylib.11.1
  Referenced from: TEST_VIRTUALENV/lib/python2.7/site-packages/cx_Oracle.so
  Reason: image not found

uh oh!!

cx_Oracle seems not able to find /ade/b/3071542110/oracle/rdbms/lib/libclntsh.dylib.11.1. Now, I have no idea where this path come from, anyway I have libclntsh.dylib.11.1 in my $ORACLE_HOME so I have to tell cx_Oracle to see there. Checking with otool confirm that

$ otool -L TEST_VIRTUALENV/lib/python2.7/site-packages/cx_Oracle.so
TEST_VIRTUALENV/lib/python2.7/site-packages/cx_Oracle.so:
    /ade/b/3071542110/oracle/rdbms/lib/libclntsh.dylib.11.1 (compatibility version 0.0.0, current version 0.0.0)
    /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1225.1.1)

we need to relync binaries they do not try to access avoided location; to achieve this we use to command line tools otool and install_name_tool

install_name_tool -change /ade/b/3071542110/oracle/rdbms/lib/libclntsh.dylib.11.1 $ORACLE_HOME/$baselib TEST_VIRTUALENV/lib/python2.7/site-packages/cx_Oracle.so

check the result

$ otool -L TEST_VIRTUALENV/lib/python2.7/site-packages/cx_Oracle.so
TEST_VIRTUALENV/lib/python2.7/site-packages/cx_Oracle.so:
    /data/oracle/instantclient_11_2/libclntsh.dylib.11.1 (compatibility version 0.0.0, current version 0.0.0)
    /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1225.1.1)

try again

$ ./manage.py inspectdb --database=pasport
...
...
raise ImproperlyConfigured("Error loading cx_Oracle module: %s" % e)
django.core.exceptions.ImproperlyConfigured: Error loading cx_Oracle module: dlopen(/data/VENV/capi/lib/python2.7/site-packages/cx_Oracle.so, 2): Library not loaded: /ade/dosulliv_ldapmac/oracle/ldap/lib/libnnz11.dylib
Referenced from: /data/oracle/instantclient_11_2/libclntsh.dylib.11.1
Reason: image not found

mmmm, same problem with oracle binaries, we need to apply the same patch.

The trick

A very simple script that allow you to easily patch the files. It accept two arguments, -o and -e respectively to patch oracle binaries and/or cx_Oracle.so in the active virtualenv

You only need to patch oracle binaries once, cx_Oracle need to be patched for each virtualenv (if many)

$ ./cxOracleSIP.sh -o -e

Download cxOracleSIP.sh

The script

#!/bin/sh
# cxOracleSIP.sh
# Copyright (c) 2015 Stefano Apostolico
#
# Permission is hereby granted, free of charge, to any person
# obtaining a copy of this software and associated documentation
# files (the "Software"), to deal in the Software without
# restriction, including without limitation the rights to use,
# copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the
# Software is furnished to do so, subject to the following
# conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
# OTHER DEALINGS IN THE SOFTWARE.



help () {
    echo `basename $0` "[-o] [-e]"
    echo " -o apply patch to oracle binaries ($ORACLE_HOME)"
    [[ -z "$VIRTUAL_ENV" ]] && V="need active virtualenv" || V=$VIRTUAL_ENV
    echo " -e apply patch to cx_Oracle ($V)"
    exit 1
}

echo $# $@

[[ $# -eq 0 ]]  && help

while [[ $# > 0 ]]
    do
    key="$1"
    case $key in
        -o)
            ORA=1
            ;;
        -e) if [ -z $VIRTUAL_ENV ]; then
                echo "ERROR: no active virtualenv"
                exit 1
            fi
            ENV=1
            ;;
        *) help
           exit 1
        ;;
    esac
    shift # past argument or value
done

patch (){
    echo "patching $1"
    basetarget=`basename $1`
    otool -L $1 | awk '/oracle/ {print $1}' | awk '/[^:]$/ ' | while read lib
    do
        echo "    - $lib"
        baselib=`basename $lib`
        if [ "$basetarget" = "$baselib" ]
        then
            echo "    - changing id to $baselib for $1"
            sudo install_name_tool -id $baselib $1
        else
            echo "    - changing path id for $lib in $1"
            sudo install_name_tool -change $lib $ORACLE_HOME/$baselib $1
        fi
    done
}

if [[ $ORA -eq 1 ]];then
    find $ORACLE_HOME -maxdepth 1 -type f \( -perm -1 -o \( -perm -10 -o -perm -100 \) \) -print | while read target
    do
        patch $target
    done
fi

if [[ $ENV -eq 1 ]];then
    patch $VIRTUAL_ENV/lib/python2.7/site-packages/cx_Oracle.so
fi

© 2014 Stefano Apostolico. Built using Pelican. Member of the Internet Defense League.