mirror of
https://github.com/GNS3/gns3-server.git
synced 2026-08-27 12:30:13 +03:00
test: add tests for unvalidated symlink creation in import_project
This commit is contained in:
parent
a225622a6e
commit
b797981a65
@ -169,7 +169,11 @@ async def import_project(
|
|||||||
|
|
||||||
def _create_symbolic_links(zip_file, path):
|
def _create_symbolic_links(zip_file, path):
|
||||||
"""
|
"""
|
||||||
Materialise symlink entries, refusing any target that escapes `path`.
|
Manually create symbolic links (if any) because ZipFile does not support it.
|
||||||
|
Refuse any target that escapes `path`.
|
||||||
|
|
||||||
|
:param zip_file: ZipFile instance
|
||||||
|
:param path: project location
|
||||||
"""
|
"""
|
||||||
|
|
||||||
path_root = os.path.realpath(path) + os.sep
|
path_root = os.path.realpath(path) + os.sep
|
||||||
|
|||||||
@ -19,6 +19,8 @@ import os
|
|||||||
import uuid
|
import uuid
|
||||||
import json
|
import json
|
||||||
import zipfile
|
import zipfile
|
||||||
|
import pytest
|
||||||
|
import aiohttp
|
||||||
|
|
||||||
from tests.utils import asyncio_patch, AsyncioMagicMock
|
from tests.utils import asyncio_patch, AsyncioMagicMock
|
||||||
from unittest.mock import patch, MagicMock
|
from unittest.mock import patch, MagicMock
|
||||||
@ -117,36 +119,48 @@ async def write_file(path, z):
|
|||||||
f.write(chunk)
|
f.write(chunk)
|
||||||
|
|
||||||
|
|
||||||
async def test_import_project_containing_symlink(tmpdir, controller):
|
@pytest.fixture
|
||||||
|
def export_project_with_symlink(tmpdir, controller):
|
||||||
|
async def _export(symlink_target):
|
||||||
|
project = Project(controller=controller, name="test")
|
||||||
|
project.dump = MagicMock()
|
||||||
|
|
||||||
project = Project(controller=controller, name="test")
|
topology = {
|
||||||
project.dump = MagicMock()
|
"project_id": str(uuid.uuid4()),
|
||||||
path = project.path
|
"name": "test",
|
||||||
|
"auto_open": True,
|
||||||
|
"auto_start": True,
|
||||||
|
"topology": {
|
||||||
|
},
|
||||||
|
"version": "2.0.0"
|
||||||
|
}
|
||||||
|
|
||||||
|
with open(os.path.join(project.path, "project.gns3"), 'w+') as f:
|
||||||
|
json.dump(topology, f)
|
||||||
|
|
||||||
|
os.makedirs(os.path.join(project.path, "vm1", "dynamips"))
|
||||||
|
symlink_path = os.path.join(project.path, "vm1", "dynamips", "symlink")
|
||||||
|
os.symlink(symlink_target, symlink_path)
|
||||||
|
|
||||||
|
zip_path = str(tmpdir / "project.zip")
|
||||||
|
with aiozipstream.ZipFile() as z:
|
||||||
|
with patch("gns3server.compute.Dynamips.get_images_directory", return_value=str(tmpdir / "IOS"),):
|
||||||
|
await export_project(z, project, str(tmpdir), include_images=False)
|
||||||
|
await write_file(zip_path, z)
|
||||||
|
|
||||||
|
return zip_path
|
||||||
|
|
||||||
|
return _export
|
||||||
|
|
||||||
|
|
||||||
|
async def test_import_project_containing_symlink(controller, export_project_with_symlink):
|
||||||
|
"""
|
||||||
|
Test importing a project containing a valid symlink (target inside the project directory).
|
||||||
|
"""
|
||||||
|
|
||||||
project_id = str(uuid.uuid4())
|
project_id = str(uuid.uuid4())
|
||||||
topology = {
|
symlink_target = "../symlink_target"
|
||||||
"project_id": str(uuid.uuid4()),
|
zip_path = await export_project_with_symlink(symlink_target)
|
||||||
"name": "test",
|
|
||||||
"auto_open": True,
|
|
||||||
"auto_start": True,
|
|
||||||
"topology": {
|
|
||||||
},
|
|
||||||
"version": "2.0.0"
|
|
||||||
}
|
|
||||||
|
|
||||||
with open(os.path.join(path, "project.gns3"), 'w+') as f:
|
|
||||||
json.dump(topology, f)
|
|
||||||
|
|
||||||
os.makedirs(os.path.join(path, "vm1", "dynamips"))
|
|
||||||
symlink_path = os.path.join(project.path, "vm1", "dynamips", "symlink")
|
|
||||||
symlink_target = "/tmp/anywhere"
|
|
||||||
os.symlink(symlink_target, symlink_path)
|
|
||||||
|
|
||||||
zip_path = str(tmpdir / "project.zip")
|
|
||||||
with aiozipstream.ZipFile() as z:
|
|
||||||
with patch("gns3server.compute.Dynamips.get_images_directory", return_value=str(tmpdir / "IOS"),):
|
|
||||||
await export_project(z, project, str(tmpdir), include_images=False)
|
|
||||||
await write_file(zip_path, z)
|
|
||||||
|
|
||||||
with open(zip_path, "rb") as f:
|
with open(zip_path, "rb") as f:
|
||||||
project = await import_project(controller, project_id, f)
|
project = await import_project(controller, project_id, f)
|
||||||
@ -158,6 +172,36 @@ async def test_import_project_containing_symlink(tmpdir, controller):
|
|||||||
assert os.readlink(symlink_path) == symlink_target
|
assert os.readlink(symlink_path) == symlink_target
|
||||||
|
|
||||||
|
|
||||||
|
async def test_import_project_containing_absolute_symlink(controller, export_project_with_symlink):
|
||||||
|
"""
|
||||||
|
Test importing a project containing an absolute symlink.
|
||||||
|
This should fail because absolute symlinks are not allowed for security reasons.
|
||||||
|
"""
|
||||||
|
|
||||||
|
project_id = str(uuid.uuid4())
|
||||||
|
symlink_target = "/tmp/anywhere"
|
||||||
|
zip_path = await export_project_with_symlink(symlink_target)
|
||||||
|
|
||||||
|
with pytest.raises(aiohttp.web.HTTPConflict):
|
||||||
|
with open(zip_path, "rb") as f:
|
||||||
|
await import_project(controller, project_id, f)
|
||||||
|
|
||||||
|
|
||||||
|
async def test_import_project_containing_escaping_symlink(controller, export_project_with_symlink):
|
||||||
|
"""
|
||||||
|
Test importing a project containing a symlink that escapes the project directory.
|
||||||
|
This should fail because symlinks that escape the project directory are not allowed for security reasons.
|
||||||
|
"""
|
||||||
|
|
||||||
|
project_id = str(uuid.uuid4())
|
||||||
|
symlink_target = "../../../../symlink_target"
|
||||||
|
zip_path = await export_project_with_symlink(symlink_target)
|
||||||
|
|
||||||
|
with pytest.raises(aiohttp.web.HTTPConflict):
|
||||||
|
with open(zip_path, "rb") as f:
|
||||||
|
await import_project(controller, project_id, f)
|
||||||
|
|
||||||
|
|
||||||
async def test_import_upgrade(tmpdir, controller):
|
async def test_import_upgrade(tmpdir, controller):
|
||||||
"""
|
"""
|
||||||
Topology made for previous GNS3 version are upgraded during the process
|
Topology made for previous GNS3 version are upgraded during the process
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user