hda: use user_memcpy to read/write the user buffers.

also check buffer addresses passed through structures.

Sponsored-by:	https://liberapay.com/korli
This commit is contained in:
Jérôme Duval
2018-01-18 21:19:03 +01:00
parent 755bade8ba
commit 4f2fac067d
@@ -11,6 +11,8 @@
#include "hmulti_audio.h"
#include "driver.h"
#include <kernel.h>
#ifdef TRACE
# undef TRACE
@@ -140,12 +142,21 @@ get_description(hda_audio_group* audioGroup, multi_description* data)
static status_t
get_enabled_channels(hda_audio_group* audioGroup, multi_channel_enable* data)
{
B_SET_CHANNEL(data->enable_bits, 0, true);
B_SET_CHANNEL(data->enable_bits, 1, true);
B_SET_CHANNEL(data->enable_bits, 2, true);
B_SET_CHANNEL(data->enable_bits, 3, true);
data->lock_source = B_MULTI_LOCK_INTERNAL;
int32 inChannels = 0;
if (audioGroup->record_stream != NULL)
inChannels = 2;
int32 outChannels = 0;
if (audioGroup->playback_stream != NULL)
outChannels = 2;
uint32 enable_bits = 0;
uint32 maxChannels = min_c(32, inChannels + outChannels);
for (uint32 i = 0; i < maxChannels; i++)
B_SET_CHANNEL(&enable_bits, i, true);
return B_OK;
}
@@ -947,13 +958,18 @@ get_buffers(hda_audio_group* audioGroup, multi_buffer_list* data)
uint32 playbackSampleSize = audioGroup->playback_stream->sample_size;
for (int32 i = 0; i < data->return_playback_buffers; i++) {
struct buffer_desc descs[data->return_playback_channels];
for (int32 channelIndex = 0;
channelIndex < data->return_playback_channels; channelIndex++) {
data->playback_buffers[i][channelIndex].base
= (char*)audioGroup->playback_stream->buffers[i]
+ playbackSampleSize * channelIndex;
data->playback_buffers[i][channelIndex].stride
= playbackSampleSize * data->return_playback_channels;
descs[channelIndex].base = (char*)audioGroup->playback_stream->buffers[i]
+ playbackSampleSize * channelIndex;
descs[channelIndex].stride = playbackSampleSize
* data->return_playback_channels;
}
if (!IS_USER_ADDRESS(data->playback_buffers[i])
|| user_memcpy(data->playback_buffers[i], descs, sizeof(descs))
< B_OK) {
return B_BAD_ADDRESS;
}
}
}
@@ -962,13 +978,18 @@ get_buffers(hda_audio_group* audioGroup, multi_buffer_list* data)
uint32 recordSampleSize = audioGroup->record_stream->sample_size;
for (int32 i = 0; i < data->return_record_buffers; i++) {
struct buffer_desc descs[data->return_record_channels];
for (int32 channelIndex = 0;
channelIndex < data->return_record_channels; channelIndex++) {
data->record_buffers[i][channelIndex].base
= (char*)audioGroup->record_stream->buffers[i]
+ recordSampleSize * channelIndex;
data->record_buffers[i][channelIndex].stride
= recordSampleSize * data->return_record_channels;
descs[channelIndex].base = (char*)audioGroup->record_stream->buffers[i]
+ recordSampleSize * channelIndex;
descs[channelIndex].stride = recordSampleSize
* data->return_record_channels;
}
if (!IS_USER_ADDRESS(data->record_buffers[i])
|| user_memcpy(data->record_buffers[i], descs, sizeof(descs))
< B_OK) {
return B_BAD_ADDRESS;
}
}
}
@@ -1071,6 +1092,10 @@ buffer_force_stop(hda_audio_group* audioGroup)
}
#define cookie_type hda_audio_group
#include "../generic/multi.c"
status_t
multi_audio_control(void* cookie, uint32 op, void* arg, size_t len)
{
@@ -1083,79 +1108,5 @@ multi_audio_control(void* cookie, uint32 op, void* arg, size_t len)
audioGroup = codec->audio_groups[0];
// TODO: make userland-safe when built for Haiku!
switch (op) {
case B_MULTI_GET_DESCRIPTION:
{
#ifdef __HAIKU__
multi_description description;
multi_channel_info channels[16];
multi_channel_info* originalChannels;
if (user_memcpy(&description, arg, sizeof(multi_description))
!= B_OK)
return B_BAD_ADDRESS;
originalChannels = description.channels;
description.channels = channels;
if (description.request_channel_count > 16)
description.request_channel_count = 16;
status_t status = get_description(audioGroup, &description);
if (status != B_OK)
return status;
description.channels = originalChannels;
if (user_memcpy(arg, &description, sizeof(multi_description))
!= B_OK)
return B_BAD_ADDRESS;
return user_memcpy(originalChannels, channels,
sizeof(multi_channel_info) * description.request_channel_count);
#else
return get_description(audioGroup, (multi_description*)arg);
#endif
}
case B_MULTI_GET_ENABLED_CHANNELS:
return get_enabled_channels(audioGroup, (multi_channel_enable*)arg);
case B_MULTI_SET_ENABLED_CHANNELS:
return B_OK;
case B_MULTI_GET_GLOBAL_FORMAT:
return get_global_format(audioGroup, (multi_format_info*)arg);
case B_MULTI_SET_GLOBAL_FORMAT:
return set_global_format(audioGroup, (multi_format_info*)arg);
case B_MULTI_LIST_MIX_CHANNELS:
return list_mix_channels(audioGroup, (multi_mix_channel_info*)arg);
case B_MULTI_LIST_MIX_CONTROLS:
return list_mix_controls(audioGroup, (multi_mix_control_info*)arg);
case B_MULTI_LIST_MIX_CONNECTIONS:
return list_mix_connections(audioGroup,
(multi_mix_connection_info*)arg);
case B_MULTI_GET_MIX:
return get_mix(audioGroup, (multi_mix_value_info *)arg);
case B_MULTI_SET_MIX:
return set_mix(audioGroup, (multi_mix_value_info *)arg);
case B_MULTI_GET_BUFFERS:
return get_buffers(audioGroup, (multi_buffer_list*)arg);
case B_MULTI_BUFFER_EXCHANGE:
return buffer_exchange(audioGroup, (multi_buffer_info*)arg);
case B_MULTI_BUFFER_FORCE_STOP:
return buffer_force_stop(audioGroup);
case B_MULTI_GET_EVENT_INFO:
case B_MULTI_SET_EVENT_INFO:
case B_MULTI_GET_EVENT:
case B_MULTI_GET_CHANNEL_FORMATS:
case B_MULTI_SET_CHANNEL_FORMATS:
case B_MULTI_SET_BUFFERS:
case B_MULTI_SET_START_TIME:
return B_ERROR;
}
return B_BAD_VALUE;
return multi_audio_control_generic(audioGroup, op, arg, len);
}