summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorserya@chromium.org <serya@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-08-08 09:17:41 +0000
committerserya@chromium.org <serya@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-08-08 09:19:27 +0000
commitfe928be94514d6331264a36344316ff0abb8bfa7 (patch)
tree5a3f2d3f8dc18aa762c7bbdcb7127b4eb0128416
parent236ccaa12431f101db8fc18d632352087e4eead9 (diff)
downloadchromium_src-fe928be94514d6331264a36344316ff0abb8bfa7.zip
chromium_src-fe928be94514d6331264a36344316ff0abb8bfa7.tar.gz
chromium_src-fe928be94514d6331264a36344316ff0abb8bfa7.tar.bz2
Supports DevTools socket access authentication based on Android permissions.
BUG=399567 Review URL: https://codereview.chromium.org/382143005 Cr-Commit-Position: refs/heads/master@{#288273} git-svn-id: svn://svn.chromium.org/chrome/trunk/src@288273 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/android/java/src/org/chromium/chrome/browser/DevToolsServer.java33
-rw-r--r--chrome/browser/android/dev_tools_server.cc47
-rw-r--r--chrome/browser/android/dev_tools_server.h5
-rw-r--r--content/browser/android/devtools_auth.cc17
-rw-r--r--content/public/browser/android/devtools_auth.h10
-rw-r--r--net/socket/unix_domain_client_socket_posix_unittest.cc10
-rw-r--r--net/socket/unix_domain_listen_socket_posix.cc7
-rw-r--r--net/socket/unix_domain_listen_socket_posix_unittest.cc2
-rw-r--r--net/socket/unix_domain_server_socket_posix.cc20
-rw-r--r--net/socket/unix_domain_server_socket_posix.h26
-rw-r--r--net/socket/unix_domain_server_socket_posix_unittest.cc10
-rw-r--r--remoting/host/gnubby_auth_handler_posix.cc6
12 files changed, 123 insertions, 70 deletions
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/DevToolsServer.java b/chrome/android/java/src/org/chromium/chrome/browser/DevToolsServer.java
index 7ed33f9..5f84994 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/DevToolsServer.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/DevToolsServer.java
@@ -4,13 +4,29 @@
package org.chromium.chrome.browser;
+import android.content.Context;
+import android.content.pm.PackageManager;
+
+import org.chromium.base.CalledByNative;
+
/**
* Controller for Remote Web Debugging (Developer Tools).
*/
public class DevToolsServer {
+ private static final String DEBUG_PERMISSION_SIFFIX = ".permission.DEBUG";
private long mNativeDevToolsServer = 0;
+ // Defines what processes may access to the socket.
+ public enum Security {
+ // Use content::CanUserConnectToDevTools to authorize access to the socket.
+ DEFAULT,
+
+ // In addition to default authorization allows access to an app with android permission
+ // named chromeAppPackageName + DEBUG_PERMISSION_SIFFIX.
+ ALLOW_DEBUG_PERMISSION,
+ }
+
public DevToolsServer(String socketNamePrefix) {
mNativeDevToolsServer = nativeInitRemoteDebugging(socketNamePrefix);
}
@@ -24,12 +40,25 @@ public class DevToolsServer {
return nativeIsRemoteDebuggingEnabled(mNativeDevToolsServer);
}
+ public void setRemoteDebuggingEnabled(boolean enabled, Security security) {
+ boolean allowDebugPermission = security == Security.ALLOW_DEBUG_PERMISSION;
+ nativeSetRemoteDebuggingEnabled(mNativeDevToolsServer, enabled, allowDebugPermission);
+ }
+
public void setRemoteDebuggingEnabled(boolean enabled) {
- nativeSetRemoteDebuggingEnabled(mNativeDevToolsServer, enabled);
+ setRemoteDebuggingEnabled(enabled, Security.DEFAULT);
}
private native long nativeInitRemoteDebugging(String socketNamePrefix);
private native void nativeDestroyRemoteDebugging(long devToolsServer);
private native boolean nativeIsRemoteDebuggingEnabled(long devToolsServer);
- private native void nativeSetRemoteDebuggingEnabled(long devToolsServer, boolean enabled);
+ private native void nativeSetRemoteDebuggingEnabled(
+ long devToolsServer, boolean enabled, boolean allowDebugPermission);
+
+ @CalledByNative
+ private static boolean checkDebugPermission(Context context, int pid, int uid) {
+ String debugPermissionName = context.getPackageName() + DEBUG_PERMISSION_SIFFIX;
+ return context.checkPermission(debugPermissionName, pid, uid)
+ == PackageManager.PERMISSION_GRANTED;
+ }
}
diff --git a/chrome/browser/android/dev_tools_server.cc b/chrome/browser/android/dev_tools_server.cc
index acdb6b5..3b8b3ce 100644
--- a/chrome/browser/android/dev_tools_server.cc
+++ b/chrome/browser/android/dev_tools_server.cc
@@ -63,7 +63,6 @@ const char kDevToolsChannelNameFormat[] = "%s_devtools_remote";
const char kFrontEndURL[] =
"http://chrome-devtools-frontend.appspot.com/serve_rev/%s/devtools.html";
-const char kDefaultSocketNamePrefix[] = "chrome";
const char kTetheringSocketName[] = "chrome_devtools_tethering_%d_%d";
const char kTargetTypePage[] = "page";
@@ -77,6 +76,15 @@ static GURL GetFaviconURLForContents(WebContents* web_contents) {
return GURL();
}
+bool AuthorizeSocketAccessWithDebugPermission(
+ const net::UnixDomainServerSocket::Credentials& credentials) {
+ JNIEnv* env = base::android::AttachCurrentThread();
+ return Java_DevToolsServer_checkDebugPermission(
+ env, base::android::GetApplicationContext(),
+ credentials.process_id, credentials.user_id) ||
+ content::CanUserConnectToDevTools(credentials);
+}
+
class TargetBase : public content::DevToolsTarget {
public:
// content::DevToolsTarget implementation:
@@ -268,8 +276,10 @@ class NonTabTarget : public TargetBase {
// instance of this gets created each time devtools is enabled.
class DevToolsServerDelegate : public content::DevToolsHttpHandlerDelegate {
public:
- DevToolsServerDelegate()
- : last_tethering_socket_(0) {
+ explicit DevToolsServerDelegate(
+ const net::UnixDomainServerSocket::AuthCallback& auth_callback)
+ : last_tethering_socket_(0),
+ auth_callback_(auth_callback) {
}
virtual std::string GetDiscoveryPageHTML() OVERRIDE {
@@ -371,7 +381,7 @@ class DevToolsServerDelegate : public content::DevToolsHttpHandlerDelegate {
*name,
"",
delegate,
- base::Bind(&content::CanUserConnectToDevTools))
+ auth_callback_)
.PassAs<net::StreamListenSocket>();
}
@@ -385,24 +395,13 @@ class DevToolsServerDelegate : public content::DevToolsHttpHandlerDelegate {
}
int last_tethering_socket_;
+ const net::UnixDomainServerSocket::AuthCallback auth_callback_;
DISALLOW_COPY_AND_ASSIGN(DevToolsServerDelegate);
};
} // namespace
-DevToolsServer::DevToolsServer()
- : socket_name_(base::StringPrintf(kDevToolsChannelNameFormat,
- kDefaultSocketNamePrefix)),
- protocol_handler_(NULL) {
- // Override the default socket name if one is specified on the command line.
- const CommandLine& command_line = *CommandLine::ForCurrentProcess();
- if (command_line.HasSwitch(switches::kRemoteDebuggingSocketName)) {
- socket_name_ = command_line.GetSwitchValueASCII(
- switches::kRemoteDebuggingSocketName);
- }
-}
-
DevToolsServer::DevToolsServer(const std::string& socket_name_prefix)
: socket_name_(base::StringPrintf(kDevToolsChannelNameFormat,
socket_name_prefix.c_str())),
@@ -419,17 +418,22 @@ DevToolsServer::~DevToolsServer() {
Stop();
}
-void DevToolsServer::Start() {
+void DevToolsServer::Start(bool allow_debug_permission) {
if (protocol_handler_)
return;
+ net::UnixDomainServerSocket::AuthCallback auth_callback =
+ allow_debug_permission ?
+ base::Bind(&AuthorizeSocketAccessWithDebugPermission) :
+ base::Bind(&content::CanUserConnectToDevTools);
+
protocol_handler_ = content::DevToolsHttpHandler::Start(
new net::deprecated::UnixDomainListenSocketWithAbstractNamespaceFactory(
socket_name_,
base::StringPrintf("%s_%d", socket_name_.c_str(), getpid()),
- base::Bind(&content::CanUserConnectToDevTools)),
+ auth_callback),
base::StringPrintf(kFrontEndURL, content::GetWebKitRevision().c_str()),
- new DevToolsServerDelegate(),
+ new DevToolsServerDelegate(auth_callback),
base::FilePath());
}
@@ -471,10 +475,11 @@ static jboolean IsRemoteDebuggingEnabled(JNIEnv* env,
static void SetRemoteDebuggingEnabled(JNIEnv* env,
jobject obj,
jlong server,
- jboolean enabled) {
+ jboolean enabled,
+ jboolean allow_debug_permission) {
DevToolsServer* devtools_server = reinterpret_cast<DevToolsServer*>(server);
if (enabled) {
- devtools_server->Start();
+ devtools_server->Start(allow_debug_permission);
} else {
devtools_server->Stop();
}
diff --git a/chrome/browser/android/dev_tools_server.h b/chrome/browser/android/dev_tools_server.h
index 46a0870..67f5688 100644
--- a/chrome/browser/android/dev_tools_server.h
+++ b/chrome/browser/android/dev_tools_server.h
@@ -16,14 +16,11 @@ class DevToolsHttpHandler;
// This class controls Developer Tools remote debugging server.
class DevToolsServer {
public:
- // TODO(mnaganov): Remove the prefixless constructor after having its
- // usage removed in the Chrome for Android code.
- DevToolsServer();
explicit DevToolsServer(const std::string& socket_name_prefix);
~DevToolsServer();
// Opens linux abstract socket to be ready for remote debugging.
- void Start();
+ void Start(bool allow_debug_permission);
// Closes debugging socket, stops debugging.
void Stop();
diff --git a/content/browser/android/devtools_auth.cc b/content/browser/android/devtools_auth.cc
index 777a01e..46314c4 100644
--- a/content/browser/android/devtools_auth.cc
+++ b/content/browser/android/devtools_auth.cc
@@ -4,23 +4,28 @@
#include "content/public/browser/android/devtools_auth.h"
-#include <unistd.h>
+#include <pwd.h>
#include <sys/types.h>
+#include <unistd.h>
#include "base/logging.h"
namespace content {
-bool CanUserConnectToDevTools(uid_t uid, gid_t gid) {
- struct passwd* creds = getpwuid(uid);
+bool CanUserConnectToDevTools(
+ const net::UnixDomainServerSocket::Credentials& credentials) {
+ struct passwd* creds = getpwuid(credentials.user_id);
if (!creds || !creds->pw_name) {
- LOG(WARNING) << "DevTools: can't obtain creds for uid " << uid;
+ LOG(WARNING) << "DevTools: can't obtain creds for uid "
+ << credentials.user_id;
return false;
}
- if (gid == uid &&
+ if (credentials.group_id == credentials.user_id &&
(strcmp("root", creds->pw_name) == 0 || // For rooted devices
strcmp("shell", creds->pw_name) == 0 || // For non-rooted devices
- uid == getuid())) { // From processes signed with the same key
+
+ // From processes signed with the same key
+ credentials.user_id == getuid())) {
return true;
}
LOG(WARNING) << "DevTools: connection attempt from " << creds->pw_name;
diff --git a/content/public/browser/android/devtools_auth.h b/content/public/browser/android/devtools_auth.h
index 700892c..857a1a1 100644
--- a/content/public/browser/android/devtools_auth.h
+++ b/content/public/browser/android/devtools_auth.h
@@ -6,14 +6,14 @@
#define CONTENT_PUBLIC_BROWSER_DEVTOOLS_AUTH_ANDROID_H_
#include "content/common/content_export.h"
-
-#include <pwd.h>
+#include "net/socket/unix_domain_server_socket_posix.h"
namespace content {
-// Returns true if the given user/group pair is authorized to connect to the
-// devtools server, false if not.
-CONTENT_EXPORT bool CanUserConnectToDevTools(uid_t uid, gid_t gid);
+// Returns true if the given peer identified by the credentials is authorized
+// to connect to the devtools server, false if not.
+CONTENT_EXPORT bool CanUserConnectToDevTools(
+ const net::UnixDomainServerSocket::Credentials& credentials);
} // namespace content
diff --git a/net/socket/unix_domain_client_socket_posix_unittest.cc b/net/socket/unix_domain_client_socket_posix_unittest.cc
index d791122..d22aaf6 100644
--- a/net/socket/unix_domain_client_socket_posix_unittest.cc
+++ b/net/socket/unix_domain_client_socket_posix_unittest.cc
@@ -21,10 +21,14 @@ namespace {
const char kSocketFilename[] = "socket_for_testing";
-bool UserCanConnectCallback(bool allow_user, uid_t uid, gid_t gid) {
+bool UserCanConnectCallback(
+ bool allow_user, const UnixDomainServerSocket::Credentials& credentials) {
// Here peers are running in same process.
- EXPECT_EQ(getuid(), uid);
- EXPECT_EQ(getgid(), gid);
+#if defined(OS_LINUX) || defined(OS_ANDROID)
+ EXPECT_EQ(getpid(), credentials.process_id);
+#endif
+ EXPECT_EQ(getuid(), credentials.user_id);
+ EXPECT_EQ(getgid(), credentials.group_id);
return allow_user;
}
diff --git a/net/socket/unix_domain_listen_socket_posix.cc b/net/socket/unix_domain_listen_socket_posix.cc
index 7bab4ff..dc7c19c 100644
--- a/net/socket/unix_domain_listen_socket_posix.cc
+++ b/net/socket/unix_domain_listen_socket_posix.cc
@@ -113,10 +113,9 @@ void UnixDomainListenSocket::Accept() {
SocketDescriptor conn = StreamListenSocket::AcceptSocket();
if (conn == kInvalidSocket)
return;
- uid_t user_id;
- gid_t group_id;
- if (!UnixDomainServerSocket::GetPeerIds(conn, &user_id, &group_id) ||
- !auth_callback_.Run(user_id, group_id)) {
+ UnixDomainServerSocket::Credentials credentials;
+ if (!UnixDomainServerSocket::GetPeerCredentials(conn, &credentials) ||
+ !auth_callback_.Run(credentials)) {
if (IGNORE_EINTR(close(conn)) < 0)
LOG(ERROR) << "close() error";
return;
diff --git a/net/socket/unix_domain_listen_socket_posix_unittest.cc b/net/socket/unix_domain_listen_socket_posix_unittest.cc
index 5fe5017..6fcbfd5 100644
--- a/net/socket/unix_domain_listen_socket_posix_unittest.cc
+++ b/net/socket/unix_domain_listen_socket_posix_unittest.cc
@@ -138,7 +138,7 @@ class TestListenSocketDelegate : public StreamListenSocket::Delegate {
bool UserCanConnectCallback(
bool allow_user, const scoped_refptr<EventManager>& event_manager,
- uid_t, gid_t) {
+ const UnixDomainServerSocket::Credentials&) {
event_manager->Notify(
allow_user ? EVENT_AUTH_GRANTED : EVENT_AUTH_DENIED);
return allow_user;
diff --git a/net/socket/unix_domain_server_socket_posix.cc b/net/socket/unix_domain_server_socket_posix.cc
index 8f2f2d6..a81f1ce 100644
--- a/net/socket/unix_domain_server_socket_posix.cc
+++ b/net/socket/unix_domain_server_socket_posix.cc
@@ -28,19 +28,20 @@ UnixDomainServerSocket::~UnixDomainServerSocket() {
}
// static
-bool UnixDomainServerSocket::GetPeerIds(SocketDescriptor socket,
- uid_t* user_id,
- gid_t* group_id) {
+bool UnixDomainServerSocket::GetPeerCredentials(SocketDescriptor socket,
+ Credentials* credentials) {
#if defined(OS_LINUX) || defined(OS_ANDROID)
struct ucred user_cred;
socklen_t len = sizeof(user_cred);
if (getsockopt(socket, SOL_SOCKET, SO_PEERCRED, &user_cred, &len) < 0)
return false;
- *user_id = user_cred.uid;
- *group_id = user_cred.gid;
+ credentials->process_id = user_cred.pid;
+ credentials->user_id = user_cred.uid;
+ credentials->group_id = user_cred.gid;
return true;
#else
- return getpeereid(socket, user_id, group_id) == 0;
+ return getpeereid(
+ socket, &credentials->user_id, &credentials->group_id) == 0;
#endif
}
@@ -130,10 +131,9 @@ bool UnixDomainServerSocket::AuthenticateAndGetStreamSocket(
scoped_ptr<StreamSocket>* socket) {
DCHECK(accept_socket_);
- uid_t user_id;
- gid_t group_id;
- if (!GetPeerIds(accept_socket_->socket_fd(), &user_id, &group_id) ||
- !auth_callback_.Run(user_id, group_id)) {
+ Credentials credentials;
+ if (!GetPeerCredentials(accept_socket_->socket_fd(), &credentials) ||
+ !auth_callback_.Run(credentials)) {
accept_socket_.reset();
return false;
}
diff --git a/net/socket/unix_domain_server_socket_posix.h b/net/socket/unix_domain_server_socket_posix.h
index 06fb8d3..85c743d 100644
--- a/net/socket/unix_domain_server_socket_posix.h
+++ b/net/socket/unix_domain_server_socket_posix.h
@@ -25,20 +25,30 @@ class SocketLibevent;
// Linux and Android.
class NET_EXPORT UnixDomainServerSocket : public ServerSocket {
public:
+ // Credentials of a peer process connected to the socket.
+ struct NET_EXPORT Credentials {
+#if defined(OS_LINUX) || defined(OS_ANDROID)
+ // Linux/Android API provides more information about the connected peer
+ // than Windows/OS X. It's useful for permission-based authorization on
+ // Android.
+ pid_t process_id;
+#endif
+ uid_t user_id;
+ gid_t group_id;
+ };
+
// Callback that returns whether the already connected client, identified by
- // its process |user_id| and |group_id|, is allowed to keep the connection
- // open. Note that the socket is closed immediately in case the callback
- // returns false.
- typedef base::Callback<bool (uid_t user_id, gid_t group_id)> AuthCallback;
+ // its credentials, is allowed to keep the connection open. Note that
+ // the socket is closed immediately in case the callback returns false.
+ typedef base::Callback<bool (const Credentials&)> AuthCallback;
UnixDomainServerSocket(const AuthCallback& auth_callack,
bool use_abstract_namespace);
virtual ~UnixDomainServerSocket();
- // Gets UID and GID of peer to check permissions.
- static bool GetPeerIds(SocketDescriptor socket_fd,
- uid_t* user_id,
- gid_t* group_id);
+ // Gets credentials of peer to check permissions.
+ static bool GetPeerCredentials(SocketDescriptor socket_fd,
+ Credentials* credentials);
// ServerSocket implementation.
virtual int Listen(const IPEndPoint& address, int backlog) OVERRIDE;
diff --git a/net/socket/unix_domain_server_socket_posix_unittest.cc b/net/socket/unix_domain_server_socket_posix_unittest.cc
index 07209f6..d8a5281 100644
--- a/net/socket/unix_domain_server_socket_posix_unittest.cc
+++ b/net/socket/unix_domain_server_socket_posix_unittest.cc
@@ -24,10 +24,14 @@ namespace {
const char kSocketFilename[] = "socket_for_testing";
const char kInvalidSocketPath[] = "/invalid/path";
-bool UserCanConnectCallback(bool allow_user, uid_t uid, gid_t gid) {
+bool UserCanConnectCallback(bool allow_user,
+ const UnixDomainServerSocket::Credentials& credentials) {
// Here peers are running in same process.
- EXPECT_EQ(getuid(), uid);
- EXPECT_EQ(getgid(), gid);
+#if defined(OS_LINUX) || defined(OS_ANDROID)
+ EXPECT_EQ(getpid(), credentials.process_id);
+#endif
+ EXPECT_EQ(getuid(), credentials.user_id);
+ EXPECT_EQ(getgid(), credentials.group_id);
return allow_user;
}
diff --git a/remoting/host/gnubby_auth_handler_posix.cc b/remoting/host/gnubby_auth_handler_posix.cc
index f5673d3..04afc74 100644
--- a/remoting/host/gnubby_auth_handler_posix.cc
+++ b/remoting/host/gnubby_auth_handler_posix.cc
@@ -53,10 +53,10 @@ class CompareSocket {
// Socket authentication function that only allows connections from callers with
// the current uid.
-bool MatchUid(uid_t user_id, gid_t) {
- bool allowed = user_id == getuid();
+bool MatchUid(const net::UnixDomainServerSocket::Credentials& credentials) {
+ bool allowed = credentials.user_id == getuid();
if (!allowed)
- HOST_LOG << "Refused socket connection from uid " << user_id;
+ HOST_LOG << "Refused socket connection from uid " << credentials.user_id;
return allowed;
}