Compare commits

...
8 Commits
Author SHA1 Message Date
Arkadiy Tetelman e5815840e4 Merge pull request #15 from hugoharman/main
Fix overly strict error handling causing valid protos to be skipped
2025-10-19 14:36:42 -07:00
Arkadiy Tetelman 08f630f96e Merge branch 'main' into main 2025-10-19 14:34:36 -07:00
Arkadiy Tetelman 8b8af09dcb Merge pull request #17 from arkadiyt/atetelman--actions
Add pull_request_target
2025-10-19 14:34:25 -07:00
Arkadiy Tetelman 5930c3bfb5 Add pull_request_target 2025-10-19 14:33:40 -07:00
Arkadiy Tetelman e012331a33 Merge branch 'main' into main 2025-10-19 14:17:55 -07:00
Arkadiy Tetelman 6667d79d3b Merge pull request #16 from arkadiyt/atetelman--path
Fix file traversal
2025-10-19 14:11:34 -07:00
Arkadiy Tetelman 4d9ac25fb8 Fix file traversal 2025-10-19 14:09:57 -07:00
hugoharman dcbafdb247 Fix overly strict error handling causing valid protos to be skipped 2025-07-29 21:40:08 +07:00
3 changed files with 77 additions and 10 deletions

No files matched your search

+3 -1
View File
@@ -1,4 +1,6 @@
on: [push]
on:
- push
- pull_request_target
jobs:
build:
+54 -5
View File
@@ -6,6 +6,7 @@ import (
"log"
"os"
"path"
"path/filepath"
"strings"
"github.com/arkadiyt/protodump/pkg/protodump"
@@ -20,6 +21,47 @@ func Debug(str string, a ...any) (int, error) {
return 0, nil
}
func writeFile(outputDir string, filename string, content []byte) (string, error) {
outputDirAbs, err := filepath.Abs(outputDir)
if err != nil {
return "", fmt.Errorf("couldn't get absolute dir for %s: %v", outputDir, err)
}
fileDir, fileBase := filepath.Split(filename)
parts := strings.Split(path.Clean(fileDir), string(filepath.Separator))
var i int
for i = 0; i < len(parts); i++ {
_, err := os.Stat(filepath.Join(outputDirAbs, filepath.Join(parts[:i+1]...)))
if os.IsNotExist(err) {
break
}
}
eval := filepath.Join(outputDirAbs, filepath.Join(parts[:i]...))
base, err := filepath.EvalSymlinks(eval)
if err != nil {
return "", fmt.Errorf("failed to evalsymlinks on %s: %v", eval, err)
}
if !strings.HasPrefix(base, outputDirAbs) {
return "", fmt.Errorf("invalid filepath: %s", base)
}
rest := filepath.Join(parts[i:]...)
err = os.MkdirAll(filepath.Join(base, rest), 0700)
if err != nil {
return "", fmt.Errorf("failed to mkdirall on %s: %v", rest, err)
}
final := filepath.Join(base, rest, fileBase)
err = os.WriteFile(final, content, 0700)
if err != nil {
return "", fmt.Errorf("failed to write file %s: %v", final, err)
}
return final, nil
}
func main() {
cwd, err := os.Getwd()
if err != nil {
@@ -42,18 +84,25 @@ func main() {
log.Fatalf("Got error scanning: %v\n", err)
}
err = os.MkdirAll(*output, 0700)
if err != nil {
log.Fatalf("Failed to create output folder %s: %v\n", *output, err)
}
for _, result := range results {
definition, err := protodump.NewFromBytes(result)
if err != nil {
Debug("Got error parsing definition: %v\n", err)
} else {
filename := definition.Filename()
if strings.HasSuffix(filename, ".proto") {
dir := path.Join(*output, path.Dir(filename))
final := path.Join(dir, path.Base(filename))
os.MkdirAll(dir, 0700)
os.WriteFile(final, []byte(definition.String()), 0700)
fmt.Printf("Wrote %s\n", final)
final, err := writeFile(*output, filename, []byte(definition.String()))
if err != nil {
fmt.Printf("Failed to write %s: %v\n", final, err)
} else {
fmt.Printf("Wrote %s\n", final)
}
} else {
// Need to investigate further
}
+20 -4
View File
@@ -4,6 +4,7 @@ import (
"bytes"
"fmt"
"os"
"strings"
"google.golang.org/protobuf/encoding/protowire"
)
@@ -15,12 +16,22 @@ func consumeBytes(data []byte, position int) (int, error) {
start := position
consumedFieldOne := false
for {
number, _, len := protowire.ConsumeField(data[position:])
if len < 0 {
err := protowire.ParseError(len)
number, _, length := protowire.ConsumeField(data[position:])
if length < 0 {
err := protowire.ParseError(length)
// Treat "invalid field number" as end of data, not an error
if strings.Contains(err.Error(), "invalid field number") {
return position - start, nil
}
// Return other parse errors as actual errors
return position - start, fmt.Errorf("couldn't consume proto bytes: %w", err)
}
// Prevent infinite loop - if we can't consume any bytes, we're done
if length == 0 {
return position - start, nil
}
// Only consume Field 1 once (to handle the case where protobuf definitions are adjacent
// in program memory)
if number == 1 {
@@ -30,7 +41,12 @@ func consumeBytes(data []byte, position int) (int, error) {
consumedFieldOne = true
}
position += len
position += length
// Additional safety check - don't read beyond data bounds
if position-start >= len(data[start:]) {
return position - start, nil
}
}
}