From c200367b6893e4cd85001bf10eac6fc55da89339 Mon Sep 17 00:00:00 2001 From: Leandro Pereira Date: Wed, 4 Apr 2018 13:50:32 -0700 Subject: [PATCH] drivers: Perform a runtime check if a driver is capable of an operation Driver APIs might not implement all operations, making it possible for a user thread to get the kernel to execute a function at 0x00000000. Perform runtime checks in all the driver handlers, checking if they're capable of performing the requested operation. Fixes #6907. Signed-off-by: Leandro Pereira --- CMakeLists.txt | 16 ++++++- doc/kernel/usermode/syscalls.rst | 3 ++ drivers/adc/adc_handlers.c | 17 ++++++-- drivers/aio/aio_comparator_handlers.c | 9 ++-- drivers/counter/counter_handlers.c | 14 +++--- drivers/dma/dma_handlers.c | 4 +- drivers/entropy/entropy_handlers.c | 2 +- drivers/flash/flash_handlers.c | 17 +++++--- drivers/gpio/gpio_handlers.c | 17 +++++--- drivers/i2c/i2c_handlers.c | 2 +- drivers/ipm/ipm_handlers.c | 18 +++++--- drivers/pinmux/pinmux_handlers.c | 8 ++-- drivers/pwm/pwm_handlers.c | 4 +- drivers/rtc/rtc_handlers.c | 27 +++++++++--- drivers/sensor/sensor_handlers.c | 17 +++++--- drivers/serial/uart_handlers.c | 44 ++++++++++--------- drivers/spi/spi_handlers.c | 4 +- include/kernel.h | 38 ++++------------- kernel/include/syscall_handler.h | 21 +++++++++ scripts/gen_kobject_list.py | 61 +++++++++++++++++++++------ 20 files changed, 224 insertions(+), 119 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ec11dde9bbf..8485612b6ed 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -364,6 +364,19 @@ add_custom_command(OUTPUT include/generated/syscall_dispatch.c ${syscall_list_h} DEPENDS ${syscalls_json} ) +set(DRV_VALIDATION ${PROJECT_BINARY_DIR}/include/generated/driver-validation.h) +add_custom_command( + OUTPUT ${DRV_VALIDATION} + COMMAND + ${PYTHON_EXECUTABLE} + ${ZEPHYR_BASE}/scripts/gen_kobject_list.py + --validation-output ${DRV_VALIDATION} + $<$:--verbose> + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + ) +add_custom_target(driver_validation_h_target DEPENDS ${DRV_VALIDATION}) + + # Generate offsets.c.obj from offsets.c # Generate offsets.h from offsets.c.obj @@ -376,6 +389,7 @@ target_link_libraries(offsets zephyr_interface) add_dependencies( offsets syscall_list_h_target syscall_macros_h_target + driver_validation_h_target ) add_custom_command( @@ -782,7 +796,7 @@ if(CONFIG_USERSPACE) ${PYTHON_EXECUTABLE} ${GEN_KOBJ_LIST} --kernel $ - --output ${OBJ_LIST} + --gperf-output ${OBJ_LIST} $<$:--verbose> DEPENDS zephyr_prebuilt WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} diff --git a/doc/kernel/usermode/syscalls.rst b/doc/kernel/usermode/syscalls.rst index b06cc3ebdf3..a8f2525c101 100644 --- a/doc/kernel/usermode/syscalls.rst +++ b/doc/kernel/usermode/syscalls.rst @@ -292,6 +292,9 @@ Several macros exist to validate arguments: a message parameter, instead printing the expression tested if it fails. The latter should only be used for the most obvious of tests. +* :c:macro:`_SYSCALL_DRIVER_OP()` checks at runtime if a driver + instance is capable of performing a particular operation. + If any check fails, a kernel oops will be triggered which will kill the calling thread. This is done instead of returning some error condition to keep the APIs the same when calling from supervisor mode. diff --git a/drivers/adc/adc_handlers.c b/drivers/adc/adc_handlers.c index 204d9ac8c23..79f7d4c5a72 100644 --- a/drivers/adc/adc_handlers.c +++ b/drivers/adc/adc_handlers.c @@ -7,8 +7,19 @@ #include #include -_SYSCALL_HANDLER1_SIMPLE_VOID(adc_enable, K_OBJ_DRIVER_ADC, struct device *); -_SYSCALL_HANDLER1_SIMPLE_VOID(adc_disable, K_OBJ_DRIVER_ADC, struct device *); +_SYSCALL_HANDLER(adc_enable, dev) +{ + _SYSCALL_DRIVER_ADC(dev, enable); + _impl_adc_enable((struct device *)dev); + return 0; +} + +_SYSCALL_HANDLER(adc_disable, dev) +{ + _SYSCALL_DRIVER_ADC(dev, disable); + _impl_adc_disable((struct device *)dev); + return 0; +} _SYSCALL_HANDLER(adc_read, dev, seq_table_p) { @@ -16,7 +27,7 @@ _SYSCALL_HANDLER(adc_read, dev, seq_table_p) struct adc_seq_table *seq_table = (struct adc_seq_table *)seq_table_p; int i; - _SYSCALL_OBJ(dev, K_OBJ_DRIVER_ADC); + _SYSCALL_DRIVER_ADC(dev, read); _SYSCALL_MEMORY_READ(seq_table, sizeof(struct adc_seq_table)); _SYSCALL_MEMORY_ARRAY_READ(seq_table->entries, seq_table->num_entries, sizeof(struct adc_seq_entry)); diff --git a/drivers/aio/aio_comparator_handlers.c b/drivers/aio/aio_comparator_handlers.c index e6bceff0a46..c5e7aef3c7a 100644 --- a/drivers/aio/aio_comparator_handlers.c +++ b/drivers/aio/aio_comparator_handlers.c @@ -9,9 +9,12 @@ _SYSCALL_HANDLER(aio_cmp_disable, dev, index) { - _SYSCALL_OBJ(dev, K_OBJ_DRIVER_AIO); + _SYSCALL_DRIVER_AIO_CMP(dev, disable); return _impl_aio_cmp_disable((struct device *)dev, index); } -_SYSCALL_HANDLER1_SIMPLE(aio_cmp_get_pending_int, K_OBJ_DRIVER_AIO, - struct device *); +_SYSCALL_HANDLER(aio_cmp_get_pending_int, dev) +{ + _SYSCALL_DRIVER_AIO_CMP(dev, get_pending_int); + return _impl_aio_get_pending_int((struct device *)dev, index); +} diff --git a/drivers/counter/counter_handlers.c b/drivers/counter/counter_handlers.c index 27718cfb247..3ba09ca0c03 100644 --- a/drivers/counter/counter_handlers.c +++ b/drivers/counter/counter_handlers.c @@ -11,9 +11,13 @@ * instance and return an integral value */ #define COUNTER_HANDLER(name) \ - _SYSCALL_HANDLER1_SIMPLE(name, K_OBJ_DRIVER_COUNTER, struct device *) + _SYSCALL_HANDLER(counter_ ## name, dev) \ + { \ + _SYSCALL_DRIVER_COUNTER(dev, name); \ + return _impl_counter_ ## name((struct device *)dev); \ + } -COUNTER_HANDLER(counter_get_pending_int); -COUNTER_HANDLER(counter_read); -COUNTER_HANDLER(counter_stop); -COUNTER_HANDLER(counter_start); +COUNTER_HANDLER(get_pending_int) +COUNTER_HANDLER(read) +COUNTER_HANDLER(stop) +COUNTER_HANDLER(start) diff --git a/drivers/dma/dma_handlers.c b/drivers/dma/dma_handlers.c index 8d20ed385b8..6454aa6d55e 100644 --- a/drivers/dma/dma_handlers.c +++ b/drivers/dma/dma_handlers.c @@ -13,13 +13,13 @@ _SYSCALL_HANDLER(dma_start, dev, channel) { - _SYSCALL_OBJ(dev, K_OBJ_DRIVER_DMA); + _SYSCALL_DRIVER_DMA(dev, start); return _impl_dma_start((struct device *)dev, channel); } _SYSCALL_HANDLER(dma_stop, dev, channel) { - _SYSCALL_OBJ(dev, K_OBJ_DRIVER_DMA); + _SYSCALL_DRIVER_DMA(dev, stop); return _impl_dma_stop((struct device *)dev, channel); } diff --git a/drivers/entropy/entropy_handlers.c b/drivers/entropy/entropy_handlers.c index 61070e7cd48..c1a5492d8b3 100644 --- a/drivers/entropy/entropy_handlers.c +++ b/drivers/entropy/entropy_handlers.c @@ -9,7 +9,7 @@ _SYSCALL_HANDLER(entropy_get_entropy, dev, buffer, len) { - _SYSCALL_OBJ(dev, K_OBJ_DRIVER_ENTROPY); + _SYSCALL_DRIVER_ENTROPY(dev, get_entropy); _SYSCALL_MEMORY_WRITE(buffer, len); return _impl_entropy_get_entropy((struct device *)dev, (u8_t *)buffer, len); diff --git a/drivers/flash/flash_handlers.c b/drivers/flash/flash_handlers.c index 820e9880849..d7c21298a85 100644 --- a/drivers/flash/flash_handlers.c +++ b/drivers/flash/flash_handlers.c @@ -9,7 +9,7 @@ _SYSCALL_HANDLER(flash_read, dev, offset, data, len) { - _SYSCALL_OBJ(dev, K_OBJ_DRIVER_FLASH); + _SYSCALL_DRIVER_FLASH(dev, read); _SYSCALL_MEMORY_WRITE(data, len); return _impl_flash_read((struct device *)dev, offset, (void *)data, len); @@ -17,7 +17,7 @@ _SYSCALL_HANDLER(flash_read, dev, offset, data, len) _SYSCALL_HANDLER(flash_write, dev, offset, data, len) { - _SYSCALL_OBJ(dev, K_OBJ_DRIVER_FLASH); + _SYSCALL_DRIVER_FLASH(dev, write); _SYSCALL_MEMORY_READ(data, len); return _impl_flash_write((struct device *)dev, offset, (const void *)data, len); @@ -25,7 +25,7 @@ _SYSCALL_HANDLER(flash_write, dev, offset, data, len) _SYSCALL_HANDLER(flash_write_protection_set, dev, enable) { - _SYSCALL_OBJ(dev, K_OBJ_DRIVER_FLASH); + _SYSCALL_DRIVER_FLASH(dev, write_protection); return _impl_flash_write_protection_set((struct device *)dev, enable); } @@ -35,7 +35,7 @@ _SYSCALL_HANDLER1_SIMPLE(flash_get_write_block_size, K_OBJ_DRIVER_FLASH, #ifdef CONFIG_FLASH_PAGE_LAYOUT _SYSCALL_HANDLER(flash_get_page_info_by_offs, dev, offs, info) { - _SYSCALL_OBJ(dev, K_OBJ_DRIVER_FLASH); + _SYSCALL_DRIVER_FLASH(dev, page_layout); _SYSCALL_MEMORY_WRITE(info, sizeof(struct flash_pages_info)); return _impl_flash_get_page_info_by_offs((struct device *)dev, offs, (struct flash_pages_info *)info); @@ -43,12 +43,15 @@ _SYSCALL_HANDLER(flash_get_page_info_by_offs, dev, offs, info) _SYSCALL_HANDLER(flash_get_page_info_by_idx, dev, idx, info) { - _SYSCALL_OBJ(dev, K_OBJ_DRIVER_FLASH); + _SYSCALL_DRIVER_FLASH(dev, page_layout); _SYSCALL_MEMORY_WRITE(info, sizeof(struct flash_pages_info)); return _impl_flash_get_page_info_by_idx((struct device *)dev, idx, (struct flash_pages_info *)info); } -_SYSCALL_HANDLER1_SIMPLE(flash_get_page_count, K_OBJ_DRIVER_FLASH, - struct device *); +_SYSCALL_HANDLER(flash_get_page_count, dev) +{ + _SYSCALL_DRIVER_FLASH(dev, page_layout); + return _impl_flash_get_page_count((struct device *)dev); +} #endif diff --git a/drivers/gpio/gpio_handlers.c b/drivers/gpio/gpio_handlers.c index 83cf7f69ff8..e48a9c45d9d 100644 --- a/drivers/gpio/gpio_handlers.c +++ b/drivers/gpio/gpio_handlers.c @@ -9,19 +9,19 @@ _SYSCALL_HANDLER(gpio_config, port, access_op, pin, flags) { - _SYSCALL_OBJ(port, K_OBJ_DRIVER_GPIO); + _SYSCALL_DRIVER_GPIO(port, config); return _impl_gpio_config((struct device *)port, access_op, pin, flags); } _SYSCALL_HANDLER(gpio_write, port, access_op, pin, value) { - _SYSCALL_OBJ(port, K_OBJ_DRIVER_GPIO); + _SYSCALL_DRIVER_GPIO(port, write); return _impl_gpio_write((struct device *)port, access_op, pin, value); } _SYSCALL_HANDLER(gpio_read, port, access_op, pin, value) { - _SYSCALL_OBJ(port, K_OBJ_DRIVER_GPIO); + _SYSCALL_DRIVER_GPIO(port, read); _SYSCALL_MEMORY_WRITE(value, sizeof(u32_t)); return _impl_gpio_read((struct device *)port, access_op, pin, (u32_t *)value); @@ -29,17 +29,20 @@ _SYSCALL_HANDLER(gpio_read, port, access_op, pin, value) _SYSCALL_HANDLER(gpio_enable_callback, port, access_op, pin) { - _SYSCALL_OBJ(port, K_OBJ_DRIVER_GPIO); + _SYSCALL_DRIVER_GPIO(port, enable_callback); return _impl_gpio_enable_callback((struct device *)port, access_op, pin); } _SYSCALL_HANDLER(gpio_disable_callback, port, access_op, pin) { - _SYSCALL_OBJ(port, K_OBJ_DRIVER_GPIO); + _SYSCALL_DRIVER_GPIO(port, disable_callback); return _impl_gpio_disable_callback((struct device *)port, access_op, pin); } -_SYSCALL_HANDLER1_SIMPLE(gpio_get_pending_int, K_OBJ_DRIVER_GPIO, - struct device *); +_SYSCALL_HANDLER(gpio_get_pending_int, port) +{ + _SYSCALL_DRIVER_GPIO(port, get_pending_int); + return _impl_gpio_get_pending_int((struct device *)port); +} diff --git a/drivers/i2c/i2c_handlers.c b/drivers/i2c/i2c_handlers.c index 9e6f9523495..de7068f07dc 100644 --- a/drivers/i2c/i2c_handlers.c +++ b/drivers/i2c/i2c_handlers.c @@ -10,7 +10,7 @@ _SYSCALL_HANDLER(i2c_configure, dev, dev_config) { - _SYSCALL_OBJ(dev, K_OBJ_DRIVER_I2C); + _SYSCALL_DRIVER_I2C(dev, configure); return _impl_i2c_configure((struct device *)dev, dev_config); } diff --git a/drivers/ipm/ipm_handlers.c b/drivers/ipm/ipm_handlers.c index 0ca1fe654de..75bb8f854e0 100644 --- a/drivers/ipm/ipm_handlers.c +++ b/drivers/ipm/ipm_handlers.c @@ -9,20 +9,26 @@ _SYSCALL_HANDLER(ipm_send, dev, wait, id, data, size) { - _SYSCALL_OBJ(dev, K_OBJ_DRIVER_IPM); + _SYSCALL_DRIVER_IPM(dev, send); _SYSCALL_MEMORY_READ(data, size); return _impl_ipm_send((struct device *)dev, wait, id, (const void *)data, size); } -_SYSCALL_HANDLER1_SIMPLE(ipm_max_data_size_get, K_OBJ_DRIVER_IPM, - struct device *); +_SYSCALL_HANDLER(ipm_max_data_size_get, dev) +{ + _SYSCALL_DRIVER_IPM(dev, max_data_size_get); + return _impl_max_data_size_get((struct device *)dev); +} -_SYSCALL_HANDLER1_SIMPLE(ipm_max_id_val_get, K_OBJ_DRIVER_IPM, - struct device *); +_SYSCALL_HANDLER(ipm_max_id_val_get, dev) +{ + _SYSCALL_DRIVER_IPM(dev, max_id_val_get); + return _impl_max_id_val_get((struct device *)dev); +} _SYSCALL_HANDLER(ipm_set_enabled, dev, enable) { - _SYSCALL_OBJ(dev, K_OBJ_DRIVER_IPM); + _SYSCALL_DRIVER_IPM(dev, set_enabled); return _impl_ipm_set_enabled((struct device *)dev, enable); } diff --git a/drivers/pinmux/pinmux_handlers.c b/drivers/pinmux/pinmux_handlers.c index 5d026fed228..3a2432674b1 100644 --- a/drivers/pinmux/pinmux_handlers.c +++ b/drivers/pinmux/pinmux_handlers.c @@ -10,13 +10,13 @@ _SYSCALL_HANDLER(pinmux_pin_set, dev, pin, func) { - _SYSCALL_OBJ(dev, K_OBJ_DRIVER_PINMUX); + _SYSCALL_DRIVER_PINMUX(dev, set); return _impl_pinmux_pin_set((struct device *)dev, pin, func); } _SYSCALL_HANDLER(pinmux_pin_get, dev, pin, func) { - _SYSCALL_OBJ(dev, K_OBJ_DRIVER_PINMUX); + _SYSCALL_DRIVER_PINMUX(dev, get); _SYSCALL_MEMORY_WRITE(func, sizeof(u32_t)); return _impl_pinmux_pin_get((struct device *)dev, pin, (u32_t *)func); @@ -24,12 +24,12 @@ _SYSCALL_HANDLER(pinmux_pin_get, dev, pin, func) _SYSCALL_HANDLER(pinmux_pin_pullup, dev, pin, func) { - _SYSCALL_OBJ(dev, K_OBJ_DRIVER_PINMUX); + _SYSCALL_DRIVER_PINMUX(dev, pullup); return _impl_pinmux_pin_pullup((struct device *)dev, pin, func); } _SYSCALL_HANDLER(pinmux_pin_input_enable, dev, pin, func) { - _SYSCALL_OBJ(dev, K_OBJ_DRIVER_PINMUX); + _SYSCALL_DRIVER_PINMUX(dev, input); return _impl_pinmux_pin_input_enable((struct device *)dev, pin, func); } diff --git a/drivers/pwm/pwm_handlers.c b/drivers/pwm/pwm_handlers.c index 9e3687b3dbb..5fe37de062d 100644 --- a/drivers/pwm/pwm_handlers.c +++ b/drivers/pwm/pwm_handlers.c @@ -9,14 +9,14 @@ _SYSCALL_HANDLER(pwm_pin_set_cycles, dev, pwm, period, pulse) { - _SYSCALL_OBJ(dev, K_OBJ_DRIVER_PWM); + _SYSCALL_DRIVER_PWM(dev, pin_set); return _impl_pwm_pin_set_cycles((struct device *)dev, pwm, period, pulse); } _SYSCALL_HANDLER(pwm_get_cycles_per_sec, dev, pwm, cycles) { - _SYSCALL_OBJ(dev, K_OBJ_DRIVER_PWM); + _SYSCALL_DRIVER_PWM(dev, get_cycles_per_sec); _SYSCALL_MEMORY_WRITE(cycles, sizeof(u64_t)); return _impl_pwm_get_cycles_per_sec((struct device *)dev, pwm, (u64_t *)cycles); diff --git a/drivers/rtc/rtc_handlers.c b/drivers/rtc/rtc_handlers.c index 42c140bd638..b5034d5f366 100644 --- a/drivers/rtc/rtc_handlers.c +++ b/drivers/rtc/rtc_handlers.c @@ -7,17 +7,32 @@ #include #include -_SYSCALL_HANDLER1_SIMPLE(rtc_read, K_OBJ_DRIVER_RTC, struct device *); +_SYSCALL_HANDLER(rtc_read, dev) +{ + _SYSCALL_DRIVER_RTC(dev, read); + return _impl_rtc_read((struct device *)dev); +} -_SYSCALL_HANDLER1_SIMPLE_VOID(rtc_enable, K_OBJ_DRIVER_RTC, struct device *); +_SYSCALL_HANDLER(rtc_enable, dev) +{ + _SYSCALL_DRIVER_RTC(dev, enable); + return _impl_rtc_enable((struct device *)dev); +} -_SYSCALL_HANDLER1_SIMPLE_VOID(rtc_disable, K_OBJ_DRIVER_RTC, struct device *); +_SYSCALL_HANDLER(rtc_disable, dev) +{ + _SYSCALL_DRIVER_RTC(dev, disable); + return _impl_rtc_disable((struct device *)dev); +} _SYSCALL_HANDLER(rtc_set_alarm, dev, alarm_val) { - _SYSCALL_OBJ(dev, K_OBJ_DRIVER_RTC); + _SYSCALL_DRIVER_RTC(dev, set_alarm); return _impl_rtc_set_alarm((struct device *)dev, alarm_val); } -_SYSCALL_HANDLER1_SIMPLE(rtc_get_pending_int, K_OBJ_DRIVER_RTC, - struct device *); +_SYSCALL_HANDLER(rtc_get_pending_int, dev) +{ + _SYSCALL_DRIVER_RTC(dev, get_pending_int); + return _impl_rtc_get_pending_int((struct device *)dev); +} diff --git a/drivers/sensor/sensor_handlers.c b/drivers/sensor/sensor_handlers.c index d631e5b7666..02676b34088 100644 --- a/drivers/sensor/sensor_handlers.c +++ b/drivers/sensor/sensor_handlers.c @@ -9,24 +9,27 @@ _SYSCALL_HANDLER(sensor_attr_set, dev, chan, attr, val) { - _SYSCALL_OBJ(dev, K_OBJ_DRIVER_SENSOR); + _SYSCALL_DRIVER_SENSOR(dev, attr_set); _SYSCALL_MEMORY_READ(val, sizeof(struct sensor_value)); return _impl_sensor_attr_set((struct device *)dev, chan, attr, (const struct sensor_value *)val); } -_SYSCALL_HANDLER1_SIMPLE(sensor_sample_fetch, K_OBJ_DRIVER_SENSOR, - struct device *); - -_SYSCALL_HANDLER(sensor_semple_fetch_chan, dev, type) +_SYSCALL_HANDLER(sensor_sample_sample_fetch, dev) { - _SYSCALL_OBJ(dev, K_OBJ_DRIVER_SENSOR); + _SYSCALL_DRIVER_SENSOR(dev, sample_fetch); + return _impl_sensor_sample_fetch((struct device *)dev); +} + +_SYSCALL_HANDLER(sensor_sample_fetch_chan, dev, type) +{ + _SYSCALL_DRIVER_SENSOR(dev, sample_fetch); return _impl_sensor_sample_fetch_chan((struct device *)dev, type); } _SYSCALL_HANDLER(sensor_channel_get, dev, chan, val) { - _SYSCALL_OBJ(dev, K_OBJ_DRIVER_SENSOR); + _SYSCALL_DRIVER_SENSOR(dev, channel_get); _SYSCALL_MEMORY_WRITE(val, sizeof(struct sensor_value)); return _impl_sensor_channel_get((struct device *)dev, chan, (struct sensor_value *)val); diff --git a/drivers/serial/uart_handlers.c b/drivers/serial/uart_handlers.c index a0f318f9d1f..eb9d5c8403c 100644 --- a/drivers/serial/uart_handlers.c +++ b/drivers/serial/uart_handlers.c @@ -7,18 +7,24 @@ #include #include -#define UART_SIMPLE(name_) \ - _SYSCALL_HANDLER1_SIMPLE(name_, K_OBJ_DRIVER_UART, struct device *) +#define UART_SIMPLE(op_) \ + _SYSCALL_HANDLER(uart_ ## op_, dev) { \ + _SYSCALL_DRIVER_UART(dev, op_); \ + return _impl_uart_ ## op_((struct device *)dev); \ + } -#define UART_SIMPLE_VOID(name_) \ - _SYSCALL_HANDLER1_SIMPLE_VOID(name_, K_OBJ_DRIVER_UART, \ - struct device *) +#define UART_SIMPLE_VOID(op_) \ + _SYSCALL_HANDLER(uart_ ## op_, dev) { \ + _SYSCALL_DRIVER_UART(dev, op_); \ + _impl_uart_ ## op_((struct device *)dev); \ + return 0; \ + } -UART_SIMPLE(uart_err_check); +UART_SIMPLE(err_check) _SYSCALL_HANDLER(uart_poll_in, dev, p_char) { - _SYSCALL_OBJ(dev, K_OBJ_DRIVER_UART); + _SYSCALL_DRIVER_UART(dev, poll_in); _SYSCALL_MEMORY_WRITE(p_char, sizeof(unsigned char)); return _impl_uart_poll_in((struct device *)dev, (unsigned char *)p_char); @@ -26,31 +32,31 @@ _SYSCALL_HANDLER(uart_poll_in, dev, p_char) _SYSCALL_HANDLER(uart_poll_out, dev, out_char) { - _SYSCALL_OBJ(dev, K_OBJ_DRIVER_UART); + _SYSCALL_DRIVER_UART(dev, poll_out); return _impl_uart_poll_out((struct device *)dev, out_char); } #ifdef CONFIG_UART_INTERRUPT_DRIVEN -UART_SIMPLE_VOID(uart_irq_tx_enable); -UART_SIMPLE_VOID(uart_irq_tx_disable); -UART_SIMPLE_VOID(uart_irq_rx_enable); -UART_SIMPLE_VOID(uart_irq_rx_disable); -UART_SIMPLE_VOID(uart_irq_err_enable); -UART_SIMPLE_VOID(uart_irq_err_disable); -UART_SIMPLE(uart_irq_is_pending); -UART_SIMPLE(uart_irq_update); +UART_SIMPLE_VOID(irq_tx_enable) +UART_SIMPLE_VOID(irq_tx_disable) +UART_SIMPLE_VOID(irq_rx_enable) +UART_SIMPLE_VOID(irq_rx_disable) +UART_SIMPLE_VOID(irq_err_enable) +UART_SIMPLE_VOID(irq_err_disable) +UART_SIMPLE(irq_is_pending) +UART_SIMPLE(irq_update) #endif /* CONFIG_UART_INTERRUPT_DRIVEN */ #ifdef CONFIG_UART_LINE_CTRL _SYSCALL_HANDLER(uart_line_ctrl_set, dev, ctrl, val) { - _SYSCALL_OBJ(dev, K_OBJ_DRIVER_UART); + _SYSCALL_DRIVER_UART(dev, line_ctrl_set); return _impl_uart_line_ctrl_set((struct device *)dev, ctrl, val); } _SYSCALL_HANDLER(uart_line_ctrl_get, dev, ctrl, val); { - _SYSCALL_OBJ(dev, K_OBJ_DRIVER_UART); + _SYSCALL_DRIVER_UART(dev, line_ctrl_get); _SYSCALL_MEMORY_WRITE(val, sizeof(u32_t)); return _impl_uart_line_ctrl_get((struct device *)dev, ctrl, (u32_t *)val); @@ -60,7 +66,7 @@ _SYSCALL_HANDLER(uart_line_ctrl_get, dev, ctrl, val); #ifdef CONFIG_UART_DRV_CMD _SYSCALL_HANDLER(uart_drv_cmd, dev, cmd, p) { - _SYSCALL_OBJ(dev, K_OBJ_DRIVER_UART); + _SYSCALL_DRIVER_UART(dev, drv_cmd); return _impl_uart_drv_cmd((struct device *)dev, cmd, p); } #endif /* CONFIG_UART_DRV_CMD */ diff --git a/drivers/spi/spi_handlers.c b/drivers/spi/spi_handlers.c index 92ad80a3c26..979bcd479e3 100644 --- a/drivers/spi/spi_handlers.c +++ b/drivers/spi/spi_handlers.c @@ -31,7 +31,7 @@ _SYSCALL_HANDLER(spi_transceive, dev, config_p, tx_bufs, rx_bufs) const struct spi_config *config = (const struct spi_config *)config_p; _SYSCALL_MEMORY_READ(config, sizeof(*config)); - _SYSCALL_OBJ(dev, K_OBJ_DRIVER_SPI); + _SYSCALL_DRIVER_SPI(dev, transceive); /* ssf is implicit system call stack frame parameter, used by * _SYSCALL_* APIs when something goes wrong. @@ -71,6 +71,6 @@ _SYSCALL_HANDLER(spi_release, dev, config_p) const struct spi_config *config = (const struct spi_config *)config_p; _SYSCALL_MEMORY_READ(config, sizeof(*config)); - _SYSCALL_OBJ(dev, K_OBJ_DRIVER_SPI); + _SYSCALL_DRIVER_SPI(dev, release); return _impl_spi_release((struct device *)dev, config); } diff --git a/include/kernel.h b/include/kernel.h index 2bfee10d88b..b38375cecdd 100644 --- a/include/kernel.h +++ b/include/kernel.h @@ -135,35 +135,15 @@ struct k_mem_partition; enum k_objects { K_OBJ_ANY, - /* Core kernel objects */ - K_OBJ_ALERT, - K_OBJ_MSGQ, - K_OBJ_MUTEX, - K_OBJ_PIPE, - K_OBJ_SEM, - K_OBJ_STACK, - K_OBJ_THREAD, - K_OBJ_TIMER, - K_OBJ__THREAD_STACK_ELEMENT, - - /* Driver subsystems */ - K_OBJ_DRIVER_ADC, - K_OBJ_DRIVER_AIO_CMP, - K_OBJ_DRIVER_COUNTER, - K_OBJ_DRIVER_CRYPTO, - K_OBJ_DRIVER_DMA, - K_OBJ_DRIVER_FLASH, - K_OBJ_DRIVER_GPIO, - K_OBJ_DRIVER_I2C, - K_OBJ_DRIVER_I2S, - K_OBJ_DRIVER_IPM, - K_OBJ_DRIVER_PINMUX, - K_OBJ_DRIVER_PWM, - K_OBJ_DRIVER_ENTROPY, - K_OBJ_DRIVER_RTC, - K_OBJ_DRIVER_SENSOR, - K_OBJ_DRIVER_SPI, - K_OBJ_DRIVER_UART, + /** @cond + * Doxygen should ignore this build-time generated include file + * when genrating API documentation. Enumeration values are + * generated during build by gen_kobject_list.py. It includes + * basic kernel objects (e.g. pipes and mutexes) and driver types. + */ +#include + /** @endcond + */ K_OBJ_LAST }; diff --git a/kernel/include/syscall_handler.h b/kernel/include/syscall_handler.h index 8f4cb37179e..33ae31eead2 100644 --- a/kernel/include/syscall_handler.h +++ b/kernel/include/syscall_handler.h @@ -261,6 +261,25 @@ static inline int _obj_validation_check(struct _k_object *ko, !_obj_validation_check(_k_object_find((void *)ptr), (void *)ptr, \ type, init), "access denied") +/** + * @brief Runtime check driver object pointer for presence of operation + * + * Validates if the driver object is capable of performing a certain operation. + * + * @param ptr Untrusted device instance object pointer + * @param api_struct Name of the driver API struct (e.g. gpio_driver_api) + * @param op Driver operation (e.g. manage_callback) + */ +#define _SYSCALL_DRIVER_OP(ptr, api_name, op) \ + do { \ + struct api_name *__device__ = (struct api_name *) \ + ((struct device *)ptr)->driver_api; \ + _SYSCALL_VERIFY_MSG(__device__->op != NULL, \ + "Operation %s not defined for driver " \ + "instance %p", \ + # op, __device__); \ + } while (0) + /** * @brief Runtime check kernel object pointer for non-init functions * @@ -425,6 +444,8 @@ static inline int _obj_validation_check(struct _k_object *ko, return 0; \ } +#include + #endif /* _ASMLANGUAGE */ #endif /* CONFIG_USERSPACE */ diff --git a/scripts/gen_kobject_list.py b/scripts/gen_kobject_list.py index fbb44ee83f8..559b2f0f09b 100755 --- a/scripts/gen_kobject_list.py +++ b/scripts/gen_kobject_list.py @@ -117,6 +117,30 @@ def write_gperf_table(fp, eh, objs, static_begin, static_end): fp.write(footer) +driver_macro_tpl = """ +#define _SYSCALL_DRIVER_%(driver_upper)s(ptr, op) _SYSCALL_DRIVER_GEN(ptr, op, %(driver_lower)s, %(driver_upper)s) +""" + +def write_validation_output(fp): + fp.write("#ifndef __DRIVER_VALIDATION_GEN_H__\n") + fp.write("#define __DRIVER_VALIDATION_GEN_H__\n") + + fp.write("""#define _SYSCALL_DRIVER_GEN(ptr, op, driver_lower_case, driver_upper_case) \\ + do { \\ + _SYSCALL_OBJ(ptr, K_OBJ_DRIVER_##driver_upper_case); \\ + _SYSCALL_DRIVER_OP(ptr, driver_lower_case##_driver_api, op); \\ + } while (0)\n\n"""); + + for subsystem in subsystems: + subsystem = subsystem.replace("_driver_api", "") + + fp.write(driver_macro_tpl % { + "driver_lower": subsystem.lower(), + "driver_upper": subsystem.upper(), + }) + + fp.write("#endif /* __DRIVER_VALIDATION_GEN_H__ */\n") + def parse_args(): global args @@ -124,11 +148,14 @@ def parse_args(): description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter) - parser.add_argument("-k", "--kernel", required=True, + parser.add_argument("-k", "--kernel", required=False, help="Input zephyr ELF binary") parser.add_argument( - "-o", "--output", required=True, + "-g", "--gperf-output", required=False, help="Output list of kernel object addresses for gperf use") + parser.add_argument( + "-V", "--validation-output", required=False, + help="Output driver validation macros") parser.add_argument("-v", "--verbose", action="store_true", help="Print extra debugging information") args = parser.parse_args() @@ -139,20 +166,26 @@ def parse_args(): def main(): parse_args() - eh = ElfHelper(args.kernel, args.verbose, kobjects, subsystems) - syms = eh.get_symbols() - max_threads = syms["CONFIG_MAX_THREAD_BYTES"] * 8 - objs = eh.find_kobjects(syms) + if args.gperf_output: + eh = ElfHelper(args.kernel, args.verbose, kobjects, subsystems) + syms = eh.get_symbols() + max_threads = syms["CONFIG_MAX_THREAD_BYTES"] * 8 + objs = eh.find_kobjects(syms) - if eh.get_thread_counter() > max_threads: - sys.stderr.write("Too many thread objects (%d)\n" % thread_counter) - sys.stderr.write("Increase CONFIG_MAX_THREAD_BYTES to %d\n", - -(-thread_counter // 8)) - sys.exit(1) + if eh.get_thread_counter() > max_threads: + sys.stderr.write("Too many thread objects (%d)\n" % thread_counter) + sys.stderr.write("Increase CONFIG_MAX_THREAD_BYTES to %d\n", + -(-thread_counter // 8)) + sys.exit(1) - with open(args.output, "w") as fp: - write_gperf_table(fp, eh, objs, syms["_static_kernel_objects_begin"], - syms["_static_kernel_objects_end"]) + with open(args.gperf_output, "w") as fp: + write_gperf_table(fp, eh, objs, + syms["_static_kernel_objects_begin"], + syms["_static_kernel_objects_end"]) + + if args.validation_output: + with open(args.validation_output, "w") as fp: + write_validation_output(fp) if __name__ == "__main__":