public inbox for pbs-devel@lists.proxmox.com
 help / color / mirror / Atom feed
From: Manuel Federanko <m.federanko@proxmox.com>
To: Christian Ebner <c.ebner@proxmox.com>, pbs-devel@lists.proxmox.com
Subject: Re: [PATCH proxmox-backup] fix #5247: relative paths in exclude patterns.
Date: Thu, 26 Mar 2026 09:50:49 +0100	[thread overview]
Message-ID: <e5892388-f7ec-4021-9249-78bcb54d5fe9@proxmox.com> (raw)
In-Reply-To: <21976801-5b8e-4690-b1a7-b8d769e445cf@proxmox.com>

Hi!

thanks for your input, I will incorporate the changes in v2.

On 2026-03-25 6:04 PM, Christian Ebner wrote:
> Hi, thanks for the patch! A few high level comments, no full in detail 
> review yet.
> 
> On 3/23/26 4:31 PM, Manuel Federanko wrote:
>> Patterns which start with ./ or for that matter contain /../ or similar
>> constructs will never match, since they get compared to sanitized paths
>> from directory traversal, sanitize those patterns too.
> 
> May also state that the user is now warned if such patterns are encountered.
> 
>> Tested by creating a .pxarexclude file and via the --exclude command
>> line option.
> 
> Would not include explicitly that you tested this in the commit message, 
> it should rather state that this has effect for both cases. Don't get me 
> wrong, it can make sense to include such information as well, e.g. as 
> future references for more complex command invocations, just a bit to 
> much for this trivial test case IMHO.
> 
>> 
> 
> your comment from here ...
> 
>> I'm unsure if we should accept those silently, currently I added a
>> warning for patterns supplied via the cli option, since that feels most
>> susceptible to wrong usage.
>> 
>> It might also make sense to base the patterns for the cli arg on the
>> cwd, but that would be a breaking change.
> 
> ... to here should not be part of the commit message (which will be 
> applied), but rather be additional notes which go below the `---` 
> separator (where it does not get applied). See marking below.
> 
>> 
>> Signed-off-by: Manuel Federanko <m.federanko@proxmox.com>
>> Fixes: https://bugzilla.proxmox.com/show_bug.cgi?id=5247
>> ---
> 
> -> additional notes and comments here
> 
>>   pbs-client/src/pxar/create.rs     |  7 ++++++-
>>   pbs-client/src/pxar/tools.rs      | 32 +++++++++++++++++++++++++++++++
>>   proxmox-backup-client/src/main.rs | 16 ++++++++++++++--
>>   3 files changed, 52 insertions(+), 3 deletions(-)
>> 
>> diff --git a/pbs-client/src/pxar/create.rs b/pbs-client/src/pxar/create.rs
>> index e42bcc87..1c878cb7 100644
>> --- a/pbs-client/src/pxar/create.rs
>> +++ b/pbs-client/src/pxar/create.rs
>> @@ -560,7 +560,12 @@ impl Archiver {
>>                   (line, MatchType::Exclude, false)
>>               };
>>   
>> -            match MatchEntry::parse_pattern(line, PatternFlag::PATH_NAME, mode) {
>> +            let line_normalized = crate::pxar::tools::normalize_lexically(OsStr::from_bytes(line));
>> +            match MatchEntry::parse_pattern(
>> +                line_normalized.as_path().as_os_str().as_bytes(),
>> +                PatternFlag::PATH_NAME,
>> +                mode,
>> +            ) {
>>                   Ok(pattern) => {
>>                       if anchored {
>>                           self.patterns.push(pattern.add_flags(MatchFlag::ANCHORED));
>> diff --git a/pbs-client/src/pxar/tools.rs b/pbs-client/src/pxar/tools.rs
>> index 475c08ad..71a38b29 100644
>> --- a/pbs-client/src/pxar/tools.rs
>> +++ b/pbs-client/src/pxar/tools.rs
>> @@ -76,6 +76,38 @@ fn assert_single_path_component_do(path: &Path) -> Result<(), Error> {
>>       Ok(())
>>   }
>>   
>> +pub fn normalize_lexically<S: AsRef<OsStr> + ?Sized>(path: &S) -> PathBuf {
>> +    normalize_lexically_do(Path::new(path))
> 
> comment: `path` could be wrapped here and the function in-lined:
> 
>      let path = Path::new(path);
>      [...]
> 
> 
>> +}
>> +fn normalize_lexically_do(path: &Path) -> PathBuf {
>> +    // Once std::path::normalize_lexically is stabilized we can switch
>> +    // to that
> 
> comment: This comment warrants a FIXME: prefix.
> 
>> +    use std::path::Component;
>> +    let has_trailing_slash = path
>> +        .as_os_str()
>> +        .as_encoded_bytes()
>> +        .last()
>> +        .copied()
>> +        .is_some_and(|c: u8| c == std::path::MAIN_SEPARATOR_STR.bytes().last().unwrap());
>> +    let mut new = PathBuf::new();
>> +    let iter = path.components();
>> +    for component in iter {
>> +        match component {
>> +            Component::RootDir => new.push(Component::RootDir),
>> +            Component::Prefix(p) => new.push(Component::Prefix(p)),
>> +            Component::CurDir => continue,
>> +            Component::ParentDir => {
>> +                new.pop();
>> +            }
>> +            Component::Normal(n) => new.push(n),
>> +        };
>> +    }
>> +    if has_trailing_slash {
>> +        new.push("");
>> +    }
>> +    new
>> +}
>> +
>>   #[rustfmt::skip]
>>   fn symbolic_mode(c: u64, special: bool, special_x: u8, special_no_x: u8) -> [u8; 3] {
>>       [
>> diff --git a/proxmox-backup-client/src/main.rs b/proxmox-backup-client/src/main.rs
>> index 2ada87bd..4ed23d6e 100644
>> --- a/proxmox-backup-client/src/main.rs
>> +++ b/proxmox-backup-client/src/main.rs
>> @@ -826,9 +826,21 @@ async fn create_backup(
>>           let entry = entry
>>               .as_str()
>>               .ok_or_else(|| format_err!("Invalid pattern string slice"))?;
>> +        let entry_normalized = pbs_client::pxar::tools::normalize_lexically(entry);
>> +        if entry_normalized.as_os_str() != entry {
>> +            log::info!(
> 
> nit: better escalate this to a log::warn!
> After all it has proven to behave unexpectedly to some users.
> 
>> +                "Sanitized exclude pattern. Exclude patterns are relative to backup root, \
>> +                not the current working directory and should not contain '.' or '..' as path \
>> +                segments"
>> +            );
>> +        }
>>           pattern_list.push(
>> -            MatchEntry::parse_pattern(entry, PatternFlag::PATH_NAME, MatchType::Exclude)
>> -                .map_err(|err| format_err!("invalid exclude pattern entry: {}", err))?,
>> +            MatchEntry::parse_pattern(
>> +                entry_normalized.as_os_str().as_encoded_bytes(),
>> +                PatternFlag::PATH_NAME,
>> +                MatchType::Exclude,
>> +            )
>> +            .map_err(|err| format_err!("invalid exclude pattern entry: {}", err))?,
>>           );
>>       }
>>   
> 




      reply	other threads:[~2026-03-26  8:50 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-03-23 15:32 Manuel Federanko
2026-03-25 17:05 ` Christian Ebner
2026-03-26  8:50   ` Manuel Federanko [this message]

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=e5892388-f7ec-4021-9249-78bcb54d5fe9@proxmox.com \
    --to=m.federanko@proxmox.com \
    --cc=c.ebner@proxmox.com \
    --cc=pbs-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