Skip to content

Commit

Permalink
Fix property exceptions always causing AccessDenied error
Browse files Browse the repository at this point in the history
  • Loading branch information
igo95862 committed Jun 12, 2022
1 parent f03ba02 commit 7b6a102
Show file tree
Hide file tree
Showing 3 changed files with 100 additions and 5 deletions.
9 changes: 9 additions & 0 deletions src/sdbus/sd_bus_internals.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,15 @@
new_object; \
})

#define CALL_PYTHON_GOTO_FAIL(py_function) \
({ \
PyObject* new_object = py_function; \
if (new_object == NULL) { \
goto fail; \
} \
new_object; \
})

#define PYTHON_ERR_OCCURED \
if (PyErr_Occurred()) { \
return NULL; \
Expand Down
18 changes: 13 additions & 5 deletions src/sdbus/sd_bus_internals_interface.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <systemd/sd-bus.h>
#include "sd_bus_internals.h"

// TODO: adding interface to different buses, recalculating vtable
Expand Down Expand Up @@ -413,16 +414,23 @@ static int _SdBusInterface_property_get_callback(sd_bus* Py_UNUSED(bus),
const char* property,
sd_bus_message* reply,
void* userdata,
sd_bus_error* Py_UNUSED(ret_error)) {
sd_bus_error* ret_error) {
SdBusInterfaceObject* self = userdata;
PyObject* property_name_bytes CLEANUP_PY_OBJECT = PyBytes_FromString(property);
PyObject* get_call = CALL_PYTHON_CHECK_RETURN_NEG1(PyDict_GetItem(self->property_get_dict, property_name_bytes));
PyObject* property_name_bytes CLEANUP_PY_OBJECT = NULL;
PyObject* get_call = NULL;
PyObject* new_message CLEANUP_PY_OBJECT = NULL;

PyObject* new_message CLEANUP_PY_OBJECT = CALL_PYTHON_CHECK_RETURN_NEG1(SD_BUS_PY_CLASS_DUNDER_NEW(SdBusMessage_class));
property_name_bytes = CALL_PYTHON_GOTO_FAIL(PyBytes_FromString(property));
get_call = CALL_PYTHON_GOTO_FAIL(PyDict_GetItem(self->property_get_dict, property_name_bytes));

new_message = CALL_PYTHON_GOTO_FAIL(SD_BUS_PY_CLASS_DUNDER_NEW(SdBusMessage_class));
_SdBusMessage_set_messsage((SdBusMessageObject*)new_message, reply);

Py_XDECREF(CALL_PYTHON_CHECK_RETURN_NEG1(PyObject_CallFunctionObjArgs(get_call, new_message, NULL)));
Py_XDECREF(CALL_PYTHON_GOTO_FAIL(PyObject_CallFunctionObjArgs(get_call, new_message, NULL)));
return 0;
fail:
sd_bus_error_set(ret_error, SD_BUS_ERROR_FAILED, "");
return -1;
}

static int _SdBusInterface_property_set_callback(sd_bus* Py_UNUSED(bus),
Expand Down
78 changes: 78 additions & 0 deletions test/test_low_level_errors.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
# SPDX-License-Identifier: LGPL-2.1-or-later

# Copyright (C) 2020-2022 igo95862

# This file is part of python-sdbus

# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.

# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.

# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
from __future__ import annotations

from asyncio import get_running_loop, wait_for
from typing import Any

from sdbus.unittest import IsolatedDbusTestCase

from sdbus import (
DbusFailedError,
DbusInterfaceCommonAsync,
dbus_method_async,
dbus_property_async,
request_default_bus_name_async,
)

HELLO_WORLD = 'Hello, world!'


class InterfaceWithErrors(
DbusInterfaceCommonAsync,
interface_name='org.example.test',
):
@dbus_property_async('s')
def test_str(self) -> str:
raise RuntimeError

@dbus_method_async(result_signature='s')
async def hello_error(self) -> str:
raise AttributeError

@dbus_method_async(result_signature='s')
async def hello_world(self) -> str:
return HELLO_WORLD


class TestLowLevelErrors(IsolatedDbusTestCase):
async def test_low_level_error(self) -> None:
await request_default_bus_name_async('org.test')
test_object = InterfaceWithErrors()
test_object.export_to_dbus('/')

test_object_connection = InterfaceWithErrors.new_proxy(
'org.test', '/')

loop = get_running_loop()

def silence_exceptions(*args: Any, **kwrags: Any) -> None:
...

loop.set_exception_handler(silence_exceptions)

with self.assertRaises(DbusFailedError) as cm:
await wait_for(test_object_connection.test_str.get_async(),
timeout=1)

should_be_dbus_failed = cm.exception
self.assertIs(should_be_dbus_failed.__class__, DbusFailedError)

await test_object_connection.hello_world()

0 comments on commit 7b6a102

Please sign in to comment.