mirror of https://github.com/astral-sh/uv
Disallow writing symlinks outside the source distribution target directory (#12259)
## Summary Closes #12163. ## Test Plan Created an offending source distribution with this script: ```python import io import tarfile import textwrap import time PKG_NAME = "badpkg" VERSION = "0.1" DIST_NAME = f"{PKG_NAME}-{VERSION}" ARCHIVE = f"{DIST_NAME}.tar.gz" def _bytes(data: str) -> io.BytesIO: """Helper: wrap a text blob as a BytesIO for tarfile.addfile().""" return io.BytesIO(data.encode()) def main(out_path: str = ARCHIVE) -> None: now = int(time.time()) with tarfile.open(out_path, mode="w:gz") as tar: def add_file(path: str, data: str, mode: int = 0o644) -> None: """Add a regular file whose *content* is supplied as a string.""" buf = _bytes(data) info = tarfile.TarInfo(path) info.size = len(buf.getbuffer()) info.mtime = now info.mode = mode tar.addfile(info, buf) # ── top‑level setup.py ─────────────────────────────────────────────── setup_py = textwrap.dedent(f"""\ from setuptools import setup, find_packages setup( name="{PKG_NAME}", version="{VERSION}", packages=find_packages(), ) """) add_file(f"{DIST_NAME}/setup.py", setup_py) # ── minimal package code ───────────────────────────────────────────── add_file(f"{DIST_NAME}/{PKG_NAME}/__init__.py", "# placeholder\\n") # ── the malicious symlink ──────────────────────────────────────────── link = tarfile.TarInfo(f"{DIST_NAME}/{PKG_NAME}/evil_link") link.type = tarfile.SYMTYPE link.mtime = now link.mode = 0o777 link.linkname = "../../../outside.txt" tar.addfile(link) print(f"Created {out_path}") if __name__ == "__main__": main() ``` Verified that both `pip install` and `uv pip install` rejected it. I also changed `link.linkname = "../../../outside.txt"` to `link.linkname = "/etc/outside"`, and verified that the absolute path was rejected too.
This commit is contained in:
parent
c8486da495
commit
2677e85df9
|
|
@ -500,22 +500,20 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bzip2"
|
name = "bzip2"
|
||||||
version = "0.5.0"
|
version = "0.5.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "bafdbf26611df8c14810e268ddceda071c297570a5fb360ceddf617fe417ef58"
|
checksum = "49ecfb22d906f800d4fe833b6282cf4dc1c298f5057ca0b5445e5c209735ca47"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bzip2-sys",
|
"bzip2-sys",
|
||||||
"libc",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bzip2-sys"
|
name = "bzip2-sys"
|
||||||
version = "0.1.11+1.0.8"
|
version = "0.1.13+1.0.8"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "736a955f3fa7875102d57c82b8cac37ec45224a07fd32d58f9f7a186b6cd4cdc"
|
checksum = "225bff33b2141874fe80d71e07d6eec4f85c5c216453dd96388240f96e1acc14"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cc",
|
"cc",
|
||||||
"libc",
|
|
||||||
"pkg-config",
|
"pkg-config",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
@ -690,9 +688,9 @@ checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "codspeed"
|
name = "codspeed"
|
||||||
version = "3.0.3"
|
version = "3.0.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a7524e02ff6173bc143d9abc01b518711b77addb60de871bbe5686843f88fb48"
|
checksum = "d29180405ab3b37bb020246ea66bf8ae233708766fd59581ae929feaef10ce91"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"bincode",
|
"bincode",
|
||||||
|
|
@ -708,9 +706,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "codspeed-criterion-compat"
|
name = "codspeed-criterion-compat"
|
||||||
version = "3.0.3"
|
version = "3.0.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2f71662331c4f854131a42b95055f3f8cbca53640348985f699635b1f96d8c26"
|
checksum = "2454d874ca820ffd71273565530ad318f413195bbc99dce6c958ca07db362c63"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"codspeed",
|
"codspeed",
|
||||||
"codspeed-criterion-compat-walltime",
|
"codspeed-criterion-compat-walltime",
|
||||||
|
|
@ -719,9 +717,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "codspeed-criterion-compat-walltime"
|
name = "codspeed-criterion-compat-walltime"
|
||||||
version = "3.0.3"
|
version = "3.0.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e3c9bd9e895e0aa263d139a8b5f58a4ea4abb86d5982ec7f58d3c7b8465c1e01"
|
checksum = "093a9383cdd1a5a0bd1a47cdafb49ae0c6dcd0793c8fb8f79768bab423128c9c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anes",
|
"anes",
|
||||||
"cast",
|
"cast",
|
||||||
|
|
@ -761,7 +759,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "117725a109d387c937a1533ce01b450cbde6b88abceea8473c4d7a85853cda3c"
|
checksum = "117725a109d387c937a1533ce01b450cbde6b88abceea8473c4d7a85853cda3c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
"windows-sys 0.48.0",
|
"windows-sys 0.59.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -1593,11 +1591,11 @@ checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "home"
|
name = "home"
|
||||||
version = "0.5.11"
|
version = "0.5.9"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "589533453244b0995c858700322199b2becb13b627df2851f64a2775d024abcf"
|
checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"windows-sys 0.59.0",
|
"windows-sys 0.52.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -3347,7 +3345,7 @@ dependencies = [
|
||||||
"errno",
|
"errno",
|
||||||
"libc",
|
"libc",
|
||||||
"linux-raw-sys 0.9.2",
|
"linux-raw-sys 0.9.2",
|
||||||
"windows-sys 0.59.0",
|
"windows-sys 0.60.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -6234,9 +6232,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasmtimer"
|
name = "wasmtimer"
|
||||||
version = "0.4.1"
|
version = "0.4.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0048ad49a55b9deb3953841fa1fc5858f0efbcb7a18868c899a360269fac1b23"
|
checksum = "d8d49b5d6c64e8558d9b1b065014426f35c18de636895d24893dbbd329743446"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"futures",
|
"futures",
|
||||||
"js-sys",
|
"js-sys",
|
||||||
|
|
@ -6341,7 +6339,7 @@ version = "0.1.9"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb"
|
checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"windows-sys 0.48.0",
|
"windows-sys 0.59.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -6972,7 +6970,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "84e9a772a54b54236b9b744aaaf8d7be01b4d6e99725523cb82cb32d1c81b1d7"
|
checksum = "84e9a772a54b54236b9b744aaaf8d7be01b4d6e99725523cb82cb32d1c81b1d7"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"arbitrary",
|
"arbitrary",
|
||||||
"bzip2 0.5.0",
|
"bzip2 0.5.2",
|
||||||
"crc32fast",
|
"crc32fast",
|
||||||
"crossbeam-utils",
|
"crossbeam-utils",
|
||||||
"displaydoc",
|
"displaydoc",
|
||||||
|
|
|
||||||
|
|
@ -76,7 +76,7 @@ anstream = { version = "0.6.15" }
|
||||||
anyhow = { version = "1.0.89" }
|
anyhow = { version = "1.0.89" }
|
||||||
arcstr = { version = "1.2.0" }
|
arcstr = { version = "1.2.0" }
|
||||||
arrayvec = { version = "0.7.6" }
|
arrayvec = { version = "0.7.6" }
|
||||||
astral-tokio-tar = { version = "0.5.1" }
|
astral-tokio-tar = { version = "0.5.2" }
|
||||||
async-channel = { version = "2.3.1" }
|
async-channel = { version = "2.3.1" }
|
||||||
async-compression = { version = "0.4.12", features = ["bzip2", "gzip", "xz", "zstd"] }
|
async-compression = { version = "0.4.12", features = ["bzip2", "gzip", "xz", "zstd"] }
|
||||||
async-trait = { version = "0.1.82" }
|
async-trait = { version = "0.1.82" }
|
||||||
|
|
|
||||||
|
|
@ -236,6 +236,7 @@ pub async fn untar_gz<R: tokio::io::AsyncRead + Unpin>(
|
||||||
)
|
)
|
||||||
.set_preserve_mtime(false)
|
.set_preserve_mtime(false)
|
||||||
.set_preserve_permissions(false)
|
.set_preserve_permissions(false)
|
||||||
|
.set_allow_external_symlinks(false)
|
||||||
.build();
|
.build();
|
||||||
Ok(untar_in(archive, target.as_ref()).await?)
|
Ok(untar_in(archive, target.as_ref()).await?)
|
||||||
}
|
}
|
||||||
|
|
@ -255,6 +256,7 @@ pub async fn untar_bz2<R: tokio::io::AsyncRead + Unpin>(
|
||||||
)
|
)
|
||||||
.set_preserve_mtime(false)
|
.set_preserve_mtime(false)
|
||||||
.set_preserve_permissions(false)
|
.set_preserve_permissions(false)
|
||||||
|
.set_allow_external_symlinks(false)
|
||||||
.build();
|
.build();
|
||||||
Ok(untar_in(archive, target.as_ref()).await?)
|
Ok(untar_in(archive, target.as_ref()).await?)
|
||||||
}
|
}
|
||||||
|
|
@ -274,6 +276,7 @@ pub async fn untar_zst<R: tokio::io::AsyncRead + Unpin>(
|
||||||
)
|
)
|
||||||
.set_preserve_mtime(false)
|
.set_preserve_mtime(false)
|
||||||
.set_preserve_permissions(false)
|
.set_preserve_permissions(false)
|
||||||
|
.set_allow_external_symlinks(false)
|
||||||
.build();
|
.build();
|
||||||
Ok(untar_in(archive, target.as_ref()).await?)
|
Ok(untar_in(archive, target.as_ref()).await?)
|
||||||
}
|
}
|
||||||
|
|
@ -293,6 +296,7 @@ pub async fn untar_xz<R: tokio::io::AsyncRead + Unpin>(
|
||||||
)
|
)
|
||||||
.set_preserve_mtime(false)
|
.set_preserve_mtime(false)
|
||||||
.set_preserve_permissions(false)
|
.set_preserve_permissions(false)
|
||||||
|
.set_allow_external_symlinks(false)
|
||||||
.build();
|
.build();
|
||||||
untar_in(archive, target.as_ref()).await?;
|
untar_in(archive, target.as_ref()).await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
@ -311,6 +315,7 @@ pub async fn untar<R: tokio::io::AsyncRead + Unpin>(
|
||||||
tokio_tar::ArchiveBuilder::new(&mut reader as &mut (dyn tokio::io::AsyncRead + Unpin))
|
tokio_tar::ArchiveBuilder::new(&mut reader as &mut (dyn tokio::io::AsyncRead + Unpin))
|
||||||
.set_preserve_mtime(false)
|
.set_preserve_mtime(false)
|
||||||
.set_preserve_permissions(false)
|
.set_preserve_permissions(false)
|
||||||
|
.set_allow_external_symlinks(false)
|
||||||
.build();
|
.build();
|
||||||
untar_in(archive, target.as_ref()).await?;
|
untar_in(archive, target.as_ref()).await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
|
||||||
|
|
@ -1754,13 +1754,14 @@ fn build_with_symlink() -> Result<()> {
|
||||||
build-backend = "hatchling.build"
|
build-backend = "hatchling.build"
|
||||||
"#})?;
|
"#})?;
|
||||||
fs_err::os::unix::fs::symlink(
|
fs_err::os::unix::fs::symlink(
|
||||||
context.temp_dir.child("pyproject.toml.real"),
|
"pyproject.toml.real",
|
||||||
context.temp_dir.child("pyproject.toml"),
|
context.temp_dir.child("pyproject.toml"),
|
||||||
)?;
|
)?;
|
||||||
context
|
context
|
||||||
.temp_dir
|
.temp_dir
|
||||||
.child("src/softlinked/__init__.py")
|
.child("src/softlinked/__init__.py")
|
||||||
.touch()?;
|
.touch()?;
|
||||||
|
fs_err::remove_dir_all(&context.venv)?;
|
||||||
uv_snapshot!(context.filters(), context.build(), @r###"
|
uv_snapshot!(context.filters(), context.build(), @r###"
|
||||||
success: true
|
success: true
|
||||||
exit_code: 0
|
exit_code: 0
|
||||||
|
|
@ -1799,6 +1800,7 @@ fn build_with_hardlink() -> Result<()> {
|
||||||
.temp_dir
|
.temp_dir
|
||||||
.child("src/hardlinked/__init__.py")
|
.child("src/hardlinked/__init__.py")
|
||||||
.touch()?;
|
.touch()?;
|
||||||
|
fs_err::remove_dir_all(&context.venv)?;
|
||||||
uv_snapshot!(context.filters(), context.build(), @r###"
|
uv_snapshot!(context.filters(), context.build(), @r###"
|
||||||
success: true
|
success: true
|
||||||
exit_code: 0
|
exit_code: 0
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue