[libvirt] [PATCH v3 00/11] remove repetition of URI path validation

This is a code repetition that I crossed a few times, then I noticed that Cole Robinson suggested a solution for it in the wiki. Here it is. changes from v2: - use a boolean to determine 'QEMU' and 'vbox' case to avoid block repetition (patch 8) - avoid 80+ chars lines in all patches changes from v1: - handle QEMU and vbox cases separately inside the validation function v2: https://www.redhat.com/archives/libvir-list/2019-September/msg01007.html v1: https://www.redhat.com/archives/libvir-list/2019-September/msg00983.html Daniel Henrique Barboza (11): src/driver.c: add virConnectValidateURIPath() interface_backend_netcf.c: use virConnectValidateURIPath() interface_backend_udev.c: use virConnectValidateURIPath() bridge_driver.c: virConnectValidateURIPath() node_device_driver.c: use virConnectValidateURIPath() secret_driver.c: use virConnectValidateURIPath() storage_driver.c: use virConnectValidateURIPath() driver.c: change URI validation to handle QEMU and vbox case qemu_driver.c: use virConnectValidateURIPath() vbox_common.c: use virConnectValidateURIPath() vbox_driver.c: use virConnectValidateURIPath() src/driver.c | 38 +++++++++++++++++++++++++ src/driver.h | 4 +++ src/interface/interface_backend_netcf.c | 19 +++---------- src/interface/interface_backend_udev.c | 19 +++---------- src/libvirt_private.syms | 1 + src/network/bridge_driver.c | 19 +++---------- src/node_device/node_device_driver.c | 19 +++---------- src/qemu/qemu_driver.c | 20 +++---------- src/secret/secret_driver.c | 19 +++---------- src/storage/storage_driver.c | 19 +++---------- src/vbox/vbox_common.c | 16 ++--------- src/vbox/vbox_driver.c | 16 ++--------- 12 files changed, 75 insertions(+), 134 deletions(-) -- 2.21.0

The code to validate the URI path is repeated across several files. This patch creates a common validation code to be used across all of them. Suggested-by: Cole Robinson <crobinso@redhat.com> Signed-off-by: Daniel Henrique Barboza <danielhb413@gmail.com> --- src/driver.c | 24 ++++++++++++++++++++++++ src/driver.h | 4 ++++ src/libvirt_private.syms | 1 + 3 files changed, 29 insertions(+) diff --git a/src/driver.c b/src/driver.c index 5e8f68f6df..e627b0c1d7 100644 --- a/src/driver.c +++ b/src/driver.c @@ -269,3 +269,27 @@ virSetConnectStorage(virConnectPtr conn) VIR_DEBUG("Override storage connection with %p", conn); return virThreadLocalSet(&connectStorage, conn); } + +bool +virConnectValidateURIPath(const char *uriPath, + const char *entityName, + bool privileged) +{ + if (privileged) { + if (STRNEQ(uriPath, "/system")) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("unexpected %s URI path '%s', try %s:///system"), + entityName, uriPath, entityName); + return false; + } + } else { + if (STRNEQ(uriPath, "/session")) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("unexpected %s URI path '%s', try %s:///session"), + entityName, uriPath, entityName); + return false; + } + } + + return true; +} diff --git a/src/driver.h b/src/driver.h index f7d667a03c..68c0004d86 100644 --- a/src/driver.h +++ b/src/driver.h @@ -127,3 +127,7 @@ int virSetConnectNWFilter(virConnectPtr conn); int virSetConnectNodeDev(virConnectPtr conn); int virSetConnectSecret(virConnectPtr conn); int virSetConnectStorage(virConnectPtr conn); + +bool virConnectValidateURIPath(const char *uriPath, + const char *entityName, + bool privileged); diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 39812227aa..eb9c5c22ee 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -1343,6 +1343,7 @@ virStreamClass; # driver.h +virConnectValidateURIPath; virGetConnectInterface; virGetConnectNetwork; virGetConnectNodeDev; -- 2.21.0

