python / python/cpython

tarfile extraction filters raise raw ValueError for Windows drive-relative paths

未關閉
#154,987 5 則留言 0 個 reaction 已指派 0 人 在 GitHub 檢視

還沒有人認領這個 Issue。

OS-windows stdlib type-bug
主要語言
Python
星號
77.2k
分支
36k
平均合併
1 天 9 小時
30 天內合併 PR
558

描述

Bug report

Bug description:

tarfile extraction filters raise a raw ValueError on Windows when handling drive-relative member names or link targets such as C:bad.txt.

This looks like an inconsistency in the extraction-filter error handling path. The affected cases are rejected through a raw ValueError from Windows path handling instead of the structured tarfile filter exceptions that similar rejected paths use.

For example, with filter="data" and errorlevel = 0, I expected the invalid member to be skipped/refused and extraction to continue to later members. Instead, extraction aborts with:

ValueError: Paths don't have the same drive

Minimal reproducer:

import io
import os
import tarfile
import tempfile
from pathlib import Path


def add_file(tf, name, data=b"x"):
    info = tarfile.TarInfo(name)
    info.size = len(data)
    tf.addfile(info, io.BytesIO(data))


def build_archive_with_drive_relative_member(path):
    with tarfile.open(path, "w") as tf:
        add_file(tf, "before.txt", b"before")
        add_file(tf, "C:bad.txt", b"bad")
        add_file(tf, "after.txt", b"after")


def main():
    if os.name != "nt":
        print("This reproducer is Windows-specific.")
        return 0

    with tempfile.TemporaryDirectory() as tmp:
        tmp = Path(tmp)
        archive_path = tmp / "drive_relative.tar"
        extract_dir = tmp / "extract"
        extract_dir.mkdir()

        build_archive_with_drive_relative_member(archive_path)

        try:
            with tarfile.open(archive_path, "r") as tf:
                tf.errorlevel = 0
                tf.extractall(extract_dir, filter="data")
        except Exception as exc:
            print("exception_type:", type(exc).__name__)
            print("exception_message:", str(exc))

        print("before_exists:", (extract_dir / "before.txt").exists())
        print("after_exists:", (extract_dir / "after.txt").exists())


if __name__ == "__main__":
    raise SystemExit(main())

Observed output on Windows:

exception_type: ValueError
exception_message: Paths don't have the same drive
before_exists: True
after_exists: False

Expected behavior:

The drive-relative member should be handled through the normal tarfile extraction-filter exception path, for example OutsideDestinationError, so that errorlevel = 0 can skip/refuse that member and continue extracting later members.

Expected output would be:

before_exists: True
after_exists: True

I also observed the same raw ValueError behavior for drive-relative hardlink and symlink targets under filter="data".

Expected structured exceptions:

Drive-relative member name: OutsideDestinationError
Drive-relative hardlink target: LinkOutsideDestinationError
Drive-relative symlink target: LinkOutsideDestinationError

The issue appears to come from ntpath.commonpath() raising ValueError for incompatible drive/path semantics, and that exception escaping directly instead of being converted into the appropriate tarfile filter exception.

A possible fix would be to treat ValueError from the containment/commonpath check as an outside-destination condition and raise the appropriate structured tarfile exception.

CPython versions tested on:

CPython main branch

Operating systems tested on:

Windows

Linked PRs
  • gh-154993

貢獻指南

開啟貢獻指南

從這裡開始

  1. 先讀完整個 Issue,再讀專案的貢獻指南。
  2. 在 Issue 下留言說明你要接手 —— 這能避免兩個人做同樣的事。
  3. Fork 儲存庫,在一個分支上完成修改。
  4. 送出 Pull Request,並在描述裡引用這個 Issue 編號。

研究方向

從 issue 中描述的 tarfile 擷取篩選器 containment 檢查和 ntpath.commonpath 處理開始;在 Windows 上使用 C:bad.txt 之類的成員名稱和連結目標重現這些情況。完成的標準是,磁碟機相對情況使用所述的結構化 tarfile 例外,並且 errorlevel=0 繼續向後續成員進行擷取;請注意,關聯的 PR gh-154993 已經存在。

由索引模型根據 Issue 內容生成。

評估

技術堆疊
python
領域
operating-systems
Issue 類型
缺陷
難度
3/5
預估耗時
1-2 天
活躍度
停滯
描述清晰度
描述清楚
新手友好度
30/100

把新 issue 寄到你的電子郵件信箱

精選適合新手參與的 GitHub issue 摘要。