diff options
author | kjyoun@google.com <kjyoun@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-03-25 03:30:25 +0000 |
---|---|---|
committer | kjyoun@google.com <kjyoun@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-03-25 03:30:25 +0000 |
commit | 2b301236346c520693c80db0882f4020d823157c (patch) | |
tree | 084da2a7ac100d95cf0d60cb71d8525845b68ac4 /content | |
parent | 40f035e90d03df735ce7acb87c158066cf70e2f1 (diff) | |
download | chromium_src-2b301236346c520693c80db0882f4020d823157c.zip chromium_src-2b301236346c520693c80db0882f4020d823157c.tar.gz chromium_src-2b301236346c520693c80db0882f4020d823157c.tar.bz2 |
Enable broker plugin process out of sandbox
BUG=178382
Review URL: https://chromiumcodereview.appspot.com/12902026
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@190329 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'content')
14 files changed, 216 insertions, 87 deletions
diff --git a/content/public/android/java/src/org/chromium/content/app/PrivilegedProcessService.java b/content/public/android/java/src/org/chromium/content/app/PrivilegedProcessService.java new file mode 100644 index 0000000..49ce280 --- /dev/null +++ b/content/public/android/java/src/org/chromium/content/app/PrivilegedProcessService.java @@ -0,0 +1,13 @@ +// Copyright (c) 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.content.app; + +// Privleged (unsandboxed) Services inherit from this class. We enforce the +// privileged/sandboxed distinction by type-checking objects against this parent +// class. + +public class PrivilegedProcessService extends ChildProcessService { + +} diff --git a/content/public/android/java/src/org/chromium/content/app/PrivilegedProcessService0.java b/content/public/android/java/src/org/chromium/content/app/PrivilegedProcessService0.java new file mode 100644 index 0000000..0520538 --- /dev/null +++ b/content/public/android/java/src/org/chromium/content/app/PrivilegedProcessService0.java @@ -0,0 +1,12 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.content.app; + +// This is needed to register multiple PrivilegedProcess services so that we can have +// more than one privileged process. + +public class PrivilegedProcessService0 extends PrivilegedProcessService { + +} diff --git a/content/public/android/java/src/org/chromium/content/app/PrivilegedProcessService1.java b/content/public/android/java/src/org/chromium/content/app/PrivilegedProcessService1.java new file mode 100644 index 0000000..47c16e6 --- /dev/null +++ b/content/public/android/java/src/org/chromium/content/app/PrivilegedProcessService1.java @@ -0,0 +1,12 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.content.app; + +// This is needed to register multiple SandboxedProcess services so that we can have +// more than one privileged process. + +public class PrivilegedProcessService1 extends PrivilegedProcessService { + +} diff --git a/content/public/android/java/src/org/chromium/content/app/PrivilegedProcessService2.java b/content/public/android/java/src/org/chromium/content/app/PrivilegedProcessService2.java new file mode 100644 index 0000000..16cdd6d --- /dev/null +++ b/content/public/android/java/src/org/chromium/content/app/PrivilegedProcessService2.java @@ -0,0 +1,12 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.content.app; + +// This is needed to register multiple SandboxedProcess services so that we can have +// more than one sandboxed process. + +public class PrivilegedProcessService2 extends PrivilegedProcessService { + +} diff --git a/content/public/android/java/src/org/chromium/content/app/SandboxedProcessService.java b/content/public/android/java/src/org/chromium/content/app/SandboxedProcessService.java new file mode 100644 index 0000000..7b38af8 --- /dev/null +++ b/content/public/android/java/src/org/chromium/content/app/SandboxedProcessService.java @@ -0,0 +1,12 @@ +// Copyright (c) 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.content.app; + +// Sandboxed Services inherit from this class. We enforce the privileged/sandboxed +// distinction by type-checking objects against this parent class. + +public class SandboxedProcessService extends ChildProcessService { + +} diff --git a/content/public/android/java/src/org/chromium/content/app/SandboxedProcessService0.java b/content/public/android/java/src/org/chromium/content/app/SandboxedProcessService0.java index 0b54bc4..1fcd974 100644 --- a/content/public/android/java/src/org/chromium/content/app/SandboxedProcessService0.java +++ b/content/public/android/java/src/org/chromium/content/app/SandboxedProcessService0.java @@ -7,6 +7,6 @@ package org.chromium.content.app; // This is needed to register multiple SandboxedProcess services so that we can have // more than one sandboxed process. -public class SandboxedProcessService0 extends ChildProcessService { +public class SandboxedProcessService0 extends SandboxedProcessService { } diff --git a/content/public/android/java/src/org/chromium/content/app/SandboxedProcessService1.java b/content/public/android/java/src/org/chromium/content/app/SandboxedProcessService1.java index ec275e5..24846a7 100644 --- a/content/public/android/java/src/org/chromium/content/app/SandboxedProcessService1.java +++ b/content/public/android/java/src/org/chromium/content/app/SandboxedProcessService1.java @@ -7,6 +7,6 @@ package org.chromium.content.app; // This is needed to register multiple SandboxedProcess services so that we can have // more than one sandboxed process. -public class SandboxedProcessService1 extends ChildProcessService { +public class SandboxedProcessService1 extends SandboxedProcessService { } diff --git a/content/public/android/java/src/org/chromium/content/app/SandboxedProcessService2.java b/content/public/android/java/src/org/chromium/content/app/SandboxedProcessService2.java index cc47337..f8d1802 100644 --- a/content/public/android/java/src/org/chromium/content/app/SandboxedProcessService2.java +++ b/content/public/android/java/src/org/chromium/content/app/SandboxedProcessService2.java @@ -7,6 +7,6 @@ package org.chromium.content.app; // This is needed to register multiple SandboxedProcess services so that we can have // more than one sandboxed process. -public class SandboxedProcessService2 extends ChildProcessService { +public class SandboxedProcessService2 extends SandboxedProcessService { } diff --git a/content/public/android/java/src/org/chromium/content/app/SandboxedProcessService3.java b/content/public/android/java/src/org/chromium/content/app/SandboxedProcessService3.java index 207232c..f5b8fa5 100644 --- a/content/public/android/java/src/org/chromium/content/app/SandboxedProcessService3.java +++ b/content/public/android/java/src/org/chromium/content/app/SandboxedProcessService3.java @@ -7,6 +7,6 @@ package org.chromium.content.app; // This is needed to register multiple SandboxedProcess services so that we can have // more than one sandboxed process. -public class SandboxedProcessService3 extends ChildProcessService { +public class SandboxedProcessService3 extends SandboxedProcessService { } diff --git a/content/public/android/java/src/org/chromium/content/app/SandboxedProcessService4.java b/content/public/android/java/src/org/chromium/content/app/SandboxedProcessService4.java index 3cf919c..bec8dea 100644 --- a/content/public/android/java/src/org/chromium/content/app/SandboxedProcessService4.java +++ b/content/public/android/java/src/org/chromium/content/app/SandboxedProcessService4.java @@ -7,6 +7,6 @@ package org.chromium.content.app; // This is needed to register multiple SandboxedProcess services so that we can have // more than one sandboxed process. -public class SandboxedProcessService4 extends ChildProcessService { +public class SandboxedProcessService4 extends SandboxedProcessService { } diff --git a/content/public/android/java/src/org/chromium/content/app/SandboxedProcessService5.java b/content/public/android/java/src/org/chromium/content/app/SandboxedProcessService5.java index 88a18ff..9a852e1 100644 --- a/content/public/android/java/src/org/chromium/content/app/SandboxedProcessService5.java +++ b/content/public/android/java/src/org/chromium/content/app/SandboxedProcessService5.java @@ -7,6 +7,6 @@ package org.chromium.content.app; // This is needed to register multiple SandboxedProcess services so that we can have // more than one sandboxed process. -public class SandboxedProcessService5 extends ChildProcessService { +public class SandboxedProcessService5 extends SandboxedProcessService { } diff --git a/content/public/android/java/src/org/chromium/content/browser/AndroidBrowserProcess.java b/content/public/android/java/src/org/chromium/content/browser/AndroidBrowserProcess.java index cead46a..f092b29 100644 --- a/content/public/android/java/src/org/chromium/content/browser/AndroidBrowserProcess.java +++ b/content/public/android/java/src/org/chromium/content/browser/AndroidBrowserProcess.java @@ -50,12 +50,12 @@ public class AndroidBrowserProcess { // Cap on the maximum number of renderer processes that can be requested. // This is currently set to account for: - // 6: The maximum number of child processes we have available + // 6: The maximum number of sandboxed processes we have available // - 1: The regular New Tab Page // - 1: The incognito New Tab Page // - 1: A regular incognito tab public static final int MAX_RENDERERS_LIMIT = - ChildProcessLauncher.MAX_REGISTERED_SERVICES - 3; + ChildProcessLauncher.MAX_REGISTERED_SANDBOXED_SERVICES - 3; /** * Initialize the process as a ContentView host. This must be called from the main UI thread. diff --git a/content/public/android/java/src/org/chromium/content/browser/ChildProcessConnection.java b/content/public/android/java/src/org/chromium/content/browser/ChildProcessConnection.java index 66012c5..ce9a164 100644 --- a/content/public/android/java/src/org/chromium/content/browser/ChildProcessConnection.java +++ b/content/public/android/java/src/org/chromium/content/browser/ChildProcessConnection.java @@ -53,6 +53,7 @@ public class ChildProcessConnection implements ServiceConnection { private final Context mContext; private final int mServiceNumber; + private final boolean mInSandbox; private final ChildProcessConnection.DeathCallback mDeathCallback; private final Class<? extends ChildProcessService> mServiceClass; @@ -91,11 +92,12 @@ public class ChildProcessConnection implements ServiceConnection { private ConnectionParams mConnectionParams; private boolean mIsBound; - ChildProcessConnection(Context context, int number, + ChildProcessConnection(Context context, int number, boolean inSandbox, ChildProcessConnection.DeathCallback deathCallback, Class<? extends ChildProcessService> serviceClass) { mContext = context; mServiceNumber = number; + mInSandbox = inSandbox; mDeathCallback = deathCallback; mServiceClass = serviceClass; } @@ -104,6 +106,10 @@ public class ChildProcessConnection implements ServiceConnection { return mServiceNumber; } + boolean isInSandbox() { + return mInSandbox; + } + IChildProcessService getService() { synchronized(mUiThreadLock) { return mService; @@ -112,8 +118,7 @@ public class ChildProcessConnection implements ServiceConnection { private Intent createServiceBindIntent() { Intent intent = new Intent(); - String serviceClassNameBase = mServiceClass.getName().replaceAll("[0-9]*$", ""); - intent.setClassName(mContext, serviceClassNameBase + mServiceNumber); + intent.setClassName(mContext, mServiceClass.getName() + mServiceNumber); intent.setPackage(mContext.getPackageName()); return intent; } diff --git a/content/public/android/java/src/org/chromium/content/browser/ChildProcessLauncher.java b/content/public/android/java/src/org/chromium/content/browser/ChildProcessLauncher.java index e59a7e8..5ddc008 100644 --- a/content/public/android/java/src/org/chromium/content/browser/ChildProcessLauncher.java +++ b/content/public/android/java/src/org/chromium/content/browser/ChildProcessLauncher.java @@ -8,9 +8,7 @@ import android.content.Context; import android.util.Log; import android.view.Surface; -import java.util.Arrays; import java.util.ArrayList; -import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; @@ -18,6 +16,8 @@ import org.chromium.base.CalledByNative; import org.chromium.base.JNINamespace; import org.chromium.base.ThreadUtils; import org.chromium.content.app.ChildProcessService; +import org.chromium.content.app.PrivilegedProcessService; +import org.chromium.content.app.SandboxedProcessService; import org.chromium.content.app.LibraryLoader; import org.chromium.content.common.IChildProcessCallback; import org.chromium.content.common.IChildProcessService; @@ -34,43 +34,112 @@ public class ChildProcessLauncher { private static final int CALLBACK_FOR_GPU_PROCESS = 1; private static final int CALLBACK_FOR_RENDERER_PROCESS = 2; - // The upper limit on the number of simultaneous service process instances supported. - // This must not exceed total number of SandboxedProcessServiceX classes declared in - // this package, and defined as services in the embedding application's manifest file. + private static final String SWITCH_PROCESS_TYPE = "type"; + private static final String SWITCH_PPAPI_BROKER_PROCESS = "ppapi-broker"; + private static final String SWITCH_RENDERER_PROCESS = "renderer"; + private static final String SWITCH_GPU_PROCESS = "gpu-process"; + + // The upper limit on the number of simultaneous sandboxed and privileged child service process + // instances supported. Each limit must not exceed total number of SandboxedProcessServiceX + // classes and PrivilegedProcessClassX declared in this package, and defined as services in the + // embedding application's manifest file. // (See {@link ChildProcessService} for more details on defining the services.) - /* package */ static final int MAX_REGISTERED_SERVICES = 6; - private static final ChildProcessConnection[] mConnections = - new ChildProcessConnection[MAX_REGISTERED_SERVICES]; - // The list of free slots in mConnections. When looking for a free connection, - // the first index in that list should be used. When a connection is freed, its index - // is added to the end of the list. This is so that we avoid immediately reusing a freed - // connection (see bug crbug.com/164069): the framework might keep a service process alive - // when it's been unbound for a short time. If a connection to that same service is bound - // at that point, the process is reused and bad things happen (mostly static variables are - // set when we don't expect them to). - // SHOULD BE ACCESSED WITH THE mConnections LOCK. - private static final ArrayList<Integer> mFreeConnectionIndices = - new ArrayList<Integer>(MAX_REGISTERED_SERVICES); - static { - for (int i = 0; i < MAX_REGISTERED_SERVICES; i++) { - mFreeConnectionIndices.add(i); + /* package */ static final int MAX_REGISTERED_SANDBOXED_SERVICES = 6; + /* package */ static final int MAX_REGISTERED_PRIVILEGED_SERVICES = 3; + + private static class ChildConnectionAllocator { + private ChildProcessConnection[] mChildProcessConnections; + + // The list of free slots in corresponing Connections. When looking for a free connection, + // the first index in that list should be used. When a connection is freed, its index + // is added to the end of the list. This is so that we avoid immediately reusing a freed + // connection (see bug crbug.com/164069): the framework might keep a service process alive + // when it's been unbound for a short time. If a connection to that same service is bound + // at that point, the process is reused and bad things happen (mostly static variables are + // set when we don't expect them to). + // SHOULD BE ACCESSED WITH THE mConnectionLock. + private ArrayList<Integer> mFreeConnectionIndices; + private final Object mConnectionLock = new Object(); + + private Class<? extends ChildProcessService> mChildClass; + private final boolean mInSandbox; + + public ChildConnectionAllocator(boolean inSandbox) { + int numChildServices = inSandbox ? + MAX_REGISTERED_SANDBOXED_SERVICES : MAX_REGISTERED_PRIVILEGED_SERVICES; + mChildProcessConnections = new ChildProcessConnection[numChildServices]; + mFreeConnectionIndices = new ArrayList<Integer>(numChildServices); + for (int i = 0; i < numChildServices; i++) { + mFreeConnectionIndices.add(i); + } + setServiceClass(inSandbox ? + SandboxedProcessService.class : PrivilegedProcessService.class); + mInSandbox = inSandbox; + } + + public void setServiceClass(Class<? extends ChildProcessService> childClass) { + mChildClass = childClass; + } + + public ChildProcessConnection allocate( + Context context, ChildProcessConnection.DeathCallback deathCallback) { + synchronized(mConnectionLock) { + if (mFreeConnectionIndices.isEmpty()) { + Log.w(TAG, "Ran out of service." ); + return null; + } + int slot = mFreeConnectionIndices.remove(0); + assert mChildProcessConnections[slot] == null; + mChildProcessConnections[slot] = new ChildProcessConnection(context, slot, + mInSandbox, deathCallback, mChildClass); + return mChildProcessConnections[slot]; + } + } + + public void free(ChildProcessConnection connection) { + synchronized(mConnectionLock) { + int slot = connection.getServiceNumber(); + if (mChildProcessConnections[slot] != connection) { + int occupier = mChildProcessConnections[slot] == null ? + -1 : mChildProcessConnections[slot].getServiceNumber(); + Log.e(TAG, "Unable to find connection to free in slot: " + slot + + " already occupied by service: " + occupier); + assert false; + } else { + mChildProcessConnections[slot] = null; + assert !mFreeConnectionIndices.contains(slot); + mFreeConnectionIndices.add(slot); + } + } } } // Service class for child process. As the default value it uses - // SandboxedProcessService0. - private static Class<? extends ChildProcessService> mServiceClass = - org.chromium.content.app.SandboxedProcessService0.class; + // SandboxedProcessService0 and PrivilegedProcessService0 + private static final ChildConnectionAllocator mSandboxedChildConnectionAllocator = + new ChildConnectionAllocator(true); + private static final ChildConnectionAllocator mPrivilegedChildConnectionAllocator = + new ChildConnectionAllocator(false); + private static boolean mConnectionAllocated = false; - // Sets service class for sandboxed service. - public static void setServiceClass(Class<? extends ChildProcessService> serviceClass) { + // Sets service class for sandboxed service and privileged service + public static void setChildProcessClass( + Class<? extends SandboxedProcessService> sandboxedServiceClass, + Class<? extends PrivilegedProcessService> privilegedServiceClass) { // We should guarantee this is called before allocating connection. assert !mConnectionAllocated; - mServiceClass = serviceClass; + mSandboxedChildConnectionAllocator.setServiceClass(sandboxedServiceClass); + mPrivilegedChildConnectionAllocator.setServiceClass(privilegedServiceClass); + } + + private static ChildConnectionAllocator getConnectionAllocator(boolean inSandbox) { + return inSandbox ? + mSandboxedChildConnectionAllocator : mPrivilegedChildConnectionAllocator; } - private static ChildProcessConnection allocateConnection(Context context) { + private static ChildProcessConnection allocateConnection(Context context, + boolean inSandbox) { ChildProcessConnection.DeathCallback deathCallback = new ChildProcessConnection.DeathCallback() { @Override @@ -78,23 +147,13 @@ public class ChildProcessLauncher { stop(pid); } }; - synchronized (mConnections) { - if (mFreeConnectionIndices.isEmpty()) { - Log.w(TAG, "Ran out of child services."); - return null; - } - int slot = mFreeConnectionIndices.remove(0); - assert mConnections[slot] == null; - mConnections[slot] = new ChildProcessConnection(context, slot, deathCallback, - mServiceClass); - mConnectionAllocated = true; - return mConnections[slot]; - } + mConnectionAllocated = true; + return getConnectionAllocator(inSandbox).allocate(context, deathCallback); } private static ChildProcessConnection allocateBoundConnection(Context context, - String[] commandLine) { - ChildProcessConnection connection = allocateConnection(context); + String[] commandLine, boolean inSandbox) { + ChildProcessConnection connection = allocateConnection(context, inSandbox); if (connection != null) { String libraryName = LibraryLoader.getLibraryToLoad(); assert libraryName != null : "Attempting to launch a child process without first " @@ -108,26 +167,8 @@ public class ChildProcessLauncher { if (connection == null) { return; } - int slot = connection.getServiceNumber(); - synchronized (mConnections) { - if (mConnections[slot] != connection) { - int occupier = mConnections[slot] == null ? - -1 : mConnections[slot].getServiceNumber(); - Log.e(TAG, "Unable to find connection to free in slot: " + slot + - " already occupied by service: " + occupier); - assert false; - } else { - mConnections[slot] = null; - assert !mFreeConnectionIndices.contains(slot); - mFreeConnectionIndices.add(slot); - } - } - } - - public static int getNumberOfConnections() { - synchronized (mConnections) { - return mFreeConnectionIndices.size(); - } + getConnectionAllocator(connection.isInSandbox()).free(connection); + return; } // Represents an invalid process handle; same as base/process.h kNullProcessHandle. @@ -138,7 +179,7 @@ public class ChildProcessLauncher { new ConcurrentHashMap<Integer, ChildProcessConnection>(); // A pre-allocated and pre-bound connection ready for connection setup, or null. - static ChildProcessConnection mSpareConnection = null; + static ChildProcessConnection mSpareSandboxedConnection = null; /** * Returns the child process service interface for the given pid. This may be called on @@ -159,17 +200,32 @@ public class ChildProcessLauncher { /** * Should be called early in startup so the work needed to spawn the child process can * be done in parallel to other startup work. Must not be called on the UI thread. + * Spare connection is created in sandboxed child process. * @param context the application context used for the connection. */ public static void warmUp(Context context) { synchronized (ChildProcessLauncher.class) { assert !ThreadUtils.runningOnUiThread(); - if (mSpareConnection == null) { - mSpareConnection = allocateBoundConnection(context, null); + if (mSpareSandboxedConnection == null) { + mSpareSandboxedConnection = allocateBoundConnection(context, null, true); } } } + private static String getSwitchValue(final String[] commandLine, String switchKey) { + if (commandLine == null || switchKey == null) { + return null; + } + // This format should be matched with the one defined in command_line.h. + final String switchKeyPrefix = "--" + switchKey + "="; + for (String command : commandLine) { + if (command != null && command.startsWith(switchKeyPrefix)) { + return command.substring(switchKeyPrefix.length()); + } + } + return null; + } + /** * Spawns and connects to a child process. May be called on any thread. It will not * block, but will instead callback to {@link #nativeOnChildProcessStarted} when the @@ -199,13 +255,27 @@ public class ChildProcessLauncher { new FileDescriptorInfo(fileIds[i], fileFds[i], fileAutoClose[i]); } assert clientContext != 0; - ChildProcessConnection allocatedConnection; + + int callbackType = CALLBACK_FOR_UNKNOWN_PROCESS; + boolean inSandbox = true; + String processType = getSwitchValue(commandLine, SWITCH_PROCESS_TYPE); + if (SWITCH_RENDERER_PROCESS.equals(processType)) { + callbackType = CALLBACK_FOR_RENDERER_PROCESS; + } else if (SWITCH_GPU_PROCESS.equals(processType)) { + callbackType = CALLBACK_FOR_GPU_PROCESS; + } else if (SWITCH_PPAPI_BROKER_PROCESS.equals(processType)) { + inSandbox = false; + } + + ChildProcessConnection allocatedConnection = null; synchronized (ChildProcessLauncher.class) { - allocatedConnection = mSpareConnection; - mSpareConnection = null; + if (inSandbox) { + allocatedConnection = mSpareSandboxedConnection; + mSpareSandboxedConnection = null; + } } if (allocatedConnection == null) { - allocatedConnection = allocateBoundConnection(context, commandLine); + allocatedConnection = allocateBoundConnection(context, commandLine, inSandbox); if (allocatedConnection == null) { // Notify the native code so it can free the heap allocated callback. nativeOnChildProcessStarted(clientContext, 0); @@ -228,13 +298,6 @@ public class ChildProcessLauncher { nativeOnChildProcessStarted(clientContext, pid); } }; - int callbackType = CALLBACK_FOR_UNKNOWN_PROCESS; - List<String> commandLineList = Arrays.asList(commandLine); - if (commandLineList.contains("--type=renderer")) { - callbackType = CALLBACK_FOR_RENDERER_PROCESS; - } else if (commandLineList.contains("--type=gpu-process")) { - callbackType = CALLBACK_FOR_GPU_PROCESS; - } // TODO(sievers): Revisit this as it doesn't correctly handle the utility process // assert callbackType != CALLBACK_FOR_UNKNOWN_PROCESS; |