only three small things were missing for it to work:
* on the cli, we have to get the option as an array if the type is an array
* the untainting must be done recursively, otherwise, the regex matching
  converts an array hash into the string 'ARRAY(0x123412341234)'
* JSONSchema::parse_config did not handle array formats specially, but
  we want to allow to specify them multiple time

Signed-off-by: Dominik Csapak <d.csa...@proxmox.com>
---
 src/PVE/JSONSchema.pm  | 12 ++++++++++++
 src/PVE/RESTHandler.pm | 41 ++++++++++++++++++++++++++++++++++-------
 2 files changed, 46 insertions(+), 7 deletions(-)

diff --git a/src/PVE/JSONSchema.pm b/src/PVE/JSONSchema.pm
index 527e409..526fc2b 100644
--- a/src/PVE/JSONSchema.pm
+++ b/src/PVE/JSONSchema.pm
@@ -1709,6 +1709,8 @@ sub get_options {
        } else {
            if ($pd->{format} && $pd->{format} =~ m/-a?list/) {
                push @getopt, "$prop=s@";
+           } elsif ($pd->{type} eq 'array') {
+               push @getopt, "$prop=s@";
            } else {
                push @getopt, "$prop=s";
            }
@@ -1869,6 +1871,16 @@ sub parse_config : prototype($$$;$) {
 
                $value = parse_boolean($value) // $value;
            }
+           if ($schema->{properties}->{$key} &&
+               $schema->{properties}->{$key}->{type} eq 'array') {
+
+               if (defined($cfg->{$key})) {
+                   push $cfg->{$key}->@*, $value;
+               } else {
+                   $cfg->{$key} = [$value];
+               }
+               next;
+           }
            $cfg->{$key} = $value;
        } else {
            warn "ignore config line: $line\n"
diff --git a/src/PVE/RESTHandler.pm b/src/PVE/RESTHandler.pm
index 944a04b..20714a5 100644
--- a/src/PVE/RESTHandler.pm
+++ b/src/PVE/RESTHandler.pm
@@ -426,6 +426,38 @@ sub find_handler {
     return ($handler_class, $method_info);
 }
 
+my $untaint_recursive;
+
+$untaint_recursive = sub {
+    my ($param) = @_;
+
+    my $ref = ref $param;
+    if ($ref eq 'HASH') {
+       while (my ($key, $val) = each %$param) {
+           my $newval = $untaint_recursive->($val);
+           if (defined($newval)) {
+               ($param->{$key}) = $newval;
+           } else {
+               $param->{$key} = undef;
+           }
+       }
+    } elsif ($ref eq 'ARRAY') {
+       my $newparam = [];
+       for my $val (@$param) {
+           my $newval = $untaint_recursive->($val);
+           push @$newparam, $newval if defined($newval);
+       }
+       $param = $newparam;
+    } else {
+       if (defined($param)) {
+           my ($newval) = $param =~ /^(.*)$/s;
+           $param = $newval;
+       }
+    }
+
+    return $param;
+};
+
 sub handle {
     my ($self, $info, $param, $result_verification) = @_;
 
@@ -437,16 +469,11 @@ sub handle {
 
     if (my $schema = $info->{parameters}) {
        # warn "validate ". Dumper($param}) . "\n" . Dumper($schema);
+
        PVE::JSONSchema::validate($param, $schema);
        # untaint data (already validated)
        my $extra = delete $param->{'extra-args'};
-       while (my ($key, $val) = each %$param) {
-           if (defined($val)) {
-               ($param->{$key}) = $val =~ /^(.*)$/s;
-           } else {
-               $param->{$key} = undef;
-           }
-       }
+       $param = $untaint_recursive->($param);
        $param->{'extra-args'} = [map { /^(.*)$/ } @$extra] if $extra;
     }
 
-- 
2.30.2



_______________________________________________
pve-devel mailing list
pve-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel

Reply via email to