$cpu_fmt is being reused for custom CPUs as well as VM-specific CPU settings. The "pve-vm-cpu-conf" format is introduced to verify a config specifically for use as VM-specific settings.
"pve-cpu-conf" is registered for use in custom CPU API calls (where no additional checks are required). Signed-off-by: Stefan Reiter <s.rei...@proxmox.com> --- v4 -> v5: * extract both regexes into vars * add 'pve-cpu-conf' format for future use * rename verify_vm_cpu_conf to parse_vm_cpu_conf (since it's used for parsing in a later patch, and also to make it consistent with parse_cpu_conf_basic) * fix VM-specific CPU verification to also be applied with custom models v3 -> v4: * use is_custom_model v2 -> v3: * move $cpu_fmt->{flags} changes here, to avoid having broken checks between patches PVE/QemuServer.pm | 2 +- PVE/QemuServer/CPUConfig.pm | 73 ++++++++++++++++++++++++++++++++++--- 2 files changed, 69 insertions(+), 6 deletions(-) diff --git a/PVE/QemuServer.pm b/PVE/QemuServer.pm index e7758cb..874137f 100644 --- a/PVE/QemuServer.pm +++ b/PVE/QemuServer.pm @@ -505,7 +505,7 @@ EODESCR optional => 1, description => "Emulated CPU type.", type => 'string', - format => $PVE::QemuServer::CPUConfig::cpu_fmt, + format => 'pve-vm-cpu-conf', }, parent => get_standard_option('pve-snapshot-name', { optional => 1, diff --git a/PVE/QemuServer/CPUConfig.pm b/PVE/QemuServer/CPUConfig.pm index 2a65d50..ed883e1 100644 --- a/PVE/QemuServer/CPUConfig.pm +++ b/PVE/QemuServer/CPUConfig.pm @@ -90,9 +90,10 @@ my @supported_cpu_flags = ( 'hv-evmcs', 'aes' ); -my $cpu_flag = qr/[+-](@{[join('|', @supported_cpu_flags)]})/; +my $cpu_flag_supported_re = qr/([+-])(@{[join('|', @supported_cpu_flags)]})/; +my $cpu_flag_any_re = qr/([+-])([a-zA-Z0-9\-_\.]+)/; -our $cpu_fmt = { +my $cpu_fmt = { cputype => { description => "Emulated CPU type. Can be default or custom name (custom model names must be prefixed with 'custom-').", type => 'string', @@ -125,14 +126,76 @@ our $cpu_fmt = { flags => { description => "List of additional CPU flags separated by ';'." . " Use '+FLAG' to enable, '-FLAG' to disable a flag." - . " Currently supported flags: @{[join(', ', @supported_cpu_flags)]}.", + . " Custom CPU models can specify any flag supported by" + . " QEMU/KVM, VM-specific flags must be from the following" + . " set for security reasons: @{[join(', ', @supported_cpu_flags)]}.", format_description => '+FLAG[;-FLAG...]', type => 'string', - pattern => qr/$cpu_flag(;$cpu_flag)*/, + pattern => qr/$cpu_flag_any_re(;$cpu_flag_any_re)*/, optional => 1, }, }; +# $cpu_fmt describes both the CPU config passed as part of a VM config, as well +# as the definition of a custom CPU model. There are some slight differences +# though, which we catch in the custom verification function below. +PVE::JSONSchema::register_format('pve-cpu-conf', \&parse_cpu_conf_basic); +sub parse_cpu_conf_basic { + my ($cpu_str, $noerr) = @_; + + my $cpu = eval { PVE::JSONSchema::parse_property_string($cpu_fmt, $cpu_str) }; + if ($@) { + die $@ if !$noerr; + return undef; + } + + # required, but can't be forced in schema since it's encoded in section + # header for custom models + if (!$cpu->{cputype}) { + die "CPU is missing cputype\n" if !$noerr; + return undef; + } + + return $cpu; +} + +PVE::JSONSchema::register_format('pve-vm-cpu-conf', \&parse_vm_cpu_conf); +sub parse_vm_cpu_conf { + my ($cpu_str, $noerr) = @_; + + my $cpu = parse_cpu_conf_basic($cpu_str, $noerr); + return undef if !$cpu; + + my $cputype = $cpu->{cputype}; + + # a VM-specific config is only valid if the cputype exists + if (is_custom_model($cputype)) { + eval { get_custom_model($cputype); }; + if ($@) { + die $@ if !$noerr; + return undef; + } + } else { + if (!defined($cpu_vendor_list->{$cputype})) { + die "Built-in cputype '$cputype' is not defined (missing 'custom-' prefix?)\n" if !$noerr; + return undef; + } + } + + # in a VM-specific config, certain properties are limited/forbidden + + if ($cpu->{flags} && $cpu->{flags} !~ m/$cpu_flag_supported_re(;$cpu_flag_supported_re)*/) { + die "VM-specific CPU flags must be a subset of: @{[join(', ', @supported_cpu_flags)]}\n" + if !$noerr; + return undef; + } + + die "Property 'reported-model' not allowed in VM-specific CPU config.\n" + if defined($cpu->{'reported-model'}); + + return $cpu; +} + # Section config settings my $defaultData = { # shallow copy, since SectionConfig modifies propertyList internally @@ -220,7 +283,7 @@ sub print_cpu_device { my $kvm = $conf->{kvm} // 1; my $cpu = $kvm ? "kvm64" : "qemu64"; if (my $cputype = $conf->{cpu}) { - my $cpuconf = PVE::JSONSchema::parse_property_string($cpu_fmt, $cputype) + my $cpuconf = parse_cpu_conf_basic($cputype) or die "Cannot parse cpu description: $cputype\n"; $cpu = $cpuconf->{cputype}; } -- 2.20.1 _______________________________________________ pve-devel mailing list pve-devel@pve.proxmox.com https://pve.proxmox.com/cgi-bin/mailman/listinfo/pve-devel