diff options
author | sleffler@chromium.org <sleffler@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-03-30 06:46:20 +0000 |
---|---|---|
committer | sleffler@chromium.org <sleffler@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-03-30 06:46:20 +0000 |
commit | e146bfcf4924815ea32b0e135d720eed26d5bade (patch) | |
tree | 2f6f69341aca38b5f2eb5ec5b0725651f4ea3c3b /dbus | |
parent | 9129b4fc22326a23a141c668e936e650801521e0 (diff) | |
download | chromium_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.gyp | 2 | ||||
-rw-r--r-- | dbus/file_descriptor.cc | 15 | ||||
-rw-r--r-- | dbus/file_descriptor.h | 59 | ||||
-rw-r--r-- | dbus/message.cc | 44 | ||||
-rw-r--r-- | dbus/message.h | 12 | ||||
-rw-r--r-- | dbus/message_unittest.cc | 34 | ||||
-rw-r--r-- | dbus/values_util.cc | 5 |
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)) { |