Suggested-by: Cole Robinson <crobinso@redhat.com> Signed-off-by: Daniel Henrique Barboza <danielhb413@gmail.com> --- src/interface/interface_backend_netcf.c | 19 ++++--------------- 1 file changed, 4 insertions(+), 15 deletions(-) diff --git a/src/interface/interface_backend_netcf.c b/src/interface/interface_backend_netcf.c index 9659e9fcf1..5ef8ac33db 100644 --- a/src/interface/interface_backend_netcf.c +++ b/src/interface/interface_backend_netcf.c @@ -200,21 +200,10 @@ netcfConnectOpen(virConnectPtr conn, return VIR_DRV_OPEN_ERROR; } - if (driver->privileged) { - if (STRNEQ(conn->uri->path, "/system")) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("unexpected interface URI path '%s', try interface:///system"), - conn->uri->path); - return VIR_DRV_OPEN_ERROR; - } - } else { - if (STRNEQ(conn->uri->path, "/session")) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("unexpected interface URI path '%s', try interface:///session"), - conn->uri->path); - return VIR_DRV_OPEN_ERROR; - } - } + if (!virConnectValidateURIPath(conn->uri->path, + "interface", + driver->privileged)) + return VIR_DRV_OPEN_ERROR; if (virConnectOpenEnsureACL(conn) < 0) return VIR_DRV_OPEN_ERROR; -- 2.21.0

Suggested-by: Cole Robinson <crobinso@redhat.com> Signed-off-by: Daniel Henrique Barboza <danielhb413@gmail.com> --- src/interface/interface_backend_udev.c | 19 ++++--------------- 1 file changed, 4 insertions(+), 15 deletions(-) diff --git a/src/interface/interface_backend_udev.c b/src/interface/interface_backend_udev.c index ddc3de5347..1684b8ed83 100644 --- a/src/interface/interface_backend_udev.c +++ b/src/interface/interface_backend_udev.c @@ -1250,21 +1250,10 @@ udevConnectOpen(virConnectPtr conn, return VIR_DRV_OPEN_ERROR; } - if (driver->privileged) { - if (STRNEQ(conn->uri->path, "/system")) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("unexpected interface URI path '%s', try interface:///system"), - conn->uri->path); - return VIR_DRV_OPEN_ERROR; - } - } else { - if (STRNEQ(conn->uri->path, "/session")) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("unexpected interface URI path '%s', try interface:///session"), - conn->uri->path); - return VIR_DRV_OPEN_ERROR; - } - } + if (!virConnectValidateURIPath(conn->uri->path, + "interface", + driver->privileged)) + return VIR_DRV_OPEN_ERROR; if (virConnectOpenEnsureACL(conn) < 0) return VIR_DRV_OPEN_ERROR; -- 2.21.0

Suggested-by: Cole Robinson <crobinso@redhat.com> Signed-off-by: Daniel Henrique Barboza <danielhb413@gmail.com> --- src/network/bridge_driver.c | 19 ++++--------------- 1 file changed, 4 insertions(+), 15 deletions(-) diff --git a/src/network/bridge_driver.c b/src/network/bridge_driver.c index c54be96407..c617bbb58f 100644 --- a/src/network/bridge_driver.c +++ b/src/network/bridge_driver.c @@ -938,21 +938,10 @@ networkConnectOpen(virConnectPtr conn, return VIR_DRV_OPEN_ERROR; } - if (network_driver->privileged) { - if (STRNEQ(conn->uri->path, "/system")) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("unexpected network URI path '%s', try network:///system"), - conn->uri->path); - return VIR_DRV_OPEN_ERROR; - } - } else { - if (STRNEQ(conn->uri->path, "/session")) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("unexpected network URI path '%s', try network:///session"), - conn->uri->path); - return VIR_DRV_OPEN_ERROR; - } - } + if (!virConnectValidateURIPath(conn->uri->path, + "network", + network_driver->privileged)) + return VIR_DRV_OPEN_ERROR; if (virConnectOpenEnsureACL(conn) < 0) return VIR_DRV_OPEN_ERROR; -- 2.21.0

Suggested-by: Cole Robinson <crobinso@redhat.com> Signed-off-by: Daniel Henrique Barboza <danielhb413@gmail.com> --- src/node_device/node_device_driver.c | 19 ++++--------------- 1 file changed, 4 insertions(+), 15 deletions(-) diff --git a/src/node_device/node_device_driver.c b/src/node_device/node_device_driver.c index 8fb00d0c86..578489c5be 100644 --- a/src/node_device/node_device_driver.c +++ b/src/node_device/node_device_driver.c @@ -58,21 +58,10 @@ nodeConnectOpen(virConnectPtr conn, return VIR_DRV_OPEN_ERROR; } - if (driver->privileged) { - if (STRNEQ(conn->uri->path, "/system")) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("unexpected nodedev URI path '%s', try nodedev:///system"), - conn->uri->path); - return VIR_DRV_OPEN_ERROR; - } - } else { - if (STRNEQ(conn->uri->path, "/session")) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("unexpected nodedev URI path '%s', try nodedev:///session"), - conn->uri->path); - return VIR_DRV_OPEN_ERROR; - } - } + if (!virConnectValidateURIPath(conn->uri->path, + "nodedev", + driver->privileged)) + return VIR_DRV_OPEN_ERROR; if (virConnectOpenEnsureACL(conn) < 0) return VIR_DRV_OPEN_ERROR; -- 2.21.0

