- Notifications
You must be signed in to change notification settings - Fork 1.9k
/
Copy pathtest_uffd.py
137 lines (104 loc) · 4.05 KB
/
test_uffd.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
# Copyright 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved.
# SPDX-License-Identifier: Apache-2.0
"""Test UFFD related functionality when resuming from snapshot."""
importos
importre
importpytest
importrequests
fromframework.utilsimportTimeout, check_output
fromframework.utils_uffdimportspawn_pf_handler, uffd_handler
@pytest.fixture(scope="function", name="snapshot")
defsnapshot_fxt(microvm_factory, guest_kernel_linux_5_10, rootfs):
"""Create a snapshot of a microVM."""
basevm=microvm_factory.build(guest_kernel_linux_5_10, rootfs)
basevm.spawn()
basevm.basic_config(vcpu_count=2, mem_size_mib=256)
basevm.add_net_iface()
# Add a memory balloon.
basevm.api.balloon.put(
amount_mib=0, deflate_on_oom=True, stats_polling_interval_s=0
)
basevm.start()
# Create base snapshot.
snapshot=basevm.snapshot_full()
basevm.kill()
yieldsnapshot
deftest_bad_socket_path(uvm_plain, snapshot):
"""
Test error scenario when socket path does not exist.
"""
vm=uvm_plain
vm.spawn()
jailed_vmstate=vm.create_jailed_resource(snapshot.vmstate)
expected_msg=re.escape(
"Load snapshot error: Failed to restore from snapshot: Failed to load guest "
"memory: Error creating guest memory from uffd: Failed to connect to UDS Unix stream: No "
"such file or directory (os error 2)"
)
withpytest.raises(RuntimeError, match=expected_msg):
vm.api.snapshot_load.put(
mem_backend={"backend_type": "Uffd", "backend_path": "inexistent"},
snapshot_path=jailed_vmstate,
)
vm.mark_killed()
deftest_unbinded_socket(uvm_plain, snapshot):
"""
Test error scenario when PF handler has not yet called bind on socket.
"""
vm=uvm_plain
vm.spawn()
jailed_vmstate=vm.create_jailed_resource(snapshot.vmstate)
socket_path=os.path.join(vm.path, "firecracker-uffd.sock")
check_output("touch {}".format(socket_path))
jailed_sock_path=vm.create_jailed_resource(socket_path)
expected_msg=re.escape(
"Load snapshot error: Failed to restore from snapshot: Failed to load guest "
"memory: Error creating guest memory from uffd: Failed to connect to UDS Unix stream: "
"Connection refused (os error 111)"
)
withpytest.raises(RuntimeError, match=expected_msg):
vm.api.snapshot_load.put(
mem_backend={"backend_type": "Uffd", "backend_path": jailed_sock_path},
snapshot_path=jailed_vmstate,
)
vm.mark_killed()
deftest_valid_handler(uvm_plain, snapshot):
"""
Test valid uffd handler scenario.
"""
vm=uvm_plain
vm.memory_monitor=None
vm.spawn()
# Spawn page fault handler process.
spawn_pf_handler(vm, uffd_handler("on_demand"), snapshot)
vm.restore_from_snapshot(resume=True)
# Inflate balloon.
vm.api.balloon.patch(amount_mib=200)
# Verify if the restored guest works.
vm.ssh.check_output("true")
# Deflate balloon.
vm.api.balloon.patch(amount_mib=0)
# Verify if the restored guest works.
vm.ssh.check_output("true")
deftest_malicious_handler(uvm_plain, snapshot):
"""
Test malicious uffd handler scenario.
The page fault handler panics when receiving a page fault,
so no events are handled and snapshot memory regions cannot be
loaded into memory. In this case, Firecracker is designed to freeze,
instead of silently switching to having the kernel handle page
faults, so that it becomes obvious that something went wrong.
"""
vm=uvm_plain
vm.memory_monitor=None
vm.spawn()
# Spawn page fault handler process.
spawn_pf_handler(vm, uffd_handler("malicious"), snapshot)
# We expect Firecracker to freeze while resuming from a snapshot
# due to the malicious handler's unavailability.
try:
withTimeout(seconds=30):
vm.restore_from_snapshot(resume=True)
assertFalse, "Firecracker should freeze"
except (TimeoutError, requests.exceptions.ReadTimeout):
pass