public inbox for pve-devel@lists.proxmox.com
 help / color / mirror / Atom feed
From: "Fabian Grünbichler" <f.gruenbichler@proxmox.com>
To: Proxmox VE development discussion <pve-devel@lists.proxmox.com>
Subject: Re: [pve-devel] [PATCH v2 qemu-server 02/12] api: allow SU privileged users to edit root-only options for VM configs
Date: Thu, 17 Mar 2022 11:05:07 +0100	[thread overview]
Message-ID: <1647509888.r686k9qj6u.astroid@nora.none> (raw)
In-Reply-To: <20220311112504.595964-3-o.bektas@proxmox.com>

On March 11, 2022 12:24 pm, Oguz Bektas wrote:
> we now allow users with SU privilege to edit real device configurations
> for VMs.
> 
> they still need the required privilege to edit the corresponding
> configuration options (such as `VM.Config.HWType`), as well as the SU
> privilege.
> 
> Signed-off-by: Oguz Bektas <o.bektas@proxmox.com>
> ---
> v1->v2:
> * add comments at the shortcuts for root@pam
> * remove wrong shortcut for SU, instead check required privileges + SU
> * revert migration-only parameters and vzdump internal ones
> 
> 
>  PVE/API2/Qemu.pm | 63 ++++++++++++++++++++++++------------------------
>  1 file changed, 32 insertions(+), 31 deletions(-)
> 
> diff --git a/PVE/API2/Qemu.pm b/PVE/API2/Qemu.pm
> index 68077cc..21fc82b 100644
> --- a/PVE/API2/Qemu.pm
> +++ b/PVE/API2/Qemu.pm
> @@ -352,16 +352,17 @@ my $cloudinitoptions = {
>  my $check_vm_create_serial_perm = sub {
>      my ($rpcenv, $authuser, $vmid, $pool, $param) = @_;
>  
> +    # no need to check permissions for root@pam
>      return 1 if $authuser eq 'root@pam';
>  
> +    my $is_superuser = $rpcenv->check($authuser, "/vms/$vmid", ['SuperUser'], 1);
> +
>      foreach my $opt (keys %{$param}) {
>  	next if $opt !~ m/^serial\d+$/;
>  
> -	if ($param->{$opt} eq 'socket') {
> -	    $rpcenv->check_vm_perm($authuser, $vmid, $pool, ['VM.Config.HWType']);
> -	} else {
> -	    die "only root can set '$opt' config for real devices\n";
> -	}
> +	$rpcenv->check_vm_perm($authuser, $vmid, $pool, ['VM.Config.HWType']);
> +	die "only superusers can set '$opt' config for real devices\n"
> +	    if !($param->{$opt} eq 'socket' || $is_superuser);

check and message match, but not really. IMHO

    if $param->{$opt} ne 'socket' && !$is_superuser;

matches the text of the message in a more readable fashion

>      }
>  
>      return 1;
> @@ -370,16 +371,17 @@ my $check_vm_create_serial_perm = sub {
>  my $check_vm_create_usb_perm = sub {
>      my ($rpcenv, $authuser, $vmid, $pool, $param) = @_;
>  
> +    # no need to check permissions for root@pam
>      return 1 if $authuser eq 'root@pam';
>  
> +    my $is_superuser = $rpcenv->check($authuser, "/vms/$vmid", ['SuperUser'], 1);
> +
>      foreach my $opt (keys %{$param}) {
>  	next if $opt !~ m/^usb\d+$/;
>  
> -	if ($param->{$opt} =~ m/spice/) {
> -	    $rpcenv->check_vm_perm($authuser, $vmid, $pool, ['VM.Config.HWType']);
> -	} else {
> -	    die "only root can set '$opt' config for real devices\n";
> -	}
> +	$rpcenv->check_vm_perm($authuser, $vmid, $pool, ['VM.Config.HWType']);
> +	die "only superusers can set '$opt' config for real devices\n"
> +	    if !($param->{$opt} =~ m/spice/ || $is_superuser);

same here

>      }
>  
>      return 1;
> @@ -388,8 +390,11 @@ my $check_vm_create_usb_perm = sub {
>  my $check_vm_modify_config_perm = sub {
>      my ($rpcenv, $authuser, $vmid, $pool, $key_list) = @_;
>  
> +    # no need to check permissions for root@pam
>      return 1 if $authuser eq 'root@pam';
>  
> +    my $is_superuser = $rpcenv->check($authuser, "/vms/$vmid", ['SuperUser'], 1);
> +
>      foreach my $opt (@$key_list) {
>  	# some checks (e.g., disk, serial port, usb) need to be done somewhere
>  	# else, as there the permission can be value dependend
> @@ -425,7 +430,8 @@ my $check_vm_modify_config_perm = sub {
>  	} else {
>  	    # catches hostpci\d+, args, lock, etc.
>  	    # new options will be checked here
> -	    die "only root can set '$opt' config\n";
> +	    die "only superusers can set '$opt' config\n"
> +		if !$is_superuser;
>  	}
>      }
>  
> @@ -1117,6 +1123,8 @@ my $update_vm_api  = sub {
>  	push @paramarr, "-$key", $value;
>      }
>  
> +    my $is_superuser = $authuser eq 'root@pam' || $rpcenv->check($authuser, "/vms/$vmid", ['SuperUser'], 1);

nit: line too long (I know, there are others as well, but that doesn't 
mean we want to introduce even more mess ;))

not sure whether the shortcut here is worth it anyway, this is a single 
call and we have a few others that are not skipped either.

> +
>      my $skiplock = extract_param($param, 'skiplock');
>      raise_param_exc({ skiplock => "Only root may use this option." })
>  	if $skiplock && $authuser ne 'root@pam';
> @@ -1338,19 +1346,15 @@ my $update_vm_api  = sub {
>  		    PVE::QemuConfig->add_to_pending_delete($conf, $opt, $force);
>  		    PVE::QemuConfig->write_config($vmid, $conf);
>  		} elsif ($opt =~ m/^serial\d+$/) {
> -		    if ($val eq 'socket') {
> -			$rpcenv->check_vm_perm($authuser, $vmid, undef, ['VM.Config.HWType']);
> -		    } elsif ($authuser ne 'root@pam') {
> -			die "only root can delete '$opt' config for real devices\n";
> -		    }
> +		    $rpcenv->check_vm_perm($authuser, $vmid, undef, ['VM.Config.HWType']);
> +		    die "only superusers can delete '$opt' config for real devices\n"
> +			if !($val eq 'socket' || $is_superuser);

condition style here

>  		    PVE::QemuConfig->add_to_pending_delete($conf, $opt, $force);
>  		    PVE::QemuConfig->write_config($vmid, $conf);
>  		} elsif ($opt =~ m/^usb\d+$/) {
> -		    if ($val =~ m/spice/) {
> -			$rpcenv->check_vm_perm($authuser, $vmid, undef, ['VM.Config.HWType']);
> -		    } elsif ($authuser ne 'root@pam') {
> -			die "only root can delete '$opt' config for real devices\n";
> -		    }
> +		    $rpcenv->check_vm_perm($authuser, $vmid, undef, ['VM.Config.HWType']);
> +		    die "only superusers can delete '$opt' config for real devices\n"
> +			if !($val =~ m/spice/ || $is_superuser);

and here

>  		    PVE::QemuConfig->add_to_pending_delete($conf, $opt, $force);
>  		    PVE::QemuConfig->write_config($vmid, $conf);
>  		} else {
> @@ -1362,6 +1366,7 @@ my $update_vm_api  = sub {
>  	    foreach my $opt (keys %$param) { # add/change
>  		$modified->{$opt} = 1;
>  		$conf = PVE::QemuConfig->load_config($vmid); # update/reload
> +		my $val = $conf->{$opt} // $conf->{pending}->{$opt};

no explanation for this change here, but $val now has the current value 
if one is set, or the pending value if that is set.

it seems to be copied from the code handling deletions (where this makes 
sense - there is no new value in that case), but we want to ensure the 
thing we remove is something we are allowed to add back/in the first 
place.

>  		next if defined($conf->{pending}->{$opt}) && ($param->{$opt} eq $conf->{pending}->{$opt}); # skip if nothing changed
>  
>  		my $arch = PVE::QemuServer::get_vm_arch($conf);
> @@ -1390,18 +1395,14 @@ my $update_vm_api  = sub {
>  			}
>  		    }
>  		} elsif ($opt =~ m/^serial\d+/) {
> -		    if ((!defined($conf->{$opt}) || $conf->{$opt} eq 'socket') && $param->{$opt} eq 'socket') {

but here we have totally different rules applying, and can't just 
apply the ones for deleting? this here checks both the old value if one 
is set (which we remove) and the new value (which we set)

> -			$rpcenv->check_vm_perm($authuser, $vmid, undef, ['VM.Config.HWType']);
> -		    } elsif ($authuser ne 'root@pam') {
> -			die "only root can modify '$opt' config for real devices\n";
> -		    }
> +		    $rpcenv->check_vm_perm($authuser, $vmid, undef, ['VM.Config.HWType']);
> +		    die "only superusers can modify '$opt' config for real devices\n"
> +			if !($val eq 'socket' || $is_superuser);

so this completely changes the semantics, no longer checking the new 
value at all.. so again I wonder how did you test this?  this allows 
skipping the SU check as long as I first set the allowed value, and then 
replace it with the high-privilege one..

>  		    $conf->{pending}->{$opt} = $param->{$opt};
>  		} elsif ($opt =~ m/^usb\d+/) {
> -		    if ((!defined($conf->{$opt}) || $conf->{$opt} =~ m/spice/) && $param->{$opt} =~ m/spice/) {
> -			$rpcenv->check_vm_perm($authuser, $vmid, undef, ['VM.Config.HWType']);
> -		    } elsif ($authuser ne 'root@pam') {
> -			die "only root can modify '$opt' config for real devices\n";
> -		    }
> +		    $rpcenv->check_vm_perm($authuser, $vmid, undef, ['VM.Config.HWType']);
> +		    die "only superusers can modify '$opt' config for real devices\n"
> +			if !($val =~ m/spice/ || $is_superuser);

same applies here..

>  		    $conf->{pending}->{$opt} = $param->{$opt};
>  		} else {
>  		    $conf->{pending}->{$opt} = $param->{$opt};
> -- 
> 2.30.2
> 
> 
> 
> _______________________________________________
> pve-devel mailing list
> pve-devel@lists.proxmox.com
> https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel
> 
> 
> 




  reply	other threads:[~2022-03-17 10:05 UTC|newest]

Thread overview: 23+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-03-11 11:24 [pve-devel] [PATCH v2 access-control++ 00/12] SuperUser privilege Oguz Bektas
2022-03-11 11:24 ` [pve-devel] [PATCH v2 docs 01/12] pveum: add SU privilege and SA role Oguz Bektas
2022-03-17  9:36   ` Fabian Grünbichler
2022-03-11 11:24 ` [pve-devel] [PATCH v2 qemu-server 02/12] api: allow SU privileged users to edit root-only options for VM configs Oguz Bektas
2022-03-17 10:05   ` Fabian Grünbichler [this message]
2022-03-11 11:24 ` [pve-devel] [PATCH v2 qemu-server 03/12] api: allow 'skiplock' option to be used by SU privileged users Oguz Bektas
2022-03-17 10:12   ` Fabian Grünbichler
2022-03-11 11:24 ` [pve-devel] [PATCH v2 manager 04/12] api: backup: allow SUs to use 'tmpdir', 'dumpdir' and 'script' options Oguz Bektas
2022-03-17 12:18   ` Fabian Grünbichler
2022-03-11 11:24 ` [pve-devel] [PATCH v2 manager 05/12] api: vzdump: allow SUs to use 'bwlimit' and 'ionice' parameters Oguz Bektas
2022-03-11 11:24 ` [pve-devel] [PATCH v2 manager 06/12] api: update comment about login prompt for non-root users Oguz Bektas
2022-03-17 12:33   ` Fabian Grünbichler
2022-03-11 11:24 ` [pve-devel] [PATCH v2 manager 07/12] ui: adapt sensible 'root@pam' checks to SU privilege Oguz Bektas
2022-03-17 12:28   ` Fabian Grünbichler
2022-03-11 11:25 ` [pve-devel] [PATCH v2 container 08/12] fix #2582: api: add checks for 'SuperUser' privilege for root-only options Oguz Bektas
2022-03-17 12:11   ` Fabian Grünbichler
2022-03-11 11:25 ` [pve-devel] [PATCH v2 storage 09/12] check_volume_access: allow superusers to pass arbitrary fs paths Oguz Bektas
2022-03-11 11:25 ` [pve-devel] [PATCH v2 access-control 10/12] add "SuperAdministrator" role with the new "SuperUser" privilege Oguz Bektas
2022-03-11 11:25 ` [pve-devel] [PATCH v2 access-control 11/12] api: allow superusers to edit tfa and password settings Oguz Bektas
     [not found]   ` <<20220311112504.595964-12-o.bektas@proxmox.com>
2022-03-17  9:30     ` Fabian Grünbichler
2022-03-11 11:25 ` [pve-devel] [PATCH v2 access-control 12/12] api: acl: only allow granting SU privilege if user already has it Oguz Bektas
2022-03-16 12:24   ` Fabian Grünbichler
     [not found] ` <<20220311112504.595964-1-o.bektas@proxmox.com>
2022-03-17 13:04   ` [pve-devel] [PATCH v2 access-control++ 00/12] SuperUser privilege Fabian Grünbichler

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1647509888.r686k9qj6u.astroid@nora.none \
    --to=f.gruenbichler@proxmox.com \
    --cc=pve-devel@lists.proxmox.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
Service provided by Proxmox Server Solutions GmbH | Privacy | Legal