Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(134)

Side by Side Diff: sandbox/linux/seccomp-bpf/codegen.cc

Issue 761903003: Update from https://crrev.com/306655 (Closed) Base URL: git@github.com:domokit/mojo.git@master
Patch Set: Created 6 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « sandbox/linux/seccomp-bpf/codegen.h ('k') | sandbox/linux/seccomp-bpf/codegen_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "sandbox/linux/seccomp-bpf/codegen.h" 5 #include "sandbox/linux/seccomp-bpf/codegen.h"
6 6
7 #include <linux/filter.h> 7 #include <linux/filter.h>
8 8
9 #include <limits> 9 #include <limits>
10 #include <utility> 10 #include <utility>
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
42 // sequences. 42 // sequences.
43 43
44 namespace sandbox { 44 namespace sandbox {
45 45
46 // kBranchRange is the maximum value that can be stored in 46 // kBranchRange is the maximum value that can be stored in
47 // sock_filter's 8-bit jt and jf fields. 47 // sock_filter's 8-bit jt and jf fields.
48 const size_t kBranchRange = std::numeric_limits<uint8_t>::max(); 48 const size_t kBranchRange = std::numeric_limits<uint8_t>::max();
49 49
50 const CodeGen::Node CodeGen::kNullNode; 50 const CodeGen::Node CodeGen::kNullNode;
51 51
52 CodeGen::CodeGen() : program_(), memos_() { 52 CodeGen::CodeGen() : program_(), equivalent_(), memos_() {
53 } 53 }
54 54
55 CodeGen::~CodeGen() { 55 CodeGen::~CodeGen() {
56 } 56 }
57 57
58 void CodeGen::Compile(CodeGen::Node head, Program* out) { 58 void CodeGen::Compile(CodeGen::Node head, Program* out) {
59 DCHECK(out); 59 DCHECK(out);
60 out->assign(program_.rbegin() + Offset(head), program_.rend()); 60 out->assign(program_.rbegin() + Offset(head), program_.rend());
61 } 61 }
62 62
(...skipping 11 matching lines...) Expand all
74 return *node; 74 return *node;
75 } 75 }
76 76
77 CodeGen::Node CodeGen::AppendInstruction(uint16_t code, 77 CodeGen::Node CodeGen::AppendInstruction(uint16_t code,
78 uint32_t k, 78 uint32_t k,
79 Node jt, 79 Node jt,
80 Node jf) { 80 Node jf) {
81 if (BPF_CLASS(code) == BPF_JMP) { 81 if (BPF_CLASS(code) == BPF_JMP) {
82 CHECK_NE(BPF_JA, BPF_OP(code)) << "CodeGen inserts JAs as needed"; 82 CHECK_NE(BPF_JA, BPF_OP(code)) << "CodeGen inserts JAs as needed";
83 83
84 // We need to check |jt| twice because it might get pushed 84 // Optimally adding jumps is rather tricky, so we use a quick
85 // out-of-range by appending a jump for |jf|. 85 // approximation: by artificially reducing |jt|'s range, |jt| will
86 jt = WithinRange(jt, kBranchRange); 86 // stay within its true range even if we add a jump for |jf|.
87 jt = WithinRange(jt, kBranchRange - 1);
87 jf = WithinRange(jf, kBranchRange); 88 jf = WithinRange(jf, kBranchRange);
88 jt = WithinRange(jt, kBranchRange);
89 return Append(code, k, Offset(jt), Offset(jf)); 89 return Append(code, k, Offset(jt), Offset(jf));
90 } 90 }
91 91
92 CHECK_EQ(kNullNode, jf) << "Non-branch instructions shouldn't provide jf"; 92 CHECK_EQ(kNullNode, jf) << "Non-branch instructions shouldn't provide jf";
93 if (BPF_CLASS(code) == BPF_RET) { 93 if (BPF_CLASS(code) == BPF_RET) {
94 CHECK_EQ(kNullNode, jt) << "Return instructions shouldn't provide jt"; 94 CHECK_EQ(kNullNode, jt) << "Return instructions shouldn't provide jt";
95 } else { 95 } else {
96 // For non-branch/non-return instructions, execution always 96 // For non-branch/non-return instructions, execution always
97 // proceeds to the next instruction; so we need to arrange for 97 // proceeds to the next instruction; so we need to arrange for
98 // that to be |jt|. 98 // that to be |jt|.
99 jt = WithinRange(jt, 0); 99 jt = WithinRange(jt, 0);
100 CHECK_EQ(0U, Offset(jt)) << "ICE: Failed to setup next instruction";
100 } 101 }
101 return Append(code, k, 0, 0); 102 return Append(code, k, 0, 0);
102 } 103 }
103 104
104 CodeGen::Node CodeGen::WithinRange(Node target, size_t range) { 105 CodeGen::Node CodeGen::WithinRange(Node target, size_t range) {
105 if (Offset(target) > range) { 106 // Just use |target| if it's already within range.
106 // TODO(mdempsky): If |range > 0|, we might be able to reuse an 107 if (Offset(target) <= range) {
107 // existing instruction within that range. 108 return target;
108
109 // TODO(mdempsky): If |target| is a branch or return, it might be
110 // possible to duplicate that instruction rather than jump to it.
111
112 // Fall back to emitting a jump instruction.
113 target = Append(BPF_JMP | BPF_JA, Offset(target), 0, 0);
114 } 109 }
115 110
116 CHECK_LE(Offset(target), range) << "ICE: Failed to bring target within range"; 111 // Alternatively, look for an equivalent instruction within range.
117 return target; 112 if (Offset(equivalent_.at(target)) <= range) {
113 return equivalent_.at(target);
114 }
115
116 // Otherwise, fall back to emitting a jump instruction.
117 Node jump = Append(BPF_JMP | BPF_JA, Offset(target), 0, 0);
118 equivalent_.at(target) = jump;
119 return jump;
118 } 120 }
119 121
120 CodeGen::Node CodeGen::Append(uint16_t code, uint32_t k, size_t jt, size_t jf) { 122 CodeGen::Node CodeGen::Append(uint16_t code, uint32_t k, size_t jt, size_t jf) {
121 if (BPF_CLASS(code) == BPF_JMP && BPF_OP(code) != BPF_JA) { 123 if (BPF_CLASS(code) == BPF_JMP && BPF_OP(code) != BPF_JA) {
122 CHECK_LE(jt, kBranchRange); 124 CHECK_LE(jt, kBranchRange);
123 CHECK_LE(jf, kBranchRange); 125 CHECK_LE(jf, kBranchRange);
124 } else { 126 } else {
125 CHECK_EQ(0U, jt); 127 CHECK_EQ(0U, jt);
126 CHECK_EQ(0U, jf); 128 CHECK_EQ(0U, jf);
127 } 129 }
128 130
129 CHECK_LT(program_.size(), static_cast<size_t>(BPF_MAXINSNS)); 131 CHECK_LT(program_.size(), static_cast<size_t>(BPF_MAXINSNS));
132 CHECK_EQ(program_.size(), equivalent_.size());
133
134 Node res = program_.size();
130 program_.push_back(sock_filter{code, jt, jf, k}); 135 program_.push_back(sock_filter{code, jt, jf, k});
131 return program_.size() - 1; 136 equivalent_.push_back(res);
137 return res;
132 } 138 }
133 139
134 size_t CodeGen::Offset(Node target) const { 140 size_t CodeGen::Offset(Node target) const {
135 CHECK_LT(target, program_.size()) << "Bogus offset target node"; 141 CHECK_LT(target, program_.size()) << "Bogus offset target node";
136 return (program_.size() - 1) - target; 142 return (program_.size() - 1) - target;
137 } 143 }
138 144
139 // TODO(mdempsky): Move into a general base::Tuple helper library. 145 // TODO(mdempsky): Move into a general base::Tuple helper library.
140 bool CodeGen::MemoKeyLess::operator()(const MemoKey& lhs, 146 bool CodeGen::MemoKeyLess::operator()(const MemoKey& lhs,
141 const MemoKey& rhs) const { 147 const MemoKey& rhs) const {
142 if (lhs.a != rhs.a) 148 if (lhs.a != rhs.a)
143 return lhs.a < rhs.a; 149 return lhs.a < rhs.a;
144 if (lhs.b != rhs.b) 150 if (lhs.b != rhs.b)
145 return lhs.b < rhs.b; 151 return lhs.b < rhs.b;
146 if (lhs.c != rhs.c) 152 if (lhs.c != rhs.c)
147 return lhs.c < rhs.c; 153 return lhs.c < rhs.c;
148 if (lhs.d != rhs.d) 154 if (lhs.d != rhs.d)
149 return lhs.d < rhs.d; 155 return lhs.d < rhs.d;
150 return false; 156 return false;
151 } 157 }
152 158
153 } // namespace sandbox 159 } // namespace sandbox
OLDNEW
« no previous file with comments | « sandbox/linux/seccomp-bpf/codegen.h ('k') | sandbox/linux/seccomp-bpf/codegen_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698