mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2025-10-29 05:40:27 -04:00
spa: use safe IO_Control parsing
The IO_Control areas are in shaed memory and need to use the parser to safely extract the info.
This commit is contained in:
parent
ede1924ded
commit
f4ab704948
4 changed files with 75 additions and 37 deletions
|
|
@ -83,6 +83,7 @@ struct port {
|
||||||
|
|
||||||
struct spa_io_buffers *io;
|
struct spa_io_buffers *io;
|
||||||
struct spa_io_sequence *io_control;
|
struct spa_io_sequence *io_control;
|
||||||
|
uint32_t io_control_size;
|
||||||
|
|
||||||
bool have_format;
|
bool have_format;
|
||||||
struct spa_audio_info current_format;
|
struct spa_audio_info current_format;
|
||||||
|
|
@ -872,6 +873,7 @@ impl_node_port_set_io(void *object,
|
||||||
break;
|
break;
|
||||||
case SPA_IO_Control:
|
case SPA_IO_Control:
|
||||||
port->io_control = data;
|
port->io_control = data;
|
||||||
|
port->io_control_size = size;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return -ENOENT;
|
return -ENOENT;
|
||||||
|
|
@ -909,16 +911,24 @@ static int impl_node_port_reuse_buffer(void *object, uint32_t port_id, uint32_t
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int process_control(struct impl *this, struct spa_pod_sequence *sequence)
|
static int process_control(struct impl *this, struct spa_pod_sequence *sequence, uint32_t size)
|
||||||
{
|
{
|
||||||
struct spa_pod_control *c;
|
struct spa_pod_parser parser;
|
||||||
|
struct spa_pod_frame frame;
|
||||||
|
struct spa_pod_sequence seq;
|
||||||
|
const void *seq_body, *c_body;
|
||||||
|
struct spa_pod_control c;
|
||||||
|
|
||||||
SPA_POD_SEQUENCE_FOREACH(sequence, c) {
|
spa_pod_parser_init_from_data(&parser, sequence, size, 0, size);
|
||||||
switch (c->type) {
|
if (spa_pod_parser_push_sequence_body(&parser, &frame, &seq, &seq_body) < 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
while (spa_pod_parser_get_control_body(&parser, &c, &c_body) >= 0) {
|
||||||
|
switch (c.type) {
|
||||||
case SPA_CONTROL_Properties:
|
case SPA_CONTROL_Properties:
|
||||||
{
|
{
|
||||||
struct props *p = &this->props;
|
struct props *p = &this->props;
|
||||||
spa_pod_parse_object(&c->value,
|
spa_pod_body_parse_object(&c.value, c_body,
|
||||||
SPA_TYPE_OBJECT_Props, NULL,
|
SPA_TYPE_OBJECT_Props, NULL,
|
||||||
SPA_PROP_frequency, SPA_POD_OPT_Float(&p->freq),
|
SPA_PROP_frequency, SPA_POD_OPT_Float(&p->freq),
|
||||||
SPA_PROP_volume, SPA_POD_OPT_Float(&p->volume));
|
SPA_PROP_volume, SPA_POD_OPT_Float(&p->volume));
|
||||||
|
|
@ -946,7 +956,7 @@ static int impl_node_process(void *object)
|
||||||
return -EIO;
|
return -EIO;
|
||||||
|
|
||||||
if (port->io_control)
|
if (port->io_control)
|
||||||
process_control(this, &port->io_control->sequence);
|
process_control(this, &port->io_control->sequence, port->io_control_size);
|
||||||
|
|
||||||
if (io->status == SPA_STATUS_HAVE_DATA)
|
if (io->status == SPA_STATUS_HAVE_DATA)
|
||||||
return SPA_STATUS_HAVE_DATA;
|
return SPA_STATUS_HAVE_DATA;
|
||||||
|
|
|
||||||
|
|
@ -85,6 +85,7 @@ struct port {
|
||||||
struct spa_port_info info = SPA_PORT_INFO_INIT();
|
struct spa_port_info info = SPA_PORT_INFO_INIT();
|
||||||
struct spa_io_buffers *io = nullptr;
|
struct spa_io_buffers *io = nullptr;
|
||||||
struct spa_io_sequence *control = nullptr;
|
struct spa_io_sequence *control = nullptr;
|
||||||
|
uint32_t control_size;
|
||||||
#define PORT_PropInfo 0
|
#define PORT_PropInfo 0
|
||||||
#define PORT_EnumFormat 1
|
#define PORT_EnumFormat 1
|
||||||
#define PORT_Meta 2
|
#define PORT_Meta 2
|
||||||
|
|
@ -895,7 +896,7 @@ int do_update_ctrls(struct spa_loop *loop,
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
spa_libcamera_set_control(struct impl *impl, const struct spa_pod_prop *prop)
|
spa_libcamera_set_control(struct impl *impl, const struct spa_pod_prop *prop, const void *body)
|
||||||
{
|
{
|
||||||
const ControlInfoMap &info = impl->camera->controls();
|
const ControlInfoMap &info = impl->camera->controls();
|
||||||
const ControlId *ctrl_id;
|
const ControlId *ctrl_id;
|
||||||
|
|
@ -918,16 +919,19 @@ spa_libcamera_set_control(struct impl *impl, const struct spa_pod_prop *prop)
|
||||||
|
|
||||||
switch (d.type) {
|
switch (d.type) {
|
||||||
case ControlTypeBool:
|
case ControlTypeBool:
|
||||||
if ((res = spa_pod_get_bool(&prop->value, &d.b_val)) < 0)
|
if (!spa_pod_is_bool(&prop->value))
|
||||||
goto done;
|
return -EINVAL;
|
||||||
|
spa_pod_body_get_bool(&prop->value, body, &d.b_val);
|
||||||
break;
|
break;
|
||||||
case ControlTypeFloat:
|
case ControlTypeFloat:
|
||||||
if ((res = spa_pod_get_float(&prop->value, &d.f_val)) < 0)
|
if (!spa_pod_is_float(&prop->value))
|
||||||
goto done;
|
return -EINVAL;
|
||||||
|
spa_pod_body_get_float(&prop->value, body, &d.f_val);
|
||||||
break;
|
break;
|
||||||
case ControlTypeInteger32:
|
case ControlTypeInteger32:
|
||||||
if ((res = spa_pod_get_int(&prop->value, &d.i_val)) < 0)
|
if (!spa_pod_is_int(&prop->value))
|
||||||
goto done;
|
return -EINVAL;
|
||||||
|
spa_pod_body_get_int(&prop->value, body, &d.i_val);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
res = -EINVAL;
|
res = -EINVAL;
|
||||||
|
|
@ -1483,7 +1487,7 @@ int impl_node_set_param(void *object,
|
||||||
impl->device_id = device;
|
impl->device_id = device;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
spa_libcamera_set_control(impl, prop);
|
spa_libcamera_set_control(impl, prop, SPA_POD_BODY_CONST(&prop->value));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1949,6 +1953,7 @@ int impl_node_port_set_io(void *object,
|
||||||
break;
|
break;
|
||||||
case SPA_IO_Control:
|
case SPA_IO_Control:
|
||||||
port->control = (struct spa_io_sequence*)data;
|
port->control = (struct spa_io_sequence*)data;
|
||||||
|
port->control_size = size;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return -ENOENT;
|
return -ENOENT;
|
||||||
|
|
@ -1976,20 +1981,31 @@ int impl_node_port_reuse_buffer(void *object,
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
int process_control(struct impl *impl, struct spa_pod_sequence *control)
|
int process_control(struct impl *impl, struct spa_pod_sequence *control, uint32_t size)
|
||||||
{
|
{
|
||||||
struct spa_pod_control *c;
|
struct spa_pod_parser parser[2];
|
||||||
|
struct spa_pod_frame frame[2];
|
||||||
|
struct spa_pod_sequence seq;
|
||||||
|
const void *seq_body, *c_body;
|
||||||
|
struct spa_pod_control c;
|
||||||
|
|
||||||
SPA_POD_SEQUENCE_FOREACH(control, c) {
|
spa_pod_parser_init_from_data(&parser[0], control, size, 0, size);
|
||||||
switch (c->type) {
|
if (spa_pod_parser_push_sequence_body(&parser[0], &frame[0], &seq, &seq_body) < 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
while (spa_pod_parser_get_control_body(&parser[0], &c, &c_body) >= 0) {
|
||||||
|
switch (c.type) {
|
||||||
case SPA_CONTROL_Properties:
|
case SPA_CONTROL_Properties:
|
||||||
{
|
{
|
||||||
const auto *obj = reinterpret_cast<spa_pod_object *>(&c->value);
|
struct spa_pod_object obj;
|
||||||
const struct spa_pod_prop *prop;
|
struct spa_pod_prop prop;
|
||||||
|
const void *obj_body, *prop_body;
|
||||||
|
|
||||||
SPA_POD_OBJECT_FOREACH(obj, prop) {
|
if (spa_pod_parser_init_object_body(&parser[1], &frame[1],
|
||||||
spa_libcamera_set_control(impl, prop);
|
&c.value, c_body, &obj, &obj_body) < 0)
|
||||||
}
|
continue;
|
||||||
|
while (spa_pod_parser_get_prop_body(&parser[1], &prop, &prop_body) >= 0)
|
||||||
|
spa_libcamera_set_control(impl, &prop, prop_body);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
|
|
@ -2014,7 +2030,7 @@ int impl_node_process(void *object)
|
||||||
return -EIO;
|
return -EIO;
|
||||||
|
|
||||||
if (port->control)
|
if (port->control)
|
||||||
process_control(impl, &port->control->sequence);
|
process_control(impl, &port->control->sequence, port->control_size);
|
||||||
|
|
||||||
spa_log_trace(impl->log, "%p; status %d", impl, io->status);
|
spa_log_trace(impl->log, "%p; status %d", impl, io->status);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -113,6 +113,7 @@ struct port {
|
||||||
struct spa_port_info info;
|
struct spa_port_info info;
|
||||||
struct spa_io_buffers *io;
|
struct spa_io_buffers *io;
|
||||||
struct spa_io_sequence *control;
|
struct spa_io_sequence *control;
|
||||||
|
uint32_t control_size;
|
||||||
#define PORT_PropInfo 0
|
#define PORT_PropInfo 0
|
||||||
#define PORT_EnumFormat 1
|
#define PORT_EnumFormat 1
|
||||||
#define PORT_Meta 2
|
#define PORT_Meta 2
|
||||||
|
|
@ -403,7 +404,7 @@ static int impl_node_set_param(void *object,
|
||||||
sizeof(p->device)-1);
|
sizeof(p->device)-1);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
spa_v4l2_set_control(this, prop->key, prop);
|
spa_v4l2_set_control(this, prop, SPA_POD_BODY_CONST(&prop->value));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -863,6 +864,7 @@ static int impl_node_port_set_io(void *object,
|
||||||
break;
|
break;
|
||||||
case SPA_IO_Control:
|
case SPA_IO_Control:
|
||||||
port->control = data;
|
port->control = data;
|
||||||
|
port->control_size = size;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return -ENOENT;
|
return -ENOENT;
|
||||||
|
|
@ -890,20 +892,31 @@ static int impl_node_port_reuse_buffer(void *object,
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int process_control(struct impl *this, struct spa_pod_sequence *control)
|
static int process_control(struct impl *this, struct spa_pod_sequence *control, uint32_t size)
|
||||||
{
|
{
|
||||||
struct spa_pod_control *c;
|
struct spa_pod_parser parser[2];
|
||||||
|
struct spa_pod_frame frame[2];
|
||||||
|
struct spa_pod_sequence seq;
|
||||||
|
const void *seq_body, *c_body;
|
||||||
|
struct spa_pod_control c;
|
||||||
|
|
||||||
SPA_POD_SEQUENCE_FOREACH(control, c) {
|
spa_pod_parser_init_from_data(&parser[0], control, size, 0, size);
|
||||||
switch (c->type) {
|
if (spa_pod_parser_push_sequence_body(&parser[0], &frame[0], &seq, &seq_body) < 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
while (spa_pod_parser_get_control_body(&parser[0], &c, &c_body) >= 0) {
|
||||||
|
switch (c.type) {
|
||||||
case SPA_CONTROL_Properties:
|
case SPA_CONTROL_Properties:
|
||||||
{
|
{
|
||||||
struct spa_pod_prop *prop;
|
struct spa_pod_object obj;
|
||||||
struct spa_pod_object *obj = (struct spa_pod_object *) &c->value;
|
struct spa_pod_prop prop;
|
||||||
|
const void *obj_body, *prop_body;
|
||||||
|
|
||||||
SPA_POD_OBJECT_FOREACH(obj, prop) {
|
if (spa_pod_parser_init_object_body(&parser[1], &frame[1],
|
||||||
spa_v4l2_set_control(this, prop->key, prop);
|
&c.value, c_body, &obj, &obj_body) < 0)
|
||||||
}
|
continue;
|
||||||
|
while (spa_pod_parser_get_prop_body(&parser[1], &prop, &prop_body) >= 0)
|
||||||
|
spa_v4l2_set_control(this, &prop, prop_body);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
|
|
@ -928,7 +941,7 @@ static int impl_node_process(void *object)
|
||||||
return -EIO;
|
return -EIO;
|
||||||
|
|
||||||
if (port->control)
|
if (port->control)
|
||||||
process_control(this, &port->control->sequence);
|
process_control(this, &port->control->sequence, port->control_size);
|
||||||
|
|
||||||
spa_log_trace(this->log, "%p; status %d", this, io->status);
|
spa_log_trace(this->log, "%p; status %d", this, io->status);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1569,8 +1569,7 @@ done:
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
spa_v4l2_set_control(struct impl *this, uint32_t id,
|
spa_v4l2_set_control(struct impl *this, const struct spa_pod_prop *prop, const void *body)
|
||||||
const struct spa_pod_prop *prop)
|
|
||||||
{
|
{
|
||||||
struct port *port = &this->out_ports[0];
|
struct port *port = &this->out_ports[0];
|
||||||
struct spa_v4l2_device *dev = &port->dev;
|
struct spa_v4l2_device *dev = &port->dev;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue