Skip to main content

ebpf/
error.rs

1// Copyright 2024 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use crate::visitor::{ProgramCounter, Register};
6use linux_uapi::{E2BIG, EACCES, EINVAL, bpf_map_type};
7
8/// An error reported by the eBPF verifier, bundling the error kind with the
9/// instruction PC where it occurred (or `None` for program-wide errors).
10#[derive(Debug, PartialEq, Eq, Clone, Copy)]
11pub struct VerifierError {
12    pub kind: VerifierErrorKind,
13    pub pc: Option<ProgramCounter>,
14}
15
16impl VerifierError {
17    /// The Linux errno corresponding to this error.
18    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/// Specific error kinds reported by the eBPF verifier.
35///
36/// Each variant maps to an errno that matches the one returned by the Linux
37/// verifier for the equivalent failure, see [`VerifierErrorKind::errno`].
38#[derive(thiserror::Error, Debug, PartialEq, Eq, Clone, Copy)]
39pub enum VerifierErrorKind {
40    // Program-level limits.
41    #[error("ebpf program too long")]
42    ProgramTooLarge,
43
44    #[error("verification complexity limit exceeded")]
45    ComplexityLimitExceeded,
46
47    // Malformed instructions.
48    #[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    // Control flow.
73    #[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    // Map references in lddw.
83    #[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    // Helper arguments.
93    #[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    // Resources.
109    #[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    // Memory access.
119    #[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    // Struct access.
144    #[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    // Stack access.
154    #[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    // Registers.
182    #[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    // Packet access.
192    #[error("R{0} is not a packet")]
193    RegisterNotPacket(Register),
194
195    #[error("access to unwritten offset")]
196    UninitializedPacketOffset,
197}
198
199impl VerifierErrorKind {
200    /// The Linux errno corresponding to this error.
201    pub fn errno(&self) -> u32 {
202        match self {
203            // Program-level limits.
204            Self::ProgramTooLarge | Self::ComplexityLimitExceeded => E2BIG,
205
206            // Structural errors: malformed instructions, invalid control flow, and invalid
207            // references to maps or helpers.
208            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            // Type, bounds and permission violations.
227            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        // Program-level limits map to E2BIG.
286        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        // Structural errors map to EINVAL.
294        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        // Type, bounds, and permission violations map to EACCES.
313        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}