1use crate::visitor::{ProgramCounter, Register};
6use linux_uapi::{E2BIG, EACCES, EINVAL, bpf_map_type};
7
8#[derive(Debug, PartialEq, Eq, Clone, Copy)]
11pub struct VerifierError {
12 pub kind: VerifierErrorKind,
13 pub pc: Option<ProgramCounter>,
14}
15
16impl VerifierError {
17 pub fn errno(&self) -> u32 {
19 self.kind.errno()
20 }
21}
22
23impl std::fmt::Display for VerifierError {
24 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
25 match self.pc {
26 Some(pc) => write!(f, "at PC {pc}: {}", self.kind),
27 None => self.kind.fmt(f),
28 }
29 }
30}
31
32impl std::error::Error for VerifierError {}
33
34#[derive(thiserror::Error, Debug, PartialEq, Eq, Clone, Copy)]
39pub enum VerifierErrorKind {
40 #[error("ebpf program too long")]
42 ProgramTooLarge,
43
44 #[error("verification complexity limit exceeded")]
45 ComplexityLimitExceeded,
46
47 #[error("invalid op code {0:x}")]
49 InvalidOpcode(u8),
50
51 #[error("invalid byte swap width: {0}")]
52 InvalidByteSwapWidth(i32),
53
54 #[error("invalid atomic operation {0:x}")]
55 InvalidAtomicOp(u8),
56
57 #[error("unsupported call type {0}")]
58 UnsupportedCallType(u8),
59
60 #[error("lddw is missing its second instruction")]
61 IncompleteLddw,
62
63 #[error("second instruction of lddw has non-zero fields")]
64 MalformedLddw,
65
66 #[error("unsupported lddw source {0}")]
67 UnsupportedLddwSource(u8),
68
69 #[error("R{0} is invalid")]
70 InvalidRegister(Register),
71
72 #[error("jump outside of program")]
74 JumpOutOfBounds,
75
76 #[error("execution falls off the end of the program")]
77 FellOffProgramEnd,
78
79 #[error("unknown helper {0}")]
80 UnknownHelper(u32),
81
82 #[error("lddw with invalid map index: {0}")]
84 InvalidMapIndex(u32),
85
86 #[error("lddw map value requires an array map, map at index {0} has type {1}")]
87 LddwMapValueNotArray(u32, bpf_map_type),
88
89 #[error("array has no entry")]
90 EmptyArrayMap,
91
92 #[error("buffer size is not a constant")]
94 NonConstantBufferSize,
95
96 #[error("helper expects program argument {0}")]
97 ExpectedProgramArgument(u8),
98
99 #[error("incorrect type for helper argument {0}")]
100 HelperArgumentTypeMismatch(usize),
101
102 #[error("helper argument {0} is not a map")]
103 HelperArgumentNotMap(u8),
104
105 #[error("map type {0} not allowed in helper")]
106 InvalidMapTypeForHelper(bpf_map_type),
107
108 #[error("access to released resource")]
110 UseAfterRelease,
111
112 #[error("resource already released")]
113 DoubleRelease,
114
115 #[error("some resources have not been released at exit time")]
116 ResourceLeak,
117
118 #[error("write into map forbidden")]
120 WriteToReadOnlyMap,
121
122 #[error("write into read-only memory forbidden")]
123 WriteToReadOnlyMemory,
124
125 #[error("out of bounds memory access")]
126 OutOfBoundsMemoryAccess,
127
128 #[error("pointer offset overflow")]
129 PointerOffsetOverflow,
130
131 #[error("pointer arithmetic with uninitialized scalar")]
132 UninitializedPointerArithmetic,
133
134 #[error("store through a non-pointer value")]
135 StoreToNonPointer,
136
137 #[error("load through a non-pointer value")]
138 LoadFromNonPointer,
139
140 #[error("cannot store a pointer or an uninitialized value to memory")]
141 InvalidStoredValue,
142
143 #[error("no struct field at this offset")]
145 InvalidStructFieldAccess,
146
147 #[error("store to a read-only field")]
148 WriteToReadOnlyField,
149
150 #[error("inconsistent struct field access")]
151 InconsistentStructFieldAccess,
152
153 #[error("variable stack offset")]
155 VariableStackOffset,
156
157 #[error("stack access out of bounds")]
158 StackAccessOutOfBounds,
159
160 #[error("misaligned stack access")]
161 MisalignedStackAccess,
162
163 #[error("misaligned atomic access")]
164 MisalignedAtomicAccess,
165
166 #[error("atomic access is allowed only to the stack and map values")]
167 AtomicAccessNotAllowed,
168
169 #[error("reading unwritten value from the stack")]
170 UninitializedStackRead,
171
172 #[error("reading non scalar value from the stack")]
173 NonScalarStackRead,
174
175 #[error("cannot store part of a non scalar value on the stack")]
176 PartialNonScalarStackStore,
177
178 #[error("cannot load part of a non scalar value from the stack")]
179 PartialNonScalarStackLoad,
180
181 #[error("R{0} is read-only")]
183 WriteToReadOnlyRegister(Register),
184
185 #[error("non permitted comparison")]
186 InvalidComparison,
187
188 #[error("register 0 is incorrect at exit time")]
189 InvalidReturnValue,
190
191 #[error("R{0} is not a packet")]
193 RegisterNotPacket(Register),
194
195 #[error("access to unwritten offset")]
196 UninitializedPacketOffset,
197}
198
199impl VerifierErrorKind {
200 pub fn errno(&self) -> u32 {
202 match self {
203 Self::ProgramTooLarge | Self::ComplexityLimitExceeded => E2BIG,
205
206 Self::InvalidOpcode(_)
209 | Self::InvalidByteSwapWidth(_)
210 | Self::InvalidAtomicOp(_)
211 | Self::UnsupportedCallType(_)
212 | Self::IncompleteLddw
213 | Self::MalformedLddw
214 | Self::UnsupportedLddwSource(_)
215 | Self::InvalidRegister(_)
216 | Self::JumpOutOfBounds
217 | Self::FellOffProgramEnd
218 | Self::UnknownHelper(_)
219 | Self::InvalidMapIndex(_)
220 | Self::LddwMapValueNotArray(_, _)
221 | Self::EmptyArrayMap
222 | Self::InvalidMapTypeForHelper(_)
223 | Self::ResourceLeak
224 | Self::RegisterNotPacket(_) => EINVAL,
225
226 Self::NonConstantBufferSize
228 | Self::ExpectedProgramArgument(_)
229 | Self::HelperArgumentTypeMismatch(_)
230 | Self::HelperArgumentNotMap(_)
231 | Self::UseAfterRelease
232 | Self::DoubleRelease
233 | Self::WriteToReadOnlyMap
234 | Self::WriteToReadOnlyMemory
235 | Self::OutOfBoundsMemoryAccess
236 | Self::PointerOffsetOverflow
237 | Self::UninitializedPointerArithmetic
238 | Self::StoreToNonPointer
239 | Self::LoadFromNonPointer
240 | Self::InvalidStoredValue
241 | Self::InvalidStructFieldAccess
242 | Self::WriteToReadOnlyField
243 | Self::InconsistentStructFieldAccess
244 | Self::VariableStackOffset
245 | Self::StackAccessOutOfBounds
246 | Self::MisalignedStackAccess
247 | Self::MisalignedAtomicAccess
248 | Self::AtomicAccessNotAllowed
249 | Self::UninitializedStackRead
250 | Self::NonScalarStackRead
251 | Self::PartialNonScalarStackStore
252 | Self::PartialNonScalarStackLoad
253 | Self::WriteToReadOnlyRegister(_)
254 | Self::InvalidComparison
255 | Self::InvalidReturnValue
256 | Self::UninitializedPacketOffset => EACCES,
257 }
258 }
259}
260
261#[derive(thiserror::Error, Debug, PartialEq, Eq)]
262pub enum EbpfError {
263 #[error("Verification error loading program: {0}")]
264 ProgramVerifyError(#[from] VerifierError),
265
266 #[error("Failed to link program: {0}")]
267 ProgramLinkError(String),
268
269 #[error("Invalid cBPF instruction code: 0x{0:x}")]
270 InvalidCbpfInstruction(u16),
271
272 #[error("Invalid cBPF scratch memory offset: 0x{0:x}")]
273 InvalidCbpfScratchOffset(u32),
274
275 #[error("Invalid cBPF jump offset: 0x{0:x}")]
276 InvalidCbpfJumpOffset(u32),
277}
278
279#[cfg(test)]
280mod tests {
281 use super::*;
282
283 #[test]
284 fn test_verifier_error_errno() {
285 assert_eq!(VerifierErrorKind::ProgramTooLarge.errno(), E2BIG);
287 assert_eq!(VerifierErrorKind::ComplexityLimitExceeded.errno(), E2BIG);
288 assert_eq!(
289 VerifierError { kind: VerifierErrorKind::ProgramTooLarge, pc: None }.errno(),
290 E2BIG
291 );
292
293 assert_eq!(VerifierErrorKind::InvalidOpcode(0xff).errno(), EINVAL);
295 assert_eq!(VerifierErrorKind::InvalidByteSwapWidth(8).errno(), EINVAL);
296 assert_eq!(VerifierErrorKind::InvalidAtomicOp(0xff).errno(), EINVAL);
297 assert_eq!(VerifierErrorKind::UnsupportedCallType(1).errno(), EINVAL);
298 assert_eq!(VerifierErrorKind::IncompleteLddw.errno(), EINVAL);
299 assert_eq!(VerifierErrorKind::MalformedLddw.errno(), EINVAL);
300 assert_eq!(VerifierErrorKind::UnsupportedLddwSource(99).errno(), EINVAL);
301 assert_eq!(VerifierErrorKind::InvalidRegister(11).errno(), EINVAL);
302 assert_eq!(VerifierErrorKind::JumpOutOfBounds.errno(), EINVAL);
303 assert_eq!(VerifierErrorKind::FellOffProgramEnd.errno(), EINVAL);
304 assert_eq!(VerifierErrorKind::UnknownHelper(1).errno(), EINVAL);
305 assert_eq!(VerifierErrorKind::InvalidMapIndex(0).errno(), EINVAL);
306 assert_eq!(VerifierErrorKind::LddwMapValueNotArray(0, 1).errno(), EINVAL);
307 assert_eq!(VerifierErrorKind::EmptyArrayMap.errno(), EINVAL);
308 assert_eq!(VerifierErrorKind::InvalidMapTypeForHelper(1).errno(), EINVAL);
309 assert_eq!(VerifierErrorKind::ResourceLeak.errno(), EINVAL);
310 assert_eq!(VerifierErrorKind::RegisterNotPacket(6).errno(), EINVAL);
311
312 assert_eq!(VerifierErrorKind::NonConstantBufferSize.errno(), EACCES);
314 assert_eq!(VerifierErrorKind::ExpectedProgramArgument(0).errno(), EACCES);
315 assert_eq!(VerifierErrorKind::HelperArgumentTypeMismatch(0).errno(), EACCES);
316 assert_eq!(VerifierErrorKind::HelperArgumentNotMap(0).errno(), EACCES);
317 assert_eq!(VerifierErrorKind::UseAfterRelease.errno(), EACCES);
318 assert_eq!(VerifierErrorKind::DoubleRelease.errno(), EACCES);
319 assert_eq!(VerifierErrorKind::WriteToReadOnlyMap.errno(), EACCES);
320 assert_eq!(VerifierErrorKind::WriteToReadOnlyMemory.errno(), EACCES);
321 assert_eq!(VerifierErrorKind::OutOfBoundsMemoryAccess.errno(), EACCES);
322 assert_eq!(VerifierErrorKind::PointerOffsetOverflow.errno(), EACCES);
323 assert_eq!(VerifierErrorKind::UninitializedPointerArithmetic.errno(), EACCES);
324 assert_eq!(VerifierErrorKind::StoreToNonPointer.errno(), EACCES);
325 assert_eq!(VerifierErrorKind::LoadFromNonPointer.errno(), EACCES);
326 assert_eq!(VerifierErrorKind::InvalidStoredValue.errno(), EACCES);
327 assert_eq!(VerifierErrorKind::InvalidStructFieldAccess.errno(), EACCES);
328 assert_eq!(VerifierErrorKind::WriteToReadOnlyField.errno(), EACCES);
329 assert_eq!(VerifierErrorKind::InconsistentStructFieldAccess.errno(), EACCES);
330 assert_eq!(VerifierErrorKind::VariableStackOffset.errno(), EACCES);
331 assert_eq!(VerifierErrorKind::StackAccessOutOfBounds.errno(), EACCES);
332 assert_eq!(VerifierErrorKind::MisalignedStackAccess.errno(), EACCES);
333 assert_eq!(VerifierErrorKind::UninitializedStackRead.errno(), EACCES);
334 assert_eq!(VerifierErrorKind::NonScalarStackRead.errno(), EACCES);
335 assert_eq!(VerifierErrorKind::PartialNonScalarStackStore.errno(), EACCES);
336 assert_eq!(VerifierErrorKind::PartialNonScalarStackLoad.errno(), EACCES);
337 assert_eq!(VerifierErrorKind::WriteToReadOnlyRegister(10).errno(), EACCES);
338 assert_eq!(VerifierErrorKind::InvalidComparison.errno(), EACCES);
339 assert_eq!(VerifierErrorKind::InvalidReturnValue.errno(), EACCES);
340 assert_eq!(VerifierErrorKind::UninitializedPacketOffset.errno(), EACCES);
341 }
342}