Suggested-by: Cole Robinson <crobinso@redhat.com> Signed-off-by: Daniel Henrique Barboza <danielhb413@gmail.com> --- src/secret/secret_driver.c | 19 ++++--------------- 1 file changed, 4 insertions(+), 15 deletions(-) diff --git a/src/secret/secret_driver.c b/src/secret/secret_driver.c index 7512a51c74..ed3bd3c751 100644 --- a/src/secret/secret_driver.c +++ b/src/secret/secret_driver.c @@ -552,21 +552,10 @@ secretConnectOpen(virConnectPtr conn, return VIR_DRV_OPEN_ERROR; } - if (driver->privileged) { - if (STRNEQ(conn->uri->path, "/system")) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("unexpected secret URI path '%s', try secret:///system"), - conn->uri->path); - return VIR_DRV_OPEN_ERROR; - } - } else { - if (STRNEQ(conn->uri->path, "/session")) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("unexpected secret URI path '%s', try secret:///session"), - conn->uri->path); - return VIR_DRV_OPEN_ERROR; - } - } + if (!virConnectValidateURIPath(conn->uri->path, + "secret", + driver->privileged)) + return VIR_DRV_OPEN_ERROR; if (virConnectOpenEnsureACL(conn) < 0) return VIR_DRV_OPEN_ERROR; -- 2.21.0

Suggested-by: Cole Robinson <crobinso@redhat.com> Signed-off-by: Daniel Henrique Barboza <danielhb413@gmail.com> --- src/storage/storage_driver.c | 19 ++++--------------- 1 file changed, 4 insertions(+), 15 deletions(-) diff --git a/src/storage/storage_driver.c b/src/storage/storage_driver.c index ce10b55ed0..d160ff34fe 100644 --- a/src/storage/storage_driver.c +++ b/src/storage/storage_driver.c @@ -411,21 +411,10 @@ storageConnectOpen(virConnectPtr conn, return VIR_DRV_OPEN_ERROR; } - if (driver->privileged) { - if (STRNEQ(conn->uri->path, "/system")) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("unexpected storage URI path '%s', try storage:///system"), - conn->uri->path); - return VIR_DRV_OPEN_ERROR; - } - } else { - if (STRNEQ(conn->uri->path, "/session")) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("unexpected storage URI path '%s', try storage:///session"), - conn->uri->path); - return VIR_DRV_OPEN_ERROR; - } - } + if (!virConnectValidateURIPath(conn->uri->path, + "storage", + driver->privileged)) + return VIR_DRV_OPEN_ERROR; if (virConnectOpenEnsureACL(conn) < 0) return VIR_DRV_OPEN_ERROR; -- 2.21.0

The existing QEMU and vbox URI path validation consider that a privileged user can use both a "/system" and a "/session" URI. This differs from all the other drivers that forbids the root user to use "/session" URI. Let's update virConnectValidateURIPath() to handle these cases as exceptions, using the already existent 'entityName' value to handle "QEMU" and "vbox" differently. This allows us to use the validateURI function in these cases without changing the existing behavior of other drivers. Suggested-by: Cole Robinson <crobinso@redhat.com> Signed-off-by: Daniel Henrique Barboza <danielhb413@gmail.com> --- src/driver.c | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/src/driver.c b/src/driver.c index e627b0c1d7..8f9da35f78 100644 --- a/src/driver.c +++ b/src/driver.c @@ -276,16 +276,30 @@ virConnectValidateURIPath(const char *uriPath, bool privileged) { if (privileged) { - if (STRNEQ(uriPath, "/system")) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("unexpected %s URI path '%s', try %s:///system"), - entityName, uriPath, entityName); - return false; + /* TODO: QEMU and vbox drivers allow '/session' + * connections as root. This is not ideal, but changing + * these drivers to refuse privileged '/session' + * connections, like everyone else is already doing, can + * break existing applications. Until we decide what to do, + * for now we can handle them as exception in this validate + * function. + */ + bool compatSessionRoot = (STREQ(entityName, "QEMU") || + STREQ(entityName, "vbox")); + + if ((compatSessionRoot && STRNEQ(uriPath, "/session")) || + STRNEQ(uriPath, "/system")) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("unexpected %s URI path '%s', try " + "%s:///system"), + entityName, uriPath, entityName); + return false; } } else { if (STRNEQ(uriPath, "/session")) { virReportError(VIR_ERR_INTERNAL_ERROR, - _("unexpected %s URI path '%s', try %s:///session"), + _("unexpected %s URI path '%s', try " + "%s:///session"), entityName, uriPath, entityName); return false; } -- 2.21.0

