Search code examples
securitysolarisprivileges

Solaris 11.3 Extended Privilege Profile execve return EOVERFLOW


I'm getting the following error when running java with a profile with a long list of file_read extended attributes:

# pfexec /usr/jdk/instances/jdk1.8.0/bin/java -cp /vagrant HelloWorld
/usr/jdk/instances/jdk1.8.0/bin/java: Value too large for defined data type

When I run it with truss I see the exec error message is:

execve("/usr/jdk/instances/jdk1.8.0/bin/java", 0xFCEA4B60, 0xFCEA4B74) Err#79 EOVERFLOW

The man page for execve doesn't list EOVERFLOW as a possible return.

It appears to be related to the number of file_read extended attributes that I place in the profile. Here's how to reproduce the issue. The HelloWorld.java source is trivial but useful to ensure the privileges are assigned properly from ppriv -v pid

public class HelloWorld {
  public static void main( String[] args ) {
    System.out.println("Sleeping");
    try {
      Thread.sleep(50000);
    } catch( Exception e ) {
    }
    System.out.println("Hello World");
  }
}

There appears to be a bug in the profiles command as well as the profiles command was unwilling to generate a large enough list of file_read at tributes. In order to create the profile, you must edit the resulting /etc/security/exec_attr as follows:

# profiles -p test 'set desc=testing; add cmd=/usr/jdk/instances/jdk1.8.0/bin/java; set privs=basic; end; commit'
# usermod -P+test root

Manually edit /etc/security/exec_attr and use the following for the minimal permission set for java to execute without any permissions errors (backslashes added for readability and are allowed within the exec_attr file):

