zephyr/drivers/adc/adc_handlers.c
Andrew Boie 7e5b021b56 drivers: adc: fix TOCTOU attacks
The toplevel adc_seq_table is now copied onto the stack and
the stack copy used.

The contained entries array is now copied onto an allocation
drawn from the caller's resource pool, to prevent modification
of the buffer pointers.

The return value policy here is to oops the caller if bad memory
or objects are passed in, but return an error otherwise.

Based on an original patch by Leandro Pereira, rebased and the
copy of the entries array added.

Signed-off-by: Andrew Boie <andrew.p.boie@intel.com>
2018-05-17 15:08:54 -07:00

70 lines
1.6 KiB
C

/*
* Copyright (c) 2017 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <adc.h>
#include <syscall_handler.h>
#include <string.h>
Z_SYSCALL_HANDLER(adc_enable, dev)
{
Z_OOPS(Z_SYSCALL_DRIVER_ADC(dev, enable));
_impl_adc_enable((struct device *)dev);
return 0;
}
Z_SYSCALL_HANDLER(adc_disable, dev)
{
Z_OOPS(Z_SYSCALL_DRIVER_ADC(dev, disable));
_impl_adc_disable((struct device *)dev);
return 0;
}
Z_SYSCALL_HANDLER(adc_read, dev, seq_table_p)
{
struct adc_seq_entry *entry, *entries_copy;
struct adc_seq_table *seq_table = (struct adc_seq_table *)seq_table_p;
struct adc_seq_table seq_table_copy;
unsigned int entries_bounds;
int i = 0, ret;
Z_OOPS(Z_SYSCALL_DRIVER_ADC(dev, read));
Z_OOPS(Z_SYSCALL_MEMORY_READ(seq_table, sizeof(struct adc_seq_table)));
seq_table_copy = *seq_table;
if (Z_SYSCALL_VERIFY_MSG(
!__builtin_umul_overflow(seq_table_copy.num_entries,
sizeof(struct adc_seq_entry),
&entries_bounds),
"num_entries too large")) {
ret = -EINVAL;
goto out;
}
Z_OOPS(Z_SYSCALL_MEMORY_READ(seq_table_copy.entries, entries_bounds));
entries_copy = z_thread_malloc(entries_bounds);
if (!entries_copy) {
ret = -ENOMEM;
goto out;
}
memcpy(entries_copy, seq_table_copy.entries, entries_bounds);
seq_table_copy.entries = entries_copy;
for (entry = seq_table_copy.entries; i < seq_table_copy.num_entries;
i++, entry++) {
if (Z_SYSCALL_MEMORY_WRITE(entry->buffer,
entry->buffer_length)) {
k_free(entries_copy);
Z_OOPS(1);
}
}
ret = _impl_adc_read((struct device *)dev, &seq_table_copy);
k_free(entries_copy);
out:
return ret;
}