ebpf/
elf.rs

1// Copyright (C) 2017 - Will Glozer. All rights reserved.
2
3use std::error;
4use std::ffi::CString;
5use std::rc::Rc;
6use std::fmt;
7use std::mem;
8use byteorder::{ByteOrder, LE};
9use errno::Errno;
10use xmas_elf::ElfFile;
11use xmas_elf::sections::SectionHeader;
12use xmas_elf::sections::SectionData::*;
13use xmas_elf::sections::ShType::*;
14use xmas_elf::symbol_table::Entry;
15use xmas_elf::symbol_table::Binding::*;
16use zero::read_array;
17use bpf::{self, Kind, Program};
18use ffi::*;
19use sys;
20use self::Error::*;
21use self::Item::*;
22use self::Kind::*;
23
24#[derive(Debug)]
25pub struct Loader {
26    pub code:    Vec<Code>,
27    pub maps:    Vec<Map>,
28    pub rels:    Vec<Relocation>,
29    pub symbols: Vec<Symbol>,
30    pub license: CString,
31    pub version: u32,
32}
33
34pub struct Code {
35    pub symbol: Symbol,
36    pub kind:   Kind,
37    pub code:   Vec<bpf_insn>,
38}
39
40#[derive(Debug)]
41pub struct Map {
42    pub symbol: Symbol,
43    pub create: bpf_map_create_arg,
44}
45
46#[derive(Debug)]
47pub struct Relocation {
48    pub section: u16,
49    pub offset:  usize,
50    pub symbol:  Symbol,
51}
52
53#[derive(Debug, Clone, Eq, PartialEq)]
54pub struct Symbol {
55    pub section: u16,
56    pub name:    String,
57    pub value:   u64,
58}
59
60#[derive(Debug)]
61pub enum Error {
62    ELF(&'static str),
63    Invalid(Item),
64    Missing(Item),
65    Syscall(Errno),
66    Program(sys::Error),
67}
68
69#[derive(Debug)]
70pub enum Item {
71    License,
72    Map,
73    Version,
74    Symbol,
75}
76
77impl Loader {
78    pub fn new(bytes: &[u8]) -> Result<Self, Error> {
79        let elf = ElfFile::new(bytes)?;
80
81        let mut loader = Loader {
82            code:    Vec::new(),
83            maps:    Vec::new(),
84            rels:    Vec::new(),
85            symbols: Vec::new(),
86            license: CString::default(),
87            version: 0,
88        };
89
90        for (index, sec) in elf.section_iter().enumerate() {
91            let kind = sec.get_type()?;
92            let name = sec.get_name(&elf);
93            let data = match sec.size() {
94                n if n > 0 => sec.raw_data(&elf),
95                _          => &[],
96            };
97
98            match (kind, name) {
99                (ProgBits, Ok("maps"),  ) => loader.maps.extend(maps(data, &elf, index)?),
100                (ProgBits, Ok("license")) => loader.license = license(data)?,
101                (ProgBits, Ok("version")) => loader.version = version(data)?,
102                (ProgBits, Ok(name),    ) => loader.code.extend(code(name, &elf, index)?),
103                (Rel,      _,           ) => loader.rels.extend(relocations(sec, &elf)?),
104                _                         => (),
105            };
106
107            loader.symbols.extend(symbols(&elf, index as u16)?);
108        }
109
110        Ok(loader)
111    }
112
113    pub fn load(&mut self) -> Result<Vec<Program>, Error> {
114        let rels = &self.rels;
115        let maps = self.maps.iter().flat_map(|map| {
116            let rels: Vec<_> = rels.iter().filter(|r| r.symbol == map.symbol).collect();
117
118            let arg = bpf_map_create_arg {
119                map_name:    sys::name(&map.symbol.name),
120                map_type:    map.create.map_type,
121                key_size:    map.create.key_size,
122                val_size:    map.create.val_size,
123                max_entries: map.create.max_entries,
124                map_flags:   0,
125                .. Default::default()
126            };
127
128            rels.first().cloned().map(|_| {
129                let fd = sys::bpf_create_map(&arg)?;
130                Ok((Rc::new(bpf::Map {
131                    name:  map.symbol.name.to_owned(),
132                    fd:    fd,
133                    ksize: arg.key_size    as usize,
134                    vsize: arg.val_size    as usize,
135                    limit: arg.max_entries as usize,
136                }), rels))
137            })
138        }).collect::<Result<Vec<_>, Error>>()?;
139
140        let license = &self.license;
141        let version = self.version;
142        let mut log = [0u8; 65535];
143
144        self.code.iter_mut().map(|ref mut code| {
145            let section = code.symbol.section;
146            let name    = code.symbol.name.clone();
147            let kind    = code.kind.clone();
148            let code    = &mut code.code;
149
150            let maps = maps.iter().flat_map(|&(ref map, ref rels)| {
151                let mut maps = rels.iter().filter(|r| r.section == section).map(|rel| {
152                    let offset = rel.offset / mem::size_of::<bpf_insn>();
153                    let insn   = &mut code[offset as usize];
154
155                    insn.regs |= BPF_PSEUDO_MAP_FD << 4;
156                    insn.imm   = map.fd;
157
158                    Rc::clone(map)
159                }).collect::<Vec<_>>();
160
161                maps.dedup_by_key(|map| map.fd);
162
163                maps
164            }).collect::<Vec<_>>();
165
166            let arg = bpf_prog_load_arg {
167                prog_name:    sys::name(&name),
168                prog_type:    prog_type(&kind) as u32,
169                insns:        code.as_ptr()    as u64,
170                insn_cnt:     code.len()       as u32,
171                license:      license.as_ptr() as u64,
172                kern_version: version          as u32,
173                .. Default::default()
174            };
175
176            let fd = sys::bpf_prog_load(&arg, &mut log)?;
177
178            Ok(Program{ name, kind, fd, maps })
179        }).collect()
180    }
181}
182
183fn relocations(sec: SectionHeader, elf: &ElfFile) -> Result<Vec<Relocation>, Error> {
184    let symtab  = sec.link() as u16;
185    let section = sec.info() as u16;
186
187    let rel = |offset: usize, symbol: u32| {
188        Ok(Relocation {
189            section: section,
190            offset:  offset,
191            symbol:  resolve(elf, symtab, symbol as usize)?,
192        })
193    };
194
195    match sec.get_data(elf)? {
196        Rel32(rs) => rs.iter().map(|r| rel(r.get_offset() as usize, r.get_symbol_table_index())).collect(),
197        Rel64(rs) => rs.iter().map(|r| rel(r.get_offset() as usize, r.get_symbol_table_index())).collect(),
198        _         => unreachable!(),
199    }
200}
201
202fn code(name: &str, elf: &ElfFile, index: usize) -> Result<Option<Code>, Error> {
203    let index = index as u16;
204    let sec   = elf.section_header(index)?;
205    let syms  = symbols(elf, index)?;
206    let data  = sec.raw_data(&elf);
207
208    let code = |kind| {
209        syms.first().map(|sym| {
210            Code {
211                symbol: sym.clone(),
212                kind:   kind,
213                code:   read_array(data).to_vec(),
214            }
215        })
216    };
217
218    let mut split = name.splitn(2, '/');
219    let code = match (split.next(), split.next()) {
220        (Some("kprobe"),     Some(event)) => code(Kprobe(event.into())),
221        (Some("kretprobe"),  Some(event)) => code(Kretprobe(event.into())),
222        (Some("tracepoint"), Some(event)) => code(Tracepoint(event.into())),
223        (Some("xdp"),        Some(name))  => code(XDP(name.into())),
224        _                                 => None,
225    };
226
227    Ok(code)
228}
229
230fn maps(data: &[u8], elf: &ElfFile, index: usize) -> Result<Vec<Map>, Error> {
231    let args = read_array(data);
232    symbols(elf, index as u16)?.iter().map(|sym| {
233        let size   = mem::size_of::<bpf_map_create_arg>();
234        let offset = sym.value as usize / size;
235        let create = *args.get(offset).ok_or(Missing(Map))?;
236        let symbol = sym.clone();
237        Ok(Map { create, symbol })
238    }).collect()
239}
240
241fn license(data: &[u8]) -> Result<CString, Error> {
242    let n    = data.len() - 1;
243    let data = data[..n].to_vec();
244    CString::new(data).map_err(|_| Invalid(License))
245}
246
247fn version(data: &[u8]) -> Result<u32, Error> {
248    match data.len() {
249        4 => Ok(LE::read_u32(data)),
250        _ => Err(Invalid(Version)),
251    }
252}
253
254fn resolve(elf: &ElfFile, section: u16, index: usize) -> Result<Symbol, Error> {
255    let symtab = match elf.header.pt2.sh_count() {
256        n if n > section => elf.section_header(section)?,
257        _                => return Err(Missing(Symbol)),
258    };
259
260    match symtab.get_data(elf)? {
261        SymbolTable32(entries) => entries.get(index).map(|e| sym(e, elf)),
262        SymbolTable64(entries) => entries.get(index).map(|e| sym(e, elf)),
263        _                      => None,
264    }.unwrap_or(Err(Missing(Symbol)))
265}
266
267fn symbols(elf: &ElfFile, section: u16) -> Result<Vec<Symbol>, Error> {
268    let filter = |e: &Entry| {
269        match (e.get_binding(), e.shndx() == section) {
270            (Ok(Global), true) => Some(sym(e, elf)),
271            _                  => None,
272        }
273    };
274
275    let mut syms = Vec::new();
276    for sec in elf.section_iter().filter(|s| s.get_type() == Ok(SymTab)) {
277        match sec.get_data(elf)? {
278            SymbolTable32(entries) => syms.extend(entries.iter().flat_map(|e| filter(e))),
279            SymbolTable64(entries) => syms.extend(entries.iter().flat_map(|e| filter(e))),
280            _                      => (),
281        }
282    }
283
284    syms.into_iter().collect()
285}
286
287fn sym(e: &Entry, elf: &ElfFile) -> Result<Symbol, Error> {
288    Ok(Symbol {
289        section: e.shndx(),
290        name:    e.get_name(elf)?.into(),
291        value:   e.value(),
292    })
293}
294
295fn prog_type(kind: &Kind) -> bpf_prog_type {
296    use ffi::bpf_prog_type::*;
297    match *kind {
298        Kprobe(..)     => BPF_PROG_TYPE_KPROBE,
299        Kretprobe(..)  => BPF_PROG_TYPE_KPROBE,
300        Socket         => BPF_PROG_TYPE_SOCKET_FILTER,
301        Tracepoint(..) => BPF_PROG_TYPE_TRACEPOINT,
302        XDP(..)        => BPF_PROG_TYPE_XDP,
303    }
304}
305
306impl From<&'static str> for Error {
307    fn from(err: &'static str) -> Self {
308        ELF(err)
309    }
310}
311
312impl From<Errno> for Error {
313    fn from(err: Errno) -> Self {
314        Syscall(err)
315    }
316}
317
318impl From<sys::Error> for Error {
319    fn from(err: sys::Error) -> Self {
320        Program(err)
321    }
322}
323
324impl error::Error for Error {
325    fn description(&self) -> &str {
326        match self {
327            ELF(..)     => "ELF loader error",
328            Invalid(..) => "invalid item",
329            Missing(..) => "missing item",
330            Syscall(..) => "syscall error",
331            Program(..) => "program error",
332        }
333    }
334
335    fn cause(&self) -> Option<&error::Error> {
336        match self {
337            ELF(..)     => None,
338            Invalid(..) => None,
339            Missing(..) => None,
340            Syscall(..) => None,
341            Program(e)  => Some(e),
342        }
343    }
344}
345
346impl fmt::Display for Error {
347    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
348        write!(f, "{:?}", self)
349    }
350}
351
352impl fmt::Debug for Code {
353    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
354        let count = format!("[{} instructions]", self.code.len());
355        f.debug_struct("Code")
356            .field("kind", &self.kind)
357            .field("code", &count)
358            .finish()
359
360    }
361}