test:solaris:cmd:::/usr/jdk/instances/jdk1.8.0/bin/java:privs=\
{file_read}\:/lib/amd64/libc.so.1,\
{file_read}\:/lib/amd64/libcryptoutil.so.1,\
{file_read}\:/lib/amd64/libdl.so.1,\
{file_read}\:/lib/amd64/libdoor.so.1,\
{file_read}\:/lib/amd64/libelf.so.1,\
{file_read}\:/lib/amd64/libgen.so.1,\
{file_read}\:/lib/amd64/libkstat.so.1,\
{file_read}\:/lib/amd64/libm.so.1,\
{file_read}\:/lib/amd64/libm.so.2,\
{file_read}\:/lib/amd64/libmp.so.2,\
{file_read}\:/lib/amd64/libnsl.so.1,\
{file_read}\:/lib/amd64/libnvpair.so.1,\
{file_read}\:/lib/amd64/libscf.so.1,\
{file_read}\:/lib/amd64/libsocket.so.1,\
{file_read}\:/lib/amd64/libthread.so.1,\
{file_read}\:/lib/amd64/libucrypto.so.1,\
{file_read}\:/lib/amd64/libuutil.so.1,\
{file_read}\:/lib/amd64/libz.so.1,\
{file_read}\:/proc/*,\
{file_read}\:/system/volatile/name_service_door,\
{file_read}\:/system/volatile/tzsync,\
{file_read}\:/tmp,\
{file_read}\:/tmp/hsperfdata_root,\
{file_read}\:/usr/jdk/instances/jdk1.8.0/bin/java,\
{file_read}\:/usr/jdk/instances/jdk1.8.0/jre/lib/amd64/jvm.cfg,\
{file_read}\:/usr/jdk/instances/jdk1.8.0/jre/lib/amd64/libjava.so,\
{file_read}\:/usr/jdk/instances/jdk1.8.0/jre/lib/amd64/libverify.so,\
{file_read}\:/usr/jdk/instances/jdk1.8.0/jre/lib/amd64/libzip.so,\
{file_read}\:/usr/jdk/instances/jdk1.8.0/jre/lib/amd64/server/libjvm.so,\
{file_read}\:/usr/jdk/instances/jdk1.8.0/jre/lib/ext,\
{file_read}\:/usr/jdk/instances/jdk1.8.0/jre/lib/ext/meta-index,\
{file_read}\:/usr/jdk/instances/jdk1.8.0/jre/lib/meta-index,\
{file_read}\:/usr/jdk/instances/jdk1.8.0/jre/lib/resources.jar,\
{file_read}\:/usr/jdk/instances/jdk1.8.0/jre/lib/rt.jar,\
{file_read}\:/usr/jdk/instances/jdk1.8.0/lib/amd64/jli/libjli.so,\
{file_read}\:/usr/lib/amd64/libCrun.so.1,\
{file_read}\:/usr/lib/amd64/libdemangle.so.1,\
{file_read}\:/usr/lib/amd64/libsched.so.1,\
{file_read}\:/usr/lib/amd64/libsmbios.so.1,\
{file_read}\:/usr/share/lib/zoneinfo/US/Eastern,\
{file_read}\:/vagrant/HelloWorld.class;limitprivs=file_read

In order to produce the error I added {file_read}\:/absolute/path entries until the error was generated. I used pre-existing files by generated by calling find /usr/lib -name '*.jar' and adding them until it failed with EOVERFLOW

In my case the following list of files was enough. Removing any of them was enough for it to work again.

{file_read}\:/usr/lib/rad/java/authentication.jar,\
{file_read}\:/usr/lib/rad/java/authentication_1.jar,\
{file_read}\:/usr/lib/rad/java/config.jar,\
{file_read}\:/usr/lib/rad/java/config_1.jar,\
{file_read}\:/usr/lib/rad/java/container.jar,\
{file_read}\:/usr/lib/rad/java/container_1.jar,\
{file_read}\:/usr/lib/rad/java/control.jar,\
{file_read}\:/usr/lib/rad/java/control_1.jar,\
{file_read}\:/usr/lib/rad/java/dlmgr.jar,\
{file_read}\:/usr/lib/rad/java/dlmgr_1.jar,\
{file_read}\:/usr/lib/rad/java/errors.jar,\
{file_read}\:/usr/lib/rad/java/errors_1.jar,\
{file_read}\:/usr/lib/rad/java/evscntl.jar,\
{file_read}\:/usr/lib/rad/java/evscntl_1.jar,\
{file_read}\:/usr/lib/rad/java/files.jar,\
{file_read}\:/usr/lib/rad/java/files_1.jar,\
{file_read}\:/usr/lib/rad/java/kstat.jar,\
{file_read}\:/usr/lib/rad/java/kstat_1.jar,\
{file_read}\:/usr/lib/rad/java/modules.jar,\
{file_read}\:/usr/lib/rad/java/modules_1.jar,\
{file_read}\:/usr/lib/rad/java/network.jar,\
{file_read}\:/usr/lib/rad/java/network_1.jar,\
{file_read}\:/usr/lib/rad/java/pam.jar,\
{file_read}\:/usr/lib/rad/java/pam_1.jar,\
{file_read}\:/usr/lib/rad/java/panels.jar,\
{file_read}\:/usr/lib/rad/java/panels_1.jar,\
{file_read}\:/usr/lib/rad/java/rad.jar,\
{file_read}\:/usr/lib/rad/java/smf.jar,\
{file_read}\:/usr/lib/rad/java/smf_1.jar,\
{file_read}\:/usr/lib/rad/java/smf_old.jar,\
{file_read}\:/usr/lib/rad/java/smf_old_1.jar,\
{file_read}\:/usr/lib/rad/java/time.jar,\
{file_read}\:/usr/lib/rad/java/time_1.jar,\
{file_read}\:/usr/lib/rad/java/usermgr.jar,\
{file_read}\:/usr/lib/rad/java/usermgr_1.jar,\
{file_read}\:/usr/lib/rad/java/zfsmgr.jar,\
{file_read}\:/usr/lib/rad/java/zfsmgr_1.jar,\
{file_read}\:/usr/lib/rad/java/zonemgr.jar,\
{file_read}\:/usr/lib/rad/java/zonemgr_1.jar,\
{file_read}\:/usr/lib/rad/java/zonesbridge.jar,\
{file_read}\:/usr/lib/rad/java/zonesbridge_1.jar,\
{file_read}\:/usr/lib/ocm/ccr/inventory/engines.jar,\
{file_read}\:/usr/lib/ocm/ccr/inventory/metricdata.jar,\
{file_read}\:/usr/lib/ocm/ccr/inventory/core.jar,\
{file_read}\:/usr/lib/ocm/ccr/inventory/scripts.jar,\
{file_read}\:/usr/lib/ocm/ccr/inventory/ocmcert.jar,\
{file_read}\:/usr/lib/ocm/ccr/oui/jlib/OraPrereq.jar,\
{file_read}\:/usr/lib/ocm/ccr/oui/jlib/OraCheckPoint.jar,\
{file_read}\:/usr/lib/ocm/ccr/oui/jlib/OraInstallerNet.jar,\
{file_read}\:/usr/lib/ocm/ccr/oui/jlib/OraInstaller.jar,\
{file_read}\:/usr/lib/ocm/ccr/oui/jlib/share.jar,\
{file_read}\:/usr/lib/ocm/ccr/oui/jlib/xmlparserv2.jar,\
{file_read}\:/usr/lib/ocm/ccr/lib/OCMRFCreator.jar,\
{file_read}\:/usr/lib/ocm/ccr/lib/OpsCenterHarvester.jar,\
{file_read}\:/usr/lib/ocm/ccr/lib/emCCR.jar,\
{file_read}\:/usr/lib/ocm/ccr/lib/emgcharvester.jar,\
{file_read}\:/usr/lib/ocm/ccr/lib/emocmclnt-14.jar,\
{file_read}\:/usr/lib/ocm/ccr/lib/emocmclnt.jar,\
{file_read}\:/usr/lib/ocm/ccr/lib/emocmcommon.jar,\
{file_read}\:/usr/lib/ocm/ccr/lib/emocmdsf.jar

Ensure your profile changes are reflected by executing profiles -l

Is this just two bugs under Solaris 11.3? One in the profiles command (which can be worked around), and the other within the kernel? (Which cannot easily be worked around)


Solution

  • First of all, why not use wildcards like {file_read}\:/usr/lib/rad/java/*? That will limit the number of entries. Also, having so many files specifically when we are talking about {file_read} will be very expensive.

    The number of rules are limited but there is an (undocumented) tunable: xpol_rules_max which you can set in /etc/system by adding the line: set xpol_rules_max=100 or on-the-fly using mdb -wk as follows:

    # mdb -wk
    Loading modules: [ unix genunix specfs dtrace mac cpu.generic uppc pcplusmp zvpsm scsi_vhci zfs sata sd ip hook neti arp usba kssl sockfs lofs random idm cpc crypto fcip fctl nfs ufs logindmux ptm sppp ]
    > xpol_rules_max/x
    xpol_rules_max:
    xpol_rules_max: 64
    > xpol_rules_max/w 100
    xpol_rules_max: 0x64    =       0x100