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
>
>
>
next prev parent 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