[pbs-devel] [PATCH proxmox-backup v2] tape: skip setting encryption if we can't and don't want to

Dominik Csapak d.csapak at proxmox.com
Fri Jul 11 12:09:47 CEST 2025


ping, should still apply as is, but we got an additional user
running into this problem:

https://forum.proxmox.com/threads/fips-mode-on-tape-library-pbs-errors-out-on-labeling.164941/#post-782914

On 4/16/25 09:07, Dominik Csapak wrote:
> Some settings on changers prevents changing the encryption parameters
> via the application, e.g. some libraries have a 'encryption disabled' or
> 'encryption is library managed' option. While the former situation can
> be fixed by setting the library to 'application managed', the latter is
> sometimes necessary for FIPS compliance (to ensure the tape data is
> encrypted).
> 
> When libraries are configured this way, the code currently fails with
> 'drive does not support AES-GCM encryption'. Instead of failing, check
> on first call to set_encryption if we could set it, and save that
> result.
> 
> Only fail when encryption is to be enabled but it is not allowed, but
> ignore the error when the backup should be done unencrypted.
> 
> `assert_encryption_mode` must also check if it's possible, and skip any
> error if it's not possible and we wanted no encryption.
> 
> With these changes, it should be possible to use such configured libraries
> when there is no encryption configured on the PBS side. (We currently
> don't have a library with such capabilities to test.)
> 
> Note that in contrast to normal operation, the tape label will also be
> encrypted then and will not be readable in case the encryption key is
> lost or changed.
> 
> Additionally, return an error for 'drive_set_encryption' in case the
> drive reports that it does not support hardware encryption, because this
> is now already caught one level above in 'set_encryption'.
> 
> Also, slightly change the error message to make it clear that the drive
> does not support *setting* encryption, not that it does not support
> it at all.
> 
> This was reported in the community forum:
> 
> https://forum.proxmox.com/threads/107383/
> https://forum.proxmox.com/threads/164941/
> 
> Signed-off-by: Dominik Csapak <d.csapak at proxmox.com>
> ---
> changes from v1:
> * adapted error message to make it clear what is not supported
> * also adapt `assert_encryption_mode`, otherwise a backup is not possible
> 
>   pbs-tape/src/sg_tape.rs            | 30 +++++++++++++++++++++++++++++-
>   pbs-tape/src/sg_tape/encryption.rs | 12 ++----------
>   src/tape/drive/lto/mod.rs          |  4 ++++
>   3 files changed, 35 insertions(+), 11 deletions(-)
> 
> diff --git a/pbs-tape/src/sg_tape.rs b/pbs-tape/src/sg_tape.rs
> index 39e6a2f94..9c7a254d5 100644
> --- a/pbs-tape/src/sg_tape.rs
> +++ b/pbs-tape/src/sg_tape.rs
> @@ -136,6 +136,8 @@ pub struct SgTape {
>       file: File,
>       locate_offset: Option<i64>,
>       info: InquiryInfo,
> +    // auto-detect if we can set the encryption mode
> +    encryption_possible: Option<bool>,
>   }
>   
>   impl SgTape {
> @@ -158,6 +160,7 @@ impl SgTape {
>               file,
>               info,
>               locate_offset: None,
> +            encryption_possible: None,
>           })
>       }
>   
> @@ -690,6 +693,14 @@ impl SgTape {
>       }
>   
>       pub fn set_encryption(&mut self, key_data: Option<([u8; 32], Uuid)>) -> Result<(), Error> {
> +        if self.encryption_possible == Some(false) {
> +            if key_data.is_some() {
> +                bail!("Drive does not support setting encryption mode");
> +            } else {
> +                // skip trying to set encryption if not supported and don't wanted
> +                return Ok(());
> +            }
> +        }
>           let key = if let Some((ref key, ref uuid)) = key_data {
>               // derive specialized key for each media-set
>   
> @@ -710,7 +721,24 @@ impl SgTape {
>               None
>           };
>   
> -        drive_set_encryption(&mut self.file, key)
> +        match drive_set_encryption(&mut self.file, key) {
> +            Ok(()) => self.encryption_possible = Some(true),
> +            Err(err) => {
> +                self.encryption_possible = Some(false);
> +                if key.is_some() {
> +                    bail!("could not set encryption mode on drive: {err}");
> +                } else {
> +                    log::info!("could not set encryption mode on drive: {err}, ignoring.");
> +                }
> +            }
> +        }
> +        Ok(())
> +    }
> +
> +    /// Returns if encryption is possible. Returns [`None`] if it's unknown, because
> +    /// no attempt was made to set the mode yet.
> +    pub fn encryption_possible(&self) -> Option<bool> {
> +        self.encryption_possible
>       }
>   
>       // Note: use alloc_page_aligned_buffer to alloc data transfer buffer
> diff --git a/pbs-tape/src/sg_tape/encryption.rs b/pbs-tape/src/sg_tape/encryption.rs
> index 7247d257f..c24a6c658 100644
> --- a/pbs-tape/src/sg_tape/encryption.rs
> +++ b/pbs-tape/src/sg_tape/encryption.rs
> @@ -12,15 +12,7 @@ use crate::sgutils2::{alloc_page_aligned_buffer, SgRaw};
>   ///
>   /// We always use mixed mode,
>   pub fn drive_set_encryption<F: AsRawFd>(file: &mut F, key: Option<[u8; 32]>) -> Result<(), Error> {
> -    let data = match sg_spin_data_encryption_caps(file) {
> -        Ok(data) => data,
> -        Err(_) if key.is_none() => {
> -            // Assume device does not support HW encryption
> -            // We can simply ignore the clear key request
> -            return Ok(());
> -        }
> -        Err(err) => return Err(err),
> -    };
> +    let data = sg_spin_data_encryption_caps(file)?;
>   
>       let algorithm_index = decode_spin_data_encryption_caps(&data)?;
>   
> @@ -266,7 +258,7 @@ fn decode_spin_data_encryption_caps(data: &[u8]) -> Result<u8, Error> {
>   
>           match aes_gcm_index {
>               Some(index) => Ok(index),
> -            None => bail!("drive does not support AES-GCM encryption"),
> +            None => bail!("drive does not support setting AES-GCM encryption"),
>           }
>       })
>       .map_err(|err: Error| format_err!("decode data encryption caps page failed - {}", err))
> diff --git a/src/tape/drive/lto/mod.rs b/src/tape/drive/lto/mod.rs
> index 23e043ce6..bd5ec8ae6 100644
> --- a/src/tape/drive/lto/mod.rs
> +++ b/src/tape/drive/lto/mod.rs
> @@ -264,6 +264,10 @@ impl TapeDriver for LtoTapeHandle {
>       }
>   
>       fn assert_encryption_mode(&mut self, encryption_wanted: bool) -> Result<(), Error> {
> +        if Some(false) == self.sg_tape.encryption_possible() && !encryption_wanted {
> +            // ignore assertion for unencrypted mode, because we can't set it anyway
> +            return Ok(());
> +        }
>           let encryption_set = drive_get_encryption(self.sg_tape.file_mut())?;
>           if encryption_wanted != encryption_set {
>               bail!("Set encryption mode not what was desired (set: {encryption_set}, wanted: {encryption_wanted})");





More information about the pbs-devel mailing list