summaryrefslogtreecommitdiffstats
path: root/dbus
diff options
context:
space:
mode:
authorsleffler@chromium.org <sleffler@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-03-30 06:46:20 +0000
committersleffler@chromium.org <sleffler@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-03-30 06:46:20 +0000
commite146bfcf4924815ea32b0e135d720eed26d5bade (patch)
tree2f6f69341aca38b5f2eb5ec5b0725651f4ea3c3b /dbus
parent9129b4fc22326a23a141c668e936e650801521e0 (diff)
downloadchromium_src-e146bfcf4924815ea32b0e135d720eed26d5bade.zip
chromium_src-e146bfcf4924815ea32b0e135d720eed26d5bade.tar.gz
chromium_src-e146bfcf4924815ea32b0e135d720eed26d5bade.tar.bz2
dbus: add support for passing file descriptors
Add support for passing file descriptors in messages. BUG=chromium-os:27809 TEST=run unit tests Change-Id: I48e52e52ea1e1a4b96bb0dbec7242337e5871510 Review URL: http://codereview.chromium.org/9700072 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@129801 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'dbus')
-rw-r--r--dbus/dbus.gyp2
-rw-r--r--dbus/file_descriptor.cc15
-rw-r--r--dbus/file_descriptor.h59
-rw-r--r--dbus/message.cc44
-rw-r--r--dbus/message.h12
-rw-r--r--dbus/message_unittest.cc34
-rw-r--r--dbus/values_util.cc5
7 files changed, 171 insertions, 0 deletions
diff --git a/dbus/dbus.gyp b/dbus/dbus.gyp
index bbb5e30..e7a2636 100644
--- a/dbus/dbus.gyp
+++ b/dbus/dbus.gyp
@@ -23,6 +23,8 @@
'bus.h',
'exported_object.cc',
'exported_object.h',
+ 'file_descriptor.cc',
+ 'file_descriptor.h',
'message.cc',
'message.h',
'object_path.cc',
diff --git a/dbus/file_descriptor.cc b/dbus/file_descriptor.cc
new file mode 100644
index 0000000..fc240f5
--- /dev/null
+++ b/dbus/file_descriptor.cc
@@ -0,0 +1,15 @@
+// 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.
+
+#include "base/platform_file.h"
+#include "dbus/file_descriptor.h"
+
+namespace dbus {
+
+FileDescriptor::~FileDescriptor() {
+ if (owner_)
+ base::ClosePlatformFile(value_);
+}
+
+} // namespace dbus
diff --git a/dbus/file_descriptor.h b/dbus/file_descriptor.h
new file mode 100644
index 0000000..12f1a2e
--- /dev/null
+++ b/dbus/file_descriptor.h
@@ -0,0 +1,59 @@
+// 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.
+
+#ifndef DBUS_FILE_DESCRIPTOR_H_
+#define DBUS_FILE_DESCRIPTOR_H_
+#pragma once
+
+namespace dbus {
+
+// FileDescriptor is a type used to encapsulate D-Bus file descriptors
+// and to follow the RAII idiom appropiate for use with message operations
+// where the descriptor might be easily leaked. To guard against this the
+// descriptor is closed when an instance is destroyed if it is owned.
+// Ownership is asserted only when PutValue is used and TakeValue can be
+// used to take ownership.
+//
+// For example, in the following
+// FileDescriptor fd;
+// if (!reader->PopString(&name) ||
+// !reader->PopFileDescriptor(&fd) ||
+// !reader->PopUint32(&flags)) {
+// the descriptor in fd will be closed if the PopUint32 fails. But
+// writer.AppendFileDescriptor(dbus::FileDescriptor(1));
+// will not automatically close "1" because it is not owned.
+class FileDescriptor {
+ public:
+ // Permits initialization without a value for passing to
+ // dbus::MessageReader::PopFileDescriptor to fill in and from int values.
+ FileDescriptor() : value_(-1), owner_(false) {}
+ explicit FileDescriptor(int value) : value_(value), owner_(false) {}
+
+ virtual ~FileDescriptor();
+
+ // Retrieves value as an int without affecting ownership.
+ int value() const { return value_; }
+
+ // Sets the value and assign ownership.
+ void PutValue(int value) {
+ value_ = value;
+ owner_ = true;
+ }
+
+ // Takes the value and ownership.
+ int TakeValue() {
+ owner_ = false;
+ return value_;
+ }
+
+ private:
+ int value_;
+ bool owner_;
+
+ DISALLOW_COPY_AND_ASSIGN(FileDescriptor);
+};
+
+} // namespace dbus
+
+#endif // DBUS_FILE_DESCRIPTOR_H_
diff --git a/dbus/message.cc b/dbus/message.cc
index 43fb3bb..d525912 100644
--- a/dbus/message.cc
+++ b/dbus/message.cc
@@ -9,6 +9,7 @@
#include "base/basictypes.h"
#include "base/format_macros.h"
#include "base/logging.h"
+#include "base/platform_file.h"
#include "base/stringprintf.h"
#include "dbus/object_path.h"
#include "third_party/protobuf/src/google/protobuf/message_lite.h"
@@ -199,6 +200,16 @@ std::string Message::ToStringInternal(const std::string& indent,
output += ToStringInternal(indent + " ", &sub_reader);
break;
}
+ case UNIX_FD: {
+ CHECK(kDBusTypeUnixFdIsSupported);
+
+ FileDescriptor file_descriptor;
+ if (!reader->PopFileDescriptor(&file_descriptor))
+ return kBrokenMessage;
+ output += indent + "fd#" +
+ base::StringPrintf("%d", file_descriptor.value()) + "\n";
+ break;
+ }
default:
LOG(FATAL) << "Unknown type: " << type;
}
@@ -677,6 +688,19 @@ void MessageWriter::AppendVariantOfBasic(int dbus_type, const void* value) {
CloseContainer(&variant_writer);
}
+void MessageWriter::AppendFileDescriptor(const FileDescriptor& value) {
+ CHECK(kDBusTypeUnixFdIsSupported);
+
+ base::PlatformFileInfo info;
+ int fd = value.value();
+ bool ok = base::GetPlatformFileInfo(fd, &info);
+ if (!ok || info.is_directory) {
+ // NB: sending a directory potentially enables sandbox escape
+ LOG(FATAL) << "Attempt to pass invalid file descriptor";
+ }
+ AppendBasic(DBUS_TYPE_UNIX_FD, &fd);
+}
+
//
// MessageReader implementation.
//
@@ -936,4 +960,24 @@ bool MessageReader::PopVariantOfBasic(int dbus_type, void* value) {
return variant_reader.PopBasic(dbus_type, value);
}
+bool MessageReader::PopFileDescriptor(FileDescriptor* value) {
+ CHECK(kDBusTypeUnixFdIsSupported);
+
+ int fd = -1;
+ const bool success = PopBasic(DBUS_TYPE_UNIX_FD, &fd);
+ if (!success)
+ return false;
+
+ base::PlatformFileInfo info;
+ bool ok = base::GetPlatformFileInfo(fd, &info);
+ if (!ok || info.is_directory) {
+ base::ClosePlatformFile(fd);
+ // NB: receiving a directory potentially enables sandbox escape
+ LOG(FATAL) << "Attempt to receive invalid file descriptor";
+ return false; // NB: not reached
+ }
+ value->PutValue(fd);
+ return true;
+}
+
} // namespace dbus
diff --git a/dbus/message.h b/dbus/message.h
index 3a28fb0..75e4045 100644
--- a/dbus/message.h
+++ b/dbus/message.h
@@ -11,6 +11,7 @@
#include <dbus/dbus.h>
#include "base/basictypes.h"
+#include "dbus/file_descriptor.h"
#include "dbus/object_path.h"
namespace google {
@@ -27,6 +28,14 @@ namespace dbus {
class MessageWriter;
class MessageReader;
+// DBUS_TYPE_UNIX_FD was added in D-Bus version 1.4
+#if defined(DBUS_TYPE_UNIX_FD)
+const bool kDBusTypeUnixFdIsSupported = true;
+#else
+const bool kDBusTypeUnixFdIsSupported = false;
+#define DBUS_TYPE_UNIX_FD ((int) 'h')
+#endif
+
// Message is the base class of D-Bus message types. Client code must use
// sub classes such as MethodCall and Response instead.
//
@@ -67,6 +76,7 @@ class Message {
STRUCT = DBUS_TYPE_STRUCT,
DICT_ENTRY = DBUS_TYPE_DICT_ENTRY,
VARIANT = DBUS_TYPE_VARIANT,
+ UNIX_FD = DBUS_TYPE_UNIX_FD,
};
// Returns the type of the message. Returns MESSAGE_INVALID if
@@ -268,6 +278,7 @@ class MessageWriter {
void AppendDouble(double value);
void AppendString(const std::string& value);
void AppendObjectPath(const ObjectPath& value);
+ void AppendFileDescriptor(const FileDescriptor& value);
// Opens an array. The array contents can be added to the array with
// |sub_writer|. The client code must close the array with
@@ -377,6 +388,7 @@ class MessageReader {
bool PopDouble(double* value);
bool PopString(std::string* value);
bool PopObjectPath(ObjectPath* value);
+ bool PopFileDescriptor(FileDescriptor* value);
// Sets up the given message reader to read an array at the current
// iterator position.
diff --git a/dbus/message_unittest.cc b/dbus/message_unittest.cc
index a40ba0aa..424b50a 100644
--- a/dbus/message_unittest.cc
+++ b/dbus/message_unittest.cc
@@ -5,6 +5,7 @@
#include "dbus/message.h"
#include "base/basictypes.h"
+#include "base/eintr_wrapper.h"
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
#include "dbus/object_path.h"
@@ -94,6 +95,39 @@ TEST(MessageTest, AppendAndPopBasicDataTypes) {
EXPECT_EQ(dbus::ObjectPath("/object/path"), object_path_value);
}
+// Check all basic types can be properly written and read.
+TEST(MessageTest, AppendAndPopFileDescriptor) {
+ if (!dbus::kDBusTypeUnixFdIsSupported) {
+ LOG(WARNING) << "FD passing is not supported";
+ return;
+ }
+
+ scoped_ptr<dbus::Response> message(dbus::Response::CreateEmpty());
+ dbus::MessageWriter writer(message.get());
+
+ // Append stdout.
+ dbus::FileDescriptor temp(1);
+ writer.AppendFileDescriptor(temp);
+
+ dbus::FileDescriptor fd_value;
+
+ dbus::MessageReader reader(message.get());
+ ASSERT_TRUE(reader.HasMoreData());
+ ASSERT_TRUE(reader.PopFileDescriptor(&fd_value));
+ ASSERT_FALSE(reader.HasMoreData());
+
+ // Stdout should be returned but we cannot check the descriptor
+ // value because stdout will be dup'd. Instead check st_rdev
+ // which should be identical.
+ struct stat sb_stdout;
+ int status_stdout = HANDLE_EINTR(fstat(1, &sb_stdout));
+ ASSERT_TRUE(status_stdout >= 0);
+ struct stat sb_fd;
+ int status_fd = HANDLE_EINTR(fstat(fd_value.value(), &sb_fd));
+ ASSERT_TRUE(status_fd >= 0);
+ EXPECT_EQ(sb_stdout.st_rdev, sb_fd.st_rdev);
+}
+
// Check all variant types can be properly written and read.
TEST(MessageTest, AppendAndPopVariantDataTypes) {
scoped_ptr<dbus::Response> message(dbus::Response::CreateEmpty());
diff --git a/dbus/values_util.cc b/dbus/values_util.cc
index 96cc37b3..ccd7651 100644
--- a/dbus/values_util.cc
+++ b/dbus/values_util.cc
@@ -163,6 +163,11 @@ Value* PopDataAsValue(MessageReader* reader) {
result = Value::CreateStringValue(value.value());
break;
}
+ case Message::UNIX_FD: {
+ // Cannot distinguish a file descriptor from an int
+ NOTREACHED();
+ break;
+ }
case Message::ARRAY: {
MessageReader sub_reader(NULL);
if (reader->PopArray(&sub_reader)) {