summaryrefslogtreecommitdiffstats
path: root/sandbox/linux/seccomp/library.h
blob: e27bfde8708b6e1c3ddf79e74a0334c74b3a3cb3 (plain)
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
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef LIBRARY_H__
#define LIBRARY_H__

#include <elf.h>
#include <functional>
#include <map>
#include <set>
#include <string>
#include <string.h>
#include <sys/mman.h>

#include "maps.h"

#if defined(__x86_64__)
typedef Elf64_Ehdr Elf_Ehdr;
typedef Elf64_Shdr Elf_Shdr;
typedef Elf64_Sym  Elf_Sym;
typedef Elf64_Addr Elf_Addr;
#elif defined(__i386__)
typedef Elf32_Ehdr Elf_Ehdr;
typedef Elf32_Shdr Elf_Shdr;
typedef Elf32_Sym  Elf_Sym;
typedef Elf32_Addr Elf_Addr;
#else
#error Unsupported target platform
#endif

struct SyscallTable;
namespace playground {

class Library {
  friend class Maps;
 public:
  typedef Maps::string string;

  Library() :
      valid_(false),
      isVDSO_(false),
      asr_offset_(0),
      vsys_offset_(0),
      maps_(0),
      image_(0),
      image_size_(0) {
  }

  ~Library();

  void setLibraryInfo(Maps* maps) {
    if (!maps_) {
      maps_ = maps;
    }
  }

  void addMemoryRange(void* start, void* stop, Elf_Addr offset,
                      int prot, int isVDSO) {
    isVDSO_ = isVDSO;
    RangeMap::const_iterator iter = memory_ranges_.find(offset);
    if (iter != memory_ranges_.end()) {
      // It is possible to have overlapping mappings. This is particularly
      // likely to happen with very small programs or libraries. If it does
      // happen, we really only care about the text segment. Look for a
      // mapping that is mapped executable.
      if ((prot & PROT_EXEC) == 0) {
        return;
      }
    }
    memory_ranges_.insert(std::make_pair(offset, Range(start, stop, prot)));
  }

  char *get(Elf_Addr offset, char *buf, size_t len);
  string get(Elf_Addr offset);
  char *getOriginal(Elf_Addr offset, char *buf, size_t len);
  string getOriginal(Elf_Addr offset);

  template<class T>T* get(Elf_Addr offset, T* t) {
    if (!valid_) {
      memset(t, 0, sizeof(T));
      return NULL;
    }
    return reinterpret_cast<T *>(get(offset, reinterpret_cast<char *>(t),
                                     sizeof(T)));
  }

  template<class T>T* getOriginal(Elf_Addr offset, T* t) {
    if (!valid_) {
      memset(t, 0, sizeof(T));
      return NULL;
    }
    return reinterpret_cast<T *>(getOriginal(offset,
                                             reinterpret_cast<char *>(t),
                                             sizeof(T)));
  }

  template<class T>bool set(void *addr, T* value) {
    if (!valid_) {
      return false;
    }
    *reinterpret_cast<T *>(addr) = *value;
    return true;
  }

  template<class T>bool set(Elf_Addr offset, T* value) {
    if (!valid_) {
      return false;
    }
    RangeMap::const_iterator iter = memory_ranges_.lower_bound(offset);
    if (iter == memory_ranges_.end()) {
      return false;
    }
    offset -= iter->first;
    if (offset >
        reinterpret_cast<char *>(iter->second.stop) -
        reinterpret_cast<char *>(iter->second.start) -
        sizeof(T)) {
      return false;
    }
    *reinterpret_cast<T *>(
        reinterpret_cast<char *>(iter->second.start) + offset) = *value;
    return true;
  }

  bool parseElf();
  const Elf_Ehdr* getEhdr();
  const Elf_Shdr* getSection(const string& section);
  int getSectionIndex(const string& section);
  void makeWritable(bool state) const;
  void patchSystemCalls();
  bool isVDSO() const { return isVDSO_; }

 protected:
  bool parseSymbols();

 private:
  class GreaterThan : public std::binary_function<Elf_Addr, Elf_Addr, bool> {
    // We create the RangeMap with a GreaterThan rather than the default
    // comparator, as that allows us to use lower_bound() to find memory
    // mappings.
   public:
    bool operator() (Elf_Addr s1, Elf_Addr s2) const {
      return s1 > s2;
    }
  };

  struct Range {
    Range(void* start, void* stop, int prot) :
        start(start), stop(stop), prot(prot) { }
    void* start;
    void* stop;
    int   prot;
  };

  typedef std::map<Elf_Addr, Range, GreaterThan,
                   SystemAllocator<std::pair<const Elf_Addr,
                                             Range> > > RangeMap;
  typedef std::map<string, std::pair<int, Elf_Shdr>, std::less<string>,
                   SystemAllocator<std::pair<const string,
                                             std::pair<int, Elf_Shdr> > > >
                   SectionTable;
  typedef std::map<string, Elf_Sym, std::less<string>,
                   SystemAllocator<std::pair<const string,
                                             Elf_Sym> > > SymbolTable;
  typedef std::map<string, Elf_Addr, std::less<string>,
                   SystemAllocator<std::pair<const string,
                                             Elf_Addr> > > PltTable;

  char* getBytes(char* dst, const char* src, ssize_t len);
  static bool isSafeInsn(unsigned short insn);
  static int isSimpleSystemCall(char *start, char *end);
  static char* getScratchSpace(const Maps* maps, char* near, int needed,
                               char** extraSpace, int* extraLength);
  void patchSystemCallsInFunction(const Maps* maps, char *start, char *end,
                                  char** extraSpace, int* extraLength);
  int  patchVSystemCalls();
  void patchVDSO(char** extraSpace, int* extraLength);

  RangeMap        memory_ranges_;
  bool            valid_;
  bool            isVDSO_;
  char*           asr_offset_;
  int             vsys_offset_;
  Maps*           maps_;
  Elf_Ehdr        ehdr_;
  SectionTable    section_table_;
  SymbolTable     symbols_;
  PltTable        plt_entries_;
  char*           image_;
  size_t          image_size_;
  static char*    __kernel_vsyscall;
  static char*    __kernel_sigreturn;
  static char*    __kernel_rt_sigreturn;
};

} // namespace

#endif // LIBRARY_H__