Skip to content

Commit 9294d42

Browse files
committed
add ego_largeheap build tag as workaround for heap sizes larger than 16GB
1 parent 411e328 commit 9294d42

File tree

6 files changed

+127
-9
lines changed

6 files changed

+127
-9
lines changed

ego/cli/elf.go

Lines changed: 39 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,12 @@ import (
1919
// ErrErrUnsupportedImportEClient is returned when an EGo binary uses the eclient package instead of the enclave package.
2020
var ErrUnsupportedImportEClient = errors.New("unsupported import: github.com/edgelesssys/ego/eclient")
2121

22+
// ErrLargeHeapWithSmallHeapSize is returned when a binary is built with ego_largehap, but the heap size is set to less than 512MB.
23+
var ErrLargeHeapWithSmallHeapSize = errors.New("large heap is enabled, but heapSize is too small")
24+
25+
// ErrNoLargeHeapWithLargeHeapSize is returned when a binary is built without ego_largeheap, but the heap size is set to more than 16GB.
26+
var ErrNoLargeHeapWithLargeHeapSize = errors.New("this heapSize requires large heap mode")
27+
2228
func (c *Cli) embedConfigAsPayload(path string, jsonData []byte) error {
2329
// Load ELF executable
2430
f, err := c.fs.OpenFile(path, os.O_RDWR, 0)
@@ -106,33 +112,59 @@ func getPayloadInformation(f io.ReaderAt) (uint64, int64, int64, error) {
106112
return payloadSize, int64(payloadOffset), int64(oeInfo.Offset), nil
107113
}
108114

109-
// checkUnsupportedImports checks whether the to-be-signed or to-be-executed binary uses Go imports which are not supported.
110-
func (c *Cli) checkUnsupportedImports(path string) error {
115+
func (c *Cli) getSymbolsFromELF(path string) ([]elf.Symbol, error) {
111116
// Load ELF executable
112117
file, err := c.fs.OpenFile(path, os.O_RDONLY, 0)
113118
if err != nil {
114-
return err
119+
return nil, err
115120
}
116121

117122
elfFile, err := elf.NewFile(file)
118123
if err != nil {
119-
return err
124+
return nil, err
120125
}
121126
defer elfFile.Close()
122127

123-
// Check imports based on symbols in the ELF file
124-
symbols, err := elfFile.Symbols()
128+
return elfFile.Symbols()
129+
}
130+
131+
// checkUnsupportedImports checks whether the to-be-signed or to-be-executed binary uses Go imports which are not supported.
132+
func (c *Cli) checkUnsupportedImports(path string) error {
133+
symbols, err := c.getSymbolsFromELF(path)
125134
if err != nil {
126-
return fmt.Errorf("cannot read symbol table from given ELF binary: %w", err)
135+
return fmt.Errorf("getting symbols: %w", err)
127136
}
137+
return checkUnsupportedImports(symbols)
138+
}
128139

140+
func checkUnsupportedImports(symbols []elf.Symbol) error {
129141
// Iterate through all symbols and find whether it matches a known unsupported one
130142
for _, symbol := range symbols {
131143
if strings.Contains(symbol.Name, "github.com/edgelesssys/ego/eclient") {
132144
return ErrUnsupportedImportEClient
133145
}
134146
}
147+
return nil
148+
}
135149

150+
// checkHeapMode checks whether the heapSize is compatible with the binary.
151+
// If it is built with the ego_largeheap build tag, heapSize must be >= 512.
152+
// If it is built without this tag, heapSize must be <= 16384.
153+
// (If 512 <= heapSize <= 16384, both modes work.)
154+
func checkHeapMode(symbols []elf.Symbol, heapSize int) error {
155+
for _, symbol := range symbols {
156+
if symbol.Name == "runtime.arenaBaseOffset" {
157+
// if this symbol is found, the binary wasn't built with ego_largeheap
158+
if heapSize > 16384 {
159+
return ErrNoLargeHeapWithLargeHeapSize
160+
}
161+
return nil
162+
}
163+
}
164+
// if the symbol isn't found, the binary was built with ego_largeheap
165+
if heapSize < 512 {
166+
return ErrLargeHeapWithSmallHeapSize
167+
}
136168
return nil
137169
}
138170

ego/cli/elf_test.go

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
package cli
88

99
import (
10+
"debug/elf"
1011
"encoding/json"
1112
"io/ioutil"
1213
"os"
@@ -149,3 +150,55 @@ func TestEmbedConfigAsPayload(t *testing.T) {
149150
assert.NotEqualValues(jsonData, reconstructedJSON)
150151
assert.EqualValues(jsonNewData, reconstructedJSON)
151152
}
153+
154+
func TestCheckHeapMode(t *testing.T) {
155+
testCases := map[string]struct {
156+
symbols []elf.Symbol
157+
heapSize int
158+
want error
159+
}{
160+
"default heap, small": {
161+
symbols: []elf.Symbol{{Name: "runtime.arenaBaseOffset"}},
162+
heapSize: 511,
163+
want: nil,
164+
},
165+
"default heap, lower bound": {
166+
symbols: []elf.Symbol{{Name: "runtime.arenaBaseOffset"}},
167+
heapSize: 512,
168+
want: nil,
169+
},
170+
"default heap, upper bound": {
171+
symbols: []elf.Symbol{{Name: "runtime.arenaBaseOffset"}},
172+
heapSize: 16384,
173+
want: nil,
174+
},
175+
"default heap, large": {
176+
symbols: []elf.Symbol{{Name: "runtime.arenaBaseOffset"}},
177+
heapSize: 16385,
178+
want: ErrNoLargeHeapWithLargeHeapSize,
179+
},
180+
"large heap, small": {
181+
heapSize: 511,
182+
want: ErrLargeHeapWithSmallHeapSize,
183+
},
184+
"large heap, lower bound": {
185+
heapSize: 512,
186+
want: nil,
187+
},
188+
"large heap, upper bound": {
189+
heapSize: 16384,
190+
want: nil,
191+
},
192+
"large heap, large": {
193+
heapSize: 16385,
194+
want: nil,
195+
},
196+
}
197+
198+
for name, tc := range testCases {
199+
t.Run(name, func(t *testing.T) {
200+
assert := assert.New(t)
201+
assert.Equal(tc.want, checkHeapMode(tc.symbols, tc.heapSize))
202+
})
203+
}
204+
}

ego/cli/sign.go

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,18 @@ var ErrNoOEInfo = errors.New("could not find .oeinfo section")
3131
var errConfigDoesNotExist = errors.New("enclave config file not found")
3232

3333
func (c *Cli) signWithJSON(conf *config.Config) error {
34+
symbols, err := c.getSymbolsFromELF(conf.Exe)
35+
if err != nil {
36+
return fmt.Errorf("getting symbols: %w", err)
37+
}
38+
3439
// First, check if the executable does not contain unsupported imports / symbols.
35-
if err := c.checkUnsupportedImports(conf.Exe); err != nil {
40+
if err := checkUnsupportedImports(symbols); err != nil {
41+
return err
42+
}
43+
44+
// Check that heapSize is in the supported range of the heap mode the binary was built with.
45+
if err := checkHeapMode(symbols, conf.HeapSize); err != nil {
3646
return err
3747
}
3848

ego/ego/cmd/util.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,13 @@ func handleErr(err error) {
7777
fmt.Println("ERROR: You cannot import the github.com/edgelesssys/ego/eclient package within the EGo enclave.")
7878
fmt.Println("It is intended to be used for applications running outside the SGX enclave.")
7979
fmt.Println("You can use the github.com/edgelesssys/ego/enclave package as a replacement for usage inside the enclave.")
80+
case cli.ErrLargeHeapWithSmallHeapSize:
81+
fmt.Println("ERROR: The binary is built with build tag \"ego_largeheap\", but heapSize is set to less than 512.")
82+
fmt.Println("Either increase heapSize or rebuild without this build tag.")
83+
case cli.ErrNoLargeHeapWithLargeHeapSize:
84+
fmt.Println("ERROR: The binary is built without build tag \"ego_largeheap\", but heapSize is set to more than 16384.")
85+
fmt.Println("Either decrease heapSize or rebuild with this build tag:")
86+
fmt.Println("\tego-go build -tags ego_largeheap ...")
8087
default:
8188
fmt.Println("ERROR:", err)
8289
}

src/integration_test.sh

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,22 @@ cd /tmp/ego-integration-test
4949
run ego sign
5050
run ego run integration-test
5151

52+
# Test heap size check on sign
53+
sed -i 's/"heapSize": 16,/"heapSize": 16385,/' enclave.json
54+
run ego sign |& grep "heapSize is set to more than"
55+
56+
# Test ego_largeheap
57+
cd "$egoPath/ego/cmd/integration-test"
58+
run ego-go build -o /tmp/ego-integration-test/integration-test -tags ego_largeheap
59+
cd /tmp/ego-integration-test
60+
run ego sign # sign with 16385 heapSize should succeed now
61+
sed -i 's/"heapSize": 16385,/"heapSize": 511,/' enclave.json
62+
run ego sign |& grep "heapSize is set to less than"
63+
# Run integration test built with ego_largeheap and heapSize of 512 MB
64+
sed -i 's/"heapSize": 511,/"heapSize": 512,/' enclave.json
65+
run ego sign
66+
run ego run integration-test
67+
5268
# Test unsupported import detection on sign & run
5369
mkdir "$tPath/unsupported-import-test"
5470
cd "$egoPath/ego/cmd/unsupported-import-test"

0 commit comments

Comments
 (0)