On 9/25/19 9:50 AM, Daniel Henrique Barboza wrote:
The existing QEMU and vbox URI path validation consider that a privileged user can use both a "/system" and a "/session" URI. This differs from all the other drivers that forbids the root user to use "/session" URI.
Let's update virConnectValidateURIPath() to handle these cases as exceptions, using the already existent 'entityName' value to handle "QEMU" and "vbox" differently. This allows us to use the validateURI function in these cases without changing the existing behavior of other drivers.
Suggested-by: Cole Robinson <crobinso@redhat.com> Signed-off-by: Daniel Henrique Barboza <danielhb413@gmail.com> --- src/driver.c | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-)
diff --git a/src/driver.c b/src/driver.c index e627b0c1d7..8f9da35f78 100644 --- a/src/driver.c +++ b/src/driver.c @@ -276,16 +276,30 @@ virConnectValidateURIPath(const char *uriPath, bool privileged) { if (privileged) { - if (STRNEQ(uriPath, "/system")) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("unexpected %s URI path '%s', try %s:///system"), - entityName, uriPath, entityName); - return false; + /* TODO: QEMU and vbox drivers allow '/session' + * connections as root. This is not ideal, but changing + * these drivers to refuse privileged '/session' + * connections, like everyone else is already doing, can + * break existing applications. Until we decide what to do, + * for now we can handle them as exception in this validate + * function. + */ + bool compatSessionRoot = (STREQ(entityName, "QEMU") || + STREQ(entityName, "vbox")); + + if ((compatSessionRoot && STRNEQ(uriPath, "/session")) || + STRNEQ(uriPath, "/system")) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("unexpected %s URI path '%s', try " + "%s:///system"), + entityName, uriPath, entityName); + return false; }
The logic is incorrect here. Try connecting to qemu:///system after this change, it will be rejected. Also passing in the 'QEMU' instead of 'qemu string means we print the wrong URI in the error. I think this needs a v4 :/
} else { if (STRNEQ(uriPath, "/session")) { virReportError(VIR_ERR_INTERNAL_ERROR, - _("unexpected %s URI path '%s', try %s:///session"), + _("unexpected %s URI path '%s', try " + "%s:///session"), entityName, uriPath, entityName);
This formatting should be squashed into patch #1 IMO Thanks, Cole

On 9/25/19 7:58 PM, Cole Robinson wrote:
On 9/25/19 9:50 AM, Daniel Henrique Barboza wrote:
The existing QEMU and vbox URI path validation consider that a privileged user can use both a "/system" and a "/session" URI. This differs from all the other drivers that forbids the root user to use "/session" URI.
Let's update virConnectValidateURIPath() to handle these cases as exceptions, using the already existent 'entityName' value to handle "QEMU" and "vbox" differently. This allows us to use the validateURI function in these cases without changing the existing behavior of other drivers.
Suggested-by: Cole Robinson <crobinso@redhat.com> Signed-off-by: Daniel Henrique Barboza <danielhb413@gmail.com> --- src/driver.c | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-)
diff --git a/src/driver.c b/src/driver.c index e627b0c1d7..8f9da35f78 100644 --- a/src/driver.c +++ b/src/driver.c @@ -276,16 +276,30 @@ virConnectValidateURIPath(const char *uriPath, bool privileged) { if (privileged) { - if (STRNEQ(uriPath, "/system")) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("unexpected %s URI path '%s', try %s:///system"), - entityName, uriPath, entityName); - return false; + /* TODO: QEMU and vbox drivers allow '/session' + * connections as root. This is not ideal, but changing + * these drivers to refuse privileged '/session' + * connections, like everyone else is already doing, can + * break existing applications. Until we decide what to do, + * for now we can handle them as exception in this validate + * function. + */ + bool compatSessionRoot = (STREQ(entityName, "QEMU") || + STREQ(entityName, "vbox")); + + if ((compatSessionRoot && STRNEQ(uriPath, "/session")) || + STRNEQ(uriPath, "/system")) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("unexpected %s URI path '%s', try " + "%s:///system"), + entityName, uriPath, entityName); + return false; }
The logic is incorrect here. Try connecting to qemu:///system after this change, it will be rejected.
I assumed that any of the checks in 'make check' would fail if I messed up here. Never assume huh. (/me wondering if this rewards a unit test)
Also passing in the 'QEMU' instead of 'qemu string means we print the wrong URI in the error. I think this needs a v4 :/
I'll fix that and re-spin a v4. I'll also squash the below formatting like you suggested in patch 01. Thanks, DHB
} else { if (STRNEQ(uriPath, "/session")) { virReportError(VIR_ERR_INTERNAL_ERROR, - _("unexpected %s URI path '%s', try %s:///session"), + _("unexpected %s URI path '%s', try " + "%s:///session"), entityName, uriPath, entityName);
This formatting should be squashed into patch #1 IMO
Thanks, Cole

Suggested-by: Cole Robinson <crobinso@redhat.com> Signed-off-by: Daniel Henrique Barboza <danielhb413@gmail.com> --- src/qemu/qemu_driver.c | 20 ++++---------------- 1 file changed, 4 insertions(+), 16 deletions(-) diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index db4b39dc9e..abd1533889 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -1295,22 +1295,10 @@ static virDrvOpenStatus qemuConnectOpen(virConnectPtr conn, return VIR_DRV_OPEN_ERROR; } - if (virQEMUDriverIsPrivileged(qemu_driver)) { - if (STRNEQ(conn->uri->path, "/system") && - STRNEQ(conn->uri->path, "/session")) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("unexpected QEMU URI path '%s', try qemu:///system"), - conn->uri->path); - return VIR_DRV_OPEN_ERROR; - } - } else { - if (STRNEQ(conn->uri->path, "/session")) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("unexpected QEMU URI path '%s', try qemu:///session"), - conn->uri->path); - return VIR_DRV_OPEN_ERROR; - } - } + if (!virConnectValidateURIPath(conn->uri->path, + "QEMU", + virQEMUDriverIsPrivileged(qemu_driver))) + return VIR_DRV_OPEN_ERROR; if (virConnectOpenEnsureACL(conn) < 0) return VIR_DRV_OPEN_ERROR; -- 2.21.0

