[gbinder] Support for file descriptors. JB#42956

gbinder_writer_append_fd() duplicates the descriptor and appends
the duplicate to the parcel. The caller may immediately close its
descriptor.

gbinder_reader_read_fd() fetches the descriptor from the parcel
without duplicating it. The descrriptor will be closed as soon as
the library has finished processing the request. Returns -1 on error.

gbinder_reader_read_dup_fd() fetches descriptor from the parcel
and dups it. The caller is responsible for closing the returned
descriptor. Returns -1 on failure.
This commit is contained in:
Slava Monich 2018-12-08 16:27:45 +02:00
parent 5a43b1b091
commit c39bf4b802
15 changed files with 673 additions and 22 deletions

View File

@ -95,6 +95,15 @@ gbinder_reader_read_double(
GBinderReader* reader, GBinderReader* reader,
gdouble* value); gdouble* value);
int
gbinder_reader_read_fd(
GBinderReader* reader); /* Since 1.0.18 */
int
gbinder_reader_read_dup_fd(
GBinderReader* reader) /* Since 1.0.18 */
G_GNUC_WARN_UNUSED_RESULT;
gboolean gboolean
gbinder_reader_read_nullable_object( gbinder_reader_read_nullable_object(
GBinderReader* reader, GBinderReader* reader,

View File

@ -114,6 +114,11 @@ gbinder_writer_append_bytes(
const void* data, const void* data,
gsize size); gsize size);
void
gbinder_writer_append_fd(
GBinderWriter* writer,
int fd); /* Since 1.0.18 */
guint guint
gbinder_writer_append_buffer_object_with_parent( gbinder_writer_append_buffer_object_with_parent(
GBinderWriter* writer, GBinderWriter* writer,

View File

@ -13,9 +13,9 @@
* 2. Redistributions in binary form must reproduce the above copyright * 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the * notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution. * documentation and/or other materials provided with the distribution.
* 3. Neither the name of Jolla Ltd nor the names of its contributors may * 3. Neither the names of the copyright holders nor the names of its
* be used to endorse or promote products derived from this software * contributors may be used to endorse or promote products derived
* without specific prior written permission. * from this software without specific prior written permission.
* *
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
@ -48,11 +48,33 @@ struct gbinder_cleanup {
G_STATIC_ASSERT(sizeof(GBinderCleanup) == sizeof(GArray)); G_STATIC_ASSERT(sizeof(GBinderCleanup) == sizeof(GArray));
#define ELEMENT_SIZE (sizeof(GBinderCleanupItem)) #define ELEMENT_SIZE (sizeof(GBinderCleanupItem))
static
void
gbinder_cleanup_destroy_func(
gpointer data)
{
GBinderCleanupItem* item = data;
item->destroy(item->pointer);
}
static static
GBinderCleanup* GBinderCleanup*
gbinder_cleanup_new() gbinder_cleanup_new()
{ {
return (GBinderCleanup*)g_array_sized_new(FALSE, FALSE, ELEMENT_SIZE, 0); GArray* array = g_array_sized_new(FALSE, FALSE, ELEMENT_SIZE, 0);
g_array_set_clear_func(array, gbinder_cleanup_destroy_func);
return (GBinderCleanup*)array;
}
void
gbinder_cleanup_reset(
GBinderCleanup* self)
{
if (G_LIKELY(self)) {
g_array_set_size((GArray*)self, 0);
}
} }
void void
@ -60,11 +82,6 @@ gbinder_cleanup_free(
GBinderCleanup* self) GBinderCleanup* self)
{ {
if (G_LIKELY(self)) { if (G_LIKELY(self)) {
guint i;
for (i = 0; i < self->count; i++) {
self->items[i].destroy(self->items[i].pointer);
}
g_array_free((GArray*)self, TRUE); g_array_free((GArray*)self, TRUE);
} }
} }

View File

@ -13,9 +13,9 @@
* 2. Redistributions in binary form must reproduce the above copyright * 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the * notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution. * documentation and/or other materials provided with the distribution.
* 3. Neither the name of Jolla Ltd nor the names of its contributors may * 3. Neither the names of the copyright holders nor the names of its
* be used to endorse or promote products derived from this software * contributors may be used to endorse or promote products derived
* without specific prior written permission. * from this software without specific prior written permission.
* *
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
@ -39,6 +39,10 @@ void
gbinder_cleanup_free( gbinder_cleanup_free(
GBinderCleanup* cleanup); GBinderCleanup* cleanup);
void
gbinder_cleanup_reset(
GBinderCleanup* cleanup);
GBinderCleanup* GBinderCleanup*
gbinder_cleanup_add( gbinder_cleanup_add(
GBinderCleanup* cleanup, GBinderCleanup* cleanup,

View File

@ -153,6 +153,21 @@ GBINDER_IO_FN(encode_remote_object)(
return sizeof(*dest); return sizeof(*dest);
} }
static
guint
GBINDER_IO_FN(encode_fd_object)(
void* out,
int fd)
{
struct flat_binder_object* dest = out;
memset(dest, 0, sizeof(*dest));
dest->hdr.type = BINDER_TYPE_FD;
dest->flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS;
dest->handle = fd;
return sizeof(*dest);
}
/* Encodes binder_buffer_object */ /* Encodes binder_buffer_object */
static static
guint guint
@ -488,6 +503,7 @@ const GBinderIo GBINDER_IO_PREFIX = {
.encode_pointer = GBINDER_IO_FN(encode_pointer), .encode_pointer = GBINDER_IO_FN(encode_pointer),
.encode_local_object = GBINDER_IO_FN(encode_local_object), .encode_local_object = GBINDER_IO_FN(encode_local_object),
.encode_remote_object = GBINDER_IO_FN(encode_remote_object), .encode_remote_object = GBINDER_IO_FN(encode_remote_object),
.encode_fd_object = GBINDER_IO_FN(encode_fd_object),
.encode_buffer_object = GBINDER_IO_FN(encode_buffer_object), .encode_buffer_object = GBINDER_IO_FN(encode_buffer_object),
.encode_death_notification = GBINDER_IO_FN(encode_death_notification), .encode_death_notification = GBINDER_IO_FN(encode_death_notification),
.encode_transaction = GBINDER_IO_FN(encode_transaction), .encode_transaction = GBINDER_IO_FN(encode_transaction),

View File

@ -131,6 +131,7 @@ struct gbinder_io {
#define GBINDER_MAX_BINDER_OBJECT_SIZE (24) #define GBINDER_MAX_BINDER_OBJECT_SIZE (24)
guint (*encode_local_object)(void* out, GBinderLocalObject* obj); guint (*encode_local_object)(void* out, GBinderLocalObject* obj);
guint (*encode_remote_object)(void* out, GBinderRemoteObject* obj); guint (*encode_remote_object)(void* out, GBinderRemoteObject* obj);
guint (*encode_fd_object)(void* out, int fd);
/* Encode binder_buffer_object */ /* Encode binder_buffer_object */
#define GBINDER_MAX_BUFFER_OBJECT_SIZE (40) #define GBINDER_MAX_BUFFER_OBJECT_SIZE (40)

View File

@ -38,6 +38,9 @@
#include <gutil_macros.h> #include <gutil_macros.h>
#include <errno.h>
#include <fcntl.h>
typedef struct gbinder_reader_priv { typedef struct gbinder_reader_priv {
const guint8* start; const guint8* start;
const guint8* end; const guint8* end;
@ -231,16 +234,67 @@ gbinder_reader_read_double(
} }
} }
static
inline
gboolean
gbinder_reader_can_read_object(
GBinderReaderPriv* p)
{
const GBinderReaderData* data = p->data;
return data && data->reg &&
p->objects && p->objects[0] &&
p->ptr == p->objects[0];
}
int
gbinder_reader_read_fd(
GBinderReader* reader) /* Since 1.0.18 */
{
GBinderReaderPriv* p = gbinder_reader_cast(reader);
if (gbinder_reader_can_read_object(p)) {
int fd;
const guint eaten = p->data->reg->io->decode_fd_object(p->ptr,
gbinder_reader_bytes_remaining(reader), &fd);
if (eaten) {
GASSERT(fd >= 0);
p->ptr += eaten;
p->objects++;
return fd;
}
}
return -1;
}
int
gbinder_reader_read_dup_fd(
GBinderReader* reader) /* Since 1.0.18 */
{
const int fd = gbinder_reader_read_fd(reader);
if (fd >= 0) {
const int dupfd = fcntl(fd, F_DUPFD_CLOEXEC, 0);
if (dupfd >= 0) {
return dupfd;
} else {
GWARN("Error dupping fd %d: %s", fd, strerror(errno));
}
}
return -1;
}
gboolean gboolean
gbinder_reader_read_nullable_object( gbinder_reader_read_nullable_object(
GBinderReader* reader, GBinderReader* reader,
GBinderRemoteObject** out) GBinderRemoteObject** out)
{ {
GBinderReaderPriv* p = gbinder_reader_cast(reader); GBinderReaderPriv* p = gbinder_reader_cast(reader);
const GBinderReaderData* data = p->data;
if (data && data->reg && p->objects && p->objects[0] && if (gbinder_reader_can_read_object(p)) {
p->ptr == p->objects[0]) { const GBinderReaderData* data = p->data;
const guint eaten = data->reg->io->decode_binder_object(p->ptr, const guint eaten = data->reg->io->decode_binder_object(p->ptr,
gbinder_reader_bytes_remaining(reader), data->reg, out); gbinder_reader_bytes_remaining(reader), data->reg, out);
@ -271,10 +325,9 @@ gbinder_reader_read_buffer_impl(
GBinderBuffer** out) GBinderBuffer** out)
{ {
GBinderReaderPriv* p = gbinder_reader_cast(reader); GBinderReaderPriv* p = gbinder_reader_cast(reader);
const GBinderReaderData* data = p->data;
if (data && data->reg && p->objects && p->objects[0] && if (gbinder_reader_can_read_object(p)) {
p->ptr == p->objects[0]) { const GBinderReaderData* data = p->data;
GBinderBuffer* buf = data->buffer; GBinderBuffer* buf = data->buffer;
const GBinderIo* io = data->reg->io; const GBinderIo* io = data->reg->io;
const gsize offset = p->ptr - (guint8*)buf->data; const gsize offset = p->ptr - (guint8*)buf->data;

View File

@ -39,7 +39,10 @@
#include <gutil_macros.h> #include <gutil_macros.h>
#include <gutil_strv.h> #include <gutil_strv.h>
#include <unistd.h>
#include <stdint.h> #include <stdint.h>
#include <errno.h>
#include <fcntl.h>
typedef struct gbinder_writer_priv { typedef struct gbinder_writer_priv {
GBinderWriterData* data; GBinderWriterData* data;
@ -74,6 +77,7 @@ gbinder_writer_data_set_contents(
g_byte_array_set_size(data->bytes, 0); g_byte_array_set_size(data->bytes, 0);
gutil_int_array_set_count(data->offsets, 0); gutil_int_array_set_count(data->offsets, 0);
data->buffers_size = 0; data->buffers_size = 0;
gbinder_cleanup_reset(data->cleanup);
g_byte_array_append(data->bytes, bufdata, bufsize); g_byte_array_append(data->bytes, bufdata, bufsize);
if (contents) { if (contents) {
@ -521,6 +525,60 @@ gbinder_writer_data_prepare(
return data->offsets->count; return data->offsets->count;
} }
static
void
gbinder_writer_data_close_fd(
gpointer data)
{
const int fd = GPOINTER_TO_INT(data);
if (close(fd) < 0) {
GWARN("Error closing fd %d: %s", fd, strerror(errno));
}
}
static
void
gbinder_writer_data_append_fd(
GBinderWriterData* data,
int fd)
{
GByteArray* buf = data->bytes;
const guint offset = buf->len;
/* Duplicate the descriptor so that caller can do whatever with
* the one it passed in. */
const int dupfd = fcntl(fd, F_DUPFD_CLOEXEC, 0);
guint written;
/* Preallocate enough space */
g_byte_array_set_size(buf, offset + GBINDER_MAX_BINDER_OBJECT_SIZE);
/* Write the original fd if we failed to dup it */
if (dupfd < 0) {
GWARN("Error dupping fd %d: %s", fd, strerror(errno));
written = data->io->encode_fd_object(buf->data + offset, fd);
} else {
written = data->io->encode_fd_object(buf->data + offset, dupfd);
data->cleanup = gbinder_cleanup_add(data->cleanup,
gbinder_writer_data_close_fd, GINT_TO_POINTER(dupfd));
}
/* Fix the data size */
g_byte_array_set_size(buf, offset + written);
/* Record the offset */
gbinder_writer_data_record_offset(data, offset);
}
void
gbinder_writer_append_fd(
GBinderWriter* self,
int fd) /* Since 1.0.18 */
{
GBinderWriterData* data = gbinder_writer_data(self);
if (G_LIKELY(data)) {
gbinder_writer_data_append_fd(data, fd);
}
}
guint guint
gbinder_writer_append_buffer_object_with_parent( gbinder_writer_append_buffer_object_with_parent(
GBinderWriter* self, GBinderWriter* self,

View File

@ -36,6 +36,9 @@
#include <glib-unix.h> #include <glib-unix.h>
#define BINDER_TRANSACTION(c2,c3,c4) GBINDER_FOURCC('_',c2,c3,c4)
#define BINDER_DUMP_TRANSACTION BINDER_TRANSACTION('D','M','P')
#define RET_OK (0) #define RET_OK (0)
#define RET_NOTFOUND (1) #define RET_NOTFOUND (1)
#define RET_INVARG (2) #define RET_INVARG (2)
@ -83,12 +86,15 @@ app_reply(
int* status, int* status,
void* user_data) void* user_data)
{ {
App* app = user_data;
GBinderReader reader;
gbinder_remote_request_init_reader(req, &reader);
if (code == GBINDER_FIRST_CALL_TRANSACTION) { if (code == GBINDER_FIRST_CALL_TRANSACTION) {
App* app = user_data;
const char* iface = gbinder_remote_request_interface(req); const char* iface = gbinder_remote_request_interface(req);
if (!g_strcmp0(iface, app->opt->iface)) { if (!g_strcmp0(iface, app->opt->iface)) {
char* str = gbinder_remote_request_read_string16(req); char* str = gbinder_reader_read_string16(&reader);
GBinderLocalReply* reply = gbinder_local_object_new_reply(obj); GBinderLocalReply* reply = gbinder_local_object_new_reply(obj);
GVERBOSE("\"%s\" %u", iface, code); GVERBOSE("\"%s\" %u", iface, code);
@ -100,6 +106,17 @@ app_reply(
} else { } else {
GDEBUG("Unexpected interface \"%s\"", iface); GDEBUG("Unexpected interface \"%s\"", iface);
} }
} else if (code == BINDER_DUMP_TRANSACTION) {
int fd = gbinder_reader_read_fd(&reader);
const char* dump = "Sorry, I've got nothing to dump...\n";
const gssize dump_len = strlen(dump);
GDEBUG("Dump request from %d", gbinder_remote_request_sender_pid(req));
if (write(fd, dump, dump_len) != dump_len) {
GERR("Failed to write dump: %s", strerror(errno));
}
*status = 0;
return NULL;
} }
*status = -1; *status = -1;
return NULL; return NULL;

View File

@ -3,6 +3,7 @@
all: all:
%: %:
@$(MAKE) -C unit_buffer $* @$(MAKE) -C unit_buffer $*
@$(MAKE) -C unit_cleanup $*
@$(MAKE) -C unit_client $* @$(MAKE) -C unit_client $*
@$(MAKE) -C unit_driver $* @$(MAKE) -C unit_driver $*
@$(MAKE) -C unit_ipc $* @$(MAKE) -C unit_ipc $*

View File

@ -5,6 +5,7 @@
TESTS="\ TESTS="\
unit_buffer \ unit_buffer \
unit_cleanup \
unit_client \ unit_client \
unit_driver \ unit_driver \
unit_ipc \ unit_ipc \

View File

@ -0,0 +1,5 @@
# -*- Mode: makefile-gmake -*-
EXE = unit_cleanup
include ../common/Makefile

View File

@ -0,0 +1,126 @@
/*
* Copyright (C) 2018 Jolla Ltd.
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the names of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "test_binder.h"
#include "gbinder_cleanup.h"
static TestOpt test_opt;
static
void
test_cleanup_inc(
gpointer data)
{
(*((int*)data))++;
}
/*==========================================================================*
* null
*==========================================================================*/
static
void
test_null(
void)
{
g_assert(!gbinder_cleanup_add(NULL, NULL, NULL));
gbinder_cleanup_free(NULL);
gbinder_cleanup_reset(NULL);
}
/*==========================================================================*
* basic
*==========================================================================*/
static
void
test_basic(
void)
{
int n1 = 0, n2 =0;
GBinderCleanup* cleanup = gbinder_cleanup_add(NULL, test_cleanup_inc, &n1);
g_assert(cleanup);
g_assert(gbinder_cleanup_add(cleanup, test_cleanup_inc, &n2) == cleanup);
gbinder_cleanup_free(cleanup);
g_assert(n1 == 1);
g_assert(n2 == 1);
}
/*==========================================================================*
* reset
*==========================================================================*/
static
void
test_reset(
void)
{
int n1 = 0, n2 =0;
GBinderCleanup* cleanup = gbinder_cleanup_add(NULL, test_cleanup_inc, &n1);
g_assert(cleanup);
g_assert(gbinder_cleanup_add(cleanup, test_cleanup_inc, &n2) == cleanup);
gbinder_cleanup_reset(cleanup);
g_assert(n1 == 1);
g_assert(n2 == 1);
gbinder_cleanup_free(cleanup);
g_assert(n1 == 1);
g_assert(n2 == 1);
}
/*==========================================================================*
* Common
*==========================================================================*/
#define TEST_PREFIX "/cleanup/"
#define TEST_(t) TEST_PREFIX t
int main(int argc, char* argv[])
{
g_test_init(&argc, &argv, NULL);
g_test_add_func(TEST_("null"), test_null);
g_test_add_func(TEST_("basic"), test_basic);
g_test_add_func(TEST_("reset"), test_reset);
test_init(&test_opt, argc, argv);
return g_test_run();
}
/*
* Local Variables:
* mode: C
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/

View File

@ -39,6 +39,9 @@
#include "gbinder_remote_object_p.h" #include "gbinder_remote_object_p.h"
#include "gbinder_io.h" #include "gbinder_io.h"
#include <unistd.h>
#include <fcntl.h>
static TestOpt test_opt; static TestOpt test_opt;
typedef struct binder_buffer_object_64 { typedef struct binder_buffer_object_64 {
@ -53,9 +56,12 @@ typedef struct binder_buffer_object_64 {
guint64 parent_offset; guint64 parent_offset;
} BinderObject64; } BinderObject64;
#define BINDER_TYPE_HANDLE GBINDER_FOURCC('s','h','*',0x85) #define BINDER_TYPE_(c1,c2,c3) GBINDER_FOURCC(c1,c2,c3,0x85)
#define BINDER_TYPE_PTR GBINDER_FOURCC('p','t','*',0x85) #define BINDER_TYPE_HANDLE BINDER_TYPE_('s','h','*')
#define BINDER_TYPE_PTR BINDER_TYPE_('p','t','*')
#define BINDER_TYPE_FD BINDER_TYPE_('f', 'd', '*')
#define BINDER_BUFFER_FLAG_HAS_PARENT 0x01 #define BINDER_BUFFER_FLAG_HAS_PARENT 0x01
#define BINDER_FLAG_ACCEPTS_FDS 0x100
#define BUFFER_OBJECT_SIZE_64 (GBINDER_MAX_BUFFER_OBJECT_SIZE) #define BUFFER_OBJECT_SIZE_64 (GBINDER_MAX_BUFFER_OBJECT_SIZE)
G_STATIC_ASSERT(sizeof(BinderObject64) == BUFFER_OBJECT_SIZE_64); G_STATIC_ASSERT(sizeof(BinderObject64) == BUFFER_OBJECT_SIZE_64);
@ -933,6 +939,256 @@ test_hidl_string_err(
gbinder_ipc_unref(ipc); gbinder_ipc_unref(ipc);
} }
/*==========================================================================*
* fd_ok
*==========================================================================*/
static
void
test_fd_ok(
void)
{
/* Using 64-bit I/O */
const int fd = fcntl(STDOUT_FILENO, F_DUPFD_CLOEXEC, 0);
const guint8 input[] = {
TEST_INT32_BYTES(BINDER_TYPE_FD),
TEST_INT32_BYTES(0x7f | BINDER_FLAG_ACCEPTS_FDS),
TEST_INT32_BYTES(fd), TEST_INT32_BYTES(0),
TEST_INT64_BYTES(0)
};
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_HWBINDER, NULL);
GBinderBuffer* buf = gbinder_buffer_new(ipc->driver,
g_memdup(input, sizeof(input)), sizeof(input), NULL);
GBinderReaderData data;
GBinderReader reader;
g_assert(ipc);
memset(&data, 0, sizeof(data));
data.buffer = buf;
data.reg = gbinder_ipc_object_registry(ipc);
data.objects = g_new(void*, 2);
data.objects[0] = buf->data;
data.objects[1] = NULL;
gbinder_reader_init(&reader, &data, 0, buf->size);
g_assert(gbinder_reader_read_fd(&reader) == fd);
gbinder_driver_close_fds(ipc->driver, data.objects,
(guint8*)buf->data + buf->size);
/* The above call must have closed the descriptor */
g_assert(close(fd) < 0);
g_free(data.objects);
gbinder_buffer_free(buf);
gbinder_ipc_unref(ipc);
}
/*==========================================================================*
* fd_shortbuf
*==========================================================================*/
static
void
test_fd_shortbuf(
void)
{
/* Using 64-bit I/O */
const guint8 input[] = {
TEST_INT32_BYTES(BINDER_TYPE_FD),
TEST_INT32_BYTES(0x7f | BINDER_FLAG_ACCEPTS_FDS)
};
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_HWBINDER, NULL);
GBinderBuffer* buf = gbinder_buffer_new(ipc->driver,
g_memdup(input, sizeof(input)), sizeof(input), NULL);
GBinderReaderData data;
GBinderReader reader;
g_assert(ipc);
memset(&data, 0, sizeof(data));
data.buffer = buf;
data.reg = gbinder_ipc_object_registry(ipc);
gbinder_reader_init(&reader, &data, 0, buf->size);
g_assert(gbinder_reader_read_fd(&reader) < 0);
gbinder_buffer_free(buf);
gbinder_ipc_unref(ipc);
}
/*==========================================================================*
* fd_badtype
*==========================================================================*/
static
void
test_fd_badtype(
void)
{
/* Using 64-bit I/O */
const int fd = fcntl(STDOUT_FILENO, F_DUPFD_CLOEXEC, 0);
const guint8 input[] = {
TEST_INT32_BYTES(BINDER_TYPE_PTR),
TEST_INT32_BYTES(0x7f | BINDER_FLAG_ACCEPTS_FDS),
TEST_INT32_BYTES(fd), TEST_INT32_BYTES(0),
TEST_INT64_BYTES(0)
};
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_HWBINDER, NULL);
GBinderBuffer* buf = gbinder_buffer_new(ipc->driver,
g_memdup(input, sizeof(input)), sizeof(input), NULL);
GBinderReaderData data;
GBinderReader reader;
g_assert(ipc);
memset(&data, 0, sizeof(data));
data.buffer = buf;
data.reg = gbinder_ipc_object_registry(ipc);
data.objects = g_new(void*, 2);
data.objects[0] = buf->data;
data.objects[1] = NULL;
gbinder_reader_init(&reader, &data, 0, buf->size);
g_assert(gbinder_reader_read_fd(&reader) < 0);
gbinder_driver_close_fds(ipc->driver, data.objects,
(guint8*)buf->data + buf->size);
/* The above call doesn't close the descriptor */
g_assert(close(fd) == 0);
g_free(data.objects);
gbinder_buffer_free(buf);
gbinder_ipc_unref(ipc);
}
/*==========================================================================*
* dupfd_ok
*==========================================================================*/
static
void
test_dupfd_ok(
void)
{
/* Using 64-bit I/O */
const int fd = fcntl(STDOUT_FILENO, F_DUPFD_CLOEXEC, 0);
const guint8 input[] = {
TEST_INT32_BYTES(BINDER_TYPE_FD),
TEST_INT32_BYTES(0x7f | BINDER_FLAG_ACCEPTS_FDS),
TEST_INT32_BYTES(fd), TEST_INT32_BYTES(0),
TEST_INT64_BYTES(0)
};
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_HWBINDER, NULL);
GBinderBuffer* buf = gbinder_buffer_new(ipc->driver,
g_memdup(input, sizeof(input)), sizeof(input), NULL);
GBinderReaderData data;
GBinderReader reader;
int fd2;
g_assert(ipc);
memset(&data, 0, sizeof(data));
data.buffer = buf;
data.reg = gbinder_ipc_object_registry(ipc);
data.objects = g_new(void*, 2);
data.objects[0] = buf->data;
data.objects[1] = NULL;
gbinder_reader_init(&reader, &data, 0, buf->size);
fd2 = gbinder_reader_read_dup_fd(&reader);
g_assert(fd2 >= 0);
g_assert(fd2 != fd);
gbinder_driver_close_fds(ipc->driver, data.objects,
(guint8*)buf->data + buf->size);
/* The above call closes fd*/
g_assert(close(fd) < 0);
g_assert(close(fd2) == 0);
g_free(data.objects);
gbinder_buffer_free(buf);
gbinder_ipc_unref(ipc);
}
/*==========================================================================*
* dupfd_badtype
*==========================================================================*/
static
void
test_dupfd_badtype(
void)
{
/* Using 64-bit I/O */
const int fd = fcntl(STDOUT_FILENO, F_DUPFD_CLOEXEC, 0);
const guint8 input[] = {
TEST_INT32_BYTES(BINDER_TYPE_PTR),
TEST_INT32_BYTES(0x7f | BINDER_FLAG_ACCEPTS_FDS),
TEST_INT32_BYTES(fd), TEST_INT32_BYTES(0),
TEST_INT64_BYTES(0)
};
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_HWBINDER, NULL);
GBinderBuffer* buf = gbinder_buffer_new(ipc->driver,
g_memdup(input, sizeof(input)), sizeof(input), NULL);
GBinderReaderData data;
GBinderReader reader;
g_assert(ipc);
memset(&data, 0, sizeof(data));
data.buffer = buf;
data.reg = gbinder_ipc_object_registry(ipc);
data.objects = g_new(void*, 2);
data.objects[0] = buf->data;
data.objects[1] = NULL;
gbinder_reader_init(&reader, &data, 0, buf->size);
g_assert(gbinder_reader_read_dup_fd(&reader) < 0);
gbinder_driver_close_fds(ipc->driver, data.objects,
(guint8*)buf->data + buf->size);
/* The above call doesn't close fd*/
g_assert(close(fd) == 0);
g_free(data.objects);
gbinder_buffer_free(buf);
gbinder_ipc_unref(ipc);
}
/*==========================================================================*
* dupfd_badfd
*==========================================================================*/
static
void
test_dupfd_badfd(
void)
{
/* Using 64-bit I/O */
const int fd = fcntl(STDOUT_FILENO, F_DUPFD_CLOEXEC, 0);
const guint8 input[] = {
TEST_INT32_BYTES(BINDER_TYPE_FD),
TEST_INT32_BYTES(0x7f | BINDER_FLAG_ACCEPTS_FDS),
TEST_INT32_BYTES(fd), TEST_INT32_BYTES(0),
TEST_INT64_BYTES(0)
};
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_HWBINDER, NULL);
GBinderBuffer* buf = gbinder_buffer_new(ipc->driver,
g_memdup(input, sizeof(input)), sizeof(input), NULL);
GBinderReaderData data;
GBinderReader reader;
g_assert(ipc);
memset(&data, 0, sizeof(data));
data.buffer = buf;
data.reg = gbinder_ipc_object_registry(ipc);
data.objects = g_new(void*, 2);
data.objects[0] = buf->data;
data.objects[1] = NULL;
gbinder_reader_init(&reader, &data, 0, buf->size);
/* Invalidate the descriptor by closing it */
g_assert(close(fd) == 0);
g_assert(gbinder_reader_read_dup_fd(&reader) < 0);
gbinder_driver_close_fds(ipc->driver, data.objects,
(guint8*)buf->data + buf->size);
g_free(data.objects);
gbinder_buffer_free(buf);
gbinder_ipc_unref(ipc);
}
/*==========================================================================* /*==========================================================================*
* object * object
*==========================================================================*/ *==========================================================================*/
@ -1294,6 +1550,12 @@ int main(int argc, char* argv[])
g_free(path); g_free(path);
} }
g_test_add_func(TEST_("fd/ok"), test_fd_ok);
g_test_add_func(TEST_("fd/shortbuf"), test_fd_shortbuf);
g_test_add_func(TEST_("fd/badtype"), test_fd_badtype);
g_test_add_func(TEST_("dupfd/ok"), test_dupfd_ok);
g_test_add_func(TEST_("dupfd/badtype"), test_dupfd_badtype);
g_test_add_func(TEST_("dupfd/badfd"), test_dupfd_badfd);
g_test_add_func(TEST_("object/valid"), test_object); g_test_add_func(TEST_("object/valid"), test_object);
g_test_add_func(TEST_("object/invalid"), test_object_invalid); g_test_add_func(TEST_("object/invalid"), test_object_invalid);
g_test_add_func(TEST_("object/no_reg"), test_object_no_reg); g_test_add_func(TEST_("object/no_reg"), test_object_no_reg);

View File

@ -39,6 +39,8 @@
#include <gutil_intarray.h> #include <gutil_intarray.h>
#include <unistd.h>
static TestOpt test_opt; static TestOpt test_opt;
#define BUFFER_OBJECT_SIZE_32 (24) #define BUFFER_OBJECT_SIZE_32 (24)
@ -77,6 +79,7 @@ test_null(
gbinder_writer_append_string16_utf16(NULL, NULL, 0); gbinder_writer_append_string16_utf16(NULL, NULL, 0);
gbinder_writer_append_bool(NULL, FALSE); gbinder_writer_append_bool(NULL, FALSE);
gbinder_writer_append_bool(&writer, FALSE); gbinder_writer_append_bool(&writer, FALSE);
gbinder_writer_append_fd(NULL, 0);
gbinder_writer_append_bytes(NULL, NULL, 0); gbinder_writer_append_bytes(NULL, NULL, 0);
gbinder_writer_append_bytes(&writer, NULL, 0); gbinder_writer_append_bytes(&writer, NULL, 0);
gbinder_writer_append_hidl_vec(NULL, NULL, 0, 0); gbinder_writer_append_hidl_vec(NULL, NULL, 0, 0);
@ -706,6 +709,76 @@ test_parent(
gbinder_local_request_unref(req); gbinder_local_request_unref(req);
} }
/*==========================================================================*
* fd
* fd_invalid
*==========================================================================*/
static
void
test_fd2(
int fd)
{
GBinderLocalRequest* req = gbinder_local_request_new(&gbinder_io_32, NULL);
GBinderOutputData* data;
GUtilIntArray* offsets;
GBinderWriter writer;
gbinder_local_request_init_writer(req, &writer);
gbinder_writer_append_fd(&writer, fd);
data = gbinder_local_request_data(req);
offsets = gbinder_output_data_offsets(data);
g_assert(offsets);
g_assert(offsets->count == 1);
g_assert(offsets->data[0] == 0);
g_assert(!gbinder_output_data_buffers_size(data));
g_assert(data->bytes->len == BINDER_OBJECT_SIZE_32);
gbinder_local_request_unref(req);
}
static
void
test_fd(
void)
{
test_fd2(0);
}
static
void
test_fd_invalid(
void)
{
test_fd2(-1);
}
/*==========================================================================*
* fd_close_error
*==========================================================================*/
static
void
test_fd_close_error(
void)
{
const GBinderIo* io = &gbinder_io_32;
GBinderLocalRequest* req = gbinder_local_request_new(io, NULL);
GBinderOutputData* data;
GBinderWriter writer;
int fd = -1;
gbinder_local_request_init_writer(req, &writer);
gbinder_writer_append_fd(&writer, STDOUT_FILENO);
data = gbinder_local_request_data(req);
g_assert(data->bytes->len == BINDER_OBJECT_SIZE_32);
/* Fetch duplicated fd and close it. That makes the second close
* done by gbinder_writer_data_close_fd() fail. */
g_assert(io->decode_fd_object(data->bytes->data, data->bytes->len, &fd));
g_assert(close(fd) == 0);
gbinder_local_request_unref(req);
}
/*==========================================================================* /*==========================================================================*
* local_object * local_object
*==========================================================================*/ *==========================================================================*/
@ -874,6 +947,9 @@ int main(int argc, char* argv[])
g_test_add_func(TEST_("buffer"), test_buffer); g_test_add_func(TEST_("buffer"), test_buffer);
g_test_add_func(TEST_("parent"), test_parent); g_test_add_func(TEST_("parent"), test_parent);
g_test_add_func(TEST_("fd"), test_fd);
g_test_add_func(TEST_("fd_invalid"), test_fd_invalid);
g_test_add_func(TEST_("fd_close_error"), test_fd_close_error);
g_test_add_func(TEST_("local_object"), test_local_object); g_test_add_func(TEST_("local_object"), test_local_object);
g_test_add_func(TEST_("remote_object"), test_remote_object); g_test_add_func(TEST_("remote_object"), test_remote_object);
g_test_add_func(TEST_("byte_array"), test_byte_array); g_test_add_func(TEST_("byte_array"), test_byte_array);