Suggested-by: Cole Robinson <crobinso@redhat.com> Signed-off-by: Daniel Henrique Barboza <danielhb413@gmail.com> --- src/vbox/vbox_common.c | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/src/vbox/vbox_common.c b/src/vbox/vbox_common.c index ddabcb80ca..d3b8fb625f 100644 --- a/src/vbox/vbox_common.c +++ b/src/vbox/vbox_common.c @@ -517,20 +517,8 @@ vboxConnectOpen(virConnectPtr conn, virCheckFlags(VIR_CONNECT_RO, VIR_DRV_OPEN_ERROR); - if (uid != 0) { - if (STRNEQ(conn->uri->path, "/session")) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("unknown driver path '%s' specified (try vbox:///session)"), conn->uri->path); - return VIR_DRV_OPEN_ERROR; - } - } else { /* root */ - if (STRNEQ(conn->uri->path, "/system") && - STRNEQ(conn->uri->path, "/session")) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("unknown driver path '%s' specified (try vbox:///system)"), conn->uri->path); - return VIR_DRV_OPEN_ERROR; - } - } + if (!virConnectValidateURIPath(conn->uri->path, "vbox", uid == 0)) + return VIR_DRV_OPEN_ERROR; if (!(driver = vboxGetDriverConnection())) return VIR_DRV_OPEN_ERROR; -- 2.21.0

Suggested-by: Cole Robinson <crobinso@redhat.com> Signed-off-by: Daniel Henrique Barboza <danielhb413@gmail.com> --- src/vbox/vbox_driver.c | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/src/vbox/vbox_driver.c b/src/vbox/vbox_driver.c index 1f31fa28df..d7e80828ab 100644 --- a/src/vbox/vbox_driver.c +++ b/src/vbox/vbox_driver.c @@ -58,20 +58,8 @@ static virDrvOpenStatus dummyConnectOpen(virConnectPtr conn, virCheckFlags(VIR_CONNECT_RO, VIR_DRV_OPEN_ERROR); - if (uid != 0) { - if (STRNEQ(conn->uri->path, "/session")) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("unknown driver path '%s' specified (try vbox:///session)"), conn->uri->path); - return VIR_DRV_OPEN_ERROR; - } - } else { /* root */ - if (STRNEQ(conn->uri->path, "/system") && - STRNEQ(conn->uri->path, "/session")) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("unknown driver path '%s' specified (try vbox:///system)"), conn->uri->path); - return VIR_DRV_OPEN_ERROR; - } - } + if (!virConnectValidateURIPath(conn->uri->path, "vbox", uid == 0)) + return VIR_DRV_OPEN_ERROR; virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("unable to initialize VirtualBox driver API")); -- 2.21.0
participants (2)
-
Cole Robinson
-
Daniel Henrique Barboza