Skip to content

Instantly share code, notes, and snippets.

@cyphar
Created February 7, 2020 03:47
Show Gist options
  • Save cyphar/47cbc8fc4209af7f598605a61a0ecad7 to your computer and use it in GitHub Desktop.
Save cyphar/47cbc8fc4209af7f598605a61a0ecad7 to your computer and use it in GitHub Desktop.
// libpathrs: safe path resolution on Linux
// Copyright (C) 2019, 2020 Aleksa Sarai <cyphar@cyphar.com>
// Copyright (C) 2020 Maxim Zhiburt <zhiburt@gmail.com>
// Copyright (C) 2019, 2020 SUSE LLC
//
// This program is free software: you can redistribute it and/or modify it under
// the terms of the GNU Lesser General Public License as published by the Free
// Software Foundation, either version 3 of the License, or (at your option) any
// later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
// PARTICULAR PURPOSE. See the GNU General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License along
// with this program. If not, see <https://www.gnu.org/licenses/>.
// Package main implements a program which print file content to stdout
// safely resolving paths with libpathrs.
package main
import (
"fmt"
"io"
"os"
"sync"
"github.com/openSUSE/libpathrs/contrib/bindings/go/pathrs"
)
func unwrap(err error) error {
type unwrappable interface {
Unwrap() error
}
if wrappedErr, ok := err.(unwrappable); ok {
return wrappedErr.Unwrap()
} else {
return nil
}
}
func usage() {
fmt.Println("usage: cat <root> <unsafe-path>")
os.Exit(1)
}
func main() {
if len(os.Args) < 3 {
usage()
}
rootPath := os.Args[1]
path := os.Args[2]
root, err := pathrs.Open(rootPath)
if err != nil {
printPathError(err)
return
}
defer root.Close()
/*
roots := []*pathrs.Root{}
for i := 0; i < 512; i++ {
newRoot, err := root.Clone()
if err != nil {
printPathError(err)
return
}
roots = append(roots, newRoot)
}
*/
startChan := make(chan struct{})
var startThreadWg sync.WaitGroup
var endThreadWg sync.WaitGroup
for i := 0; i < 512; i++ {
startThreadWg.Add(1)
endThreadWg.Add(1)
go func() {
startThreadWg.Done()
<-startChan
/*
for _, root := range roots {
root.Close()
}
*/
root, err := root.Clone()
if err != nil {
printPathError(err)
return
}
rawRoot, err := root.IntoRaw()
if err != nil {
printPathError(err)
return
}
defer rawRoot.Close()
root, err = pathrs.RootFromRaw(rawRoot)
if err != nil {
printPathError(err)
return
}
defer root.Close()
handle, err := root.Resolve(path)
if err != nil {
printPathError(err)
return
}
defer handle.Close()
rawHandle, err := handle.IntoRaw()
if err != nil {
printPathError(err)
return
}
defer rawHandle.Close()
handle, err = pathrs.HandleFromRaw(rawHandle)
if err != nil {
printPathError(err)
return
}
file, err := handle.Open()
if err != nil {
printPathError(err)
return
}
defer file.Close()
_, err = io.Copy(os.Stdout, file)
if err != nil {
fmt.Printf("Cannot write content of file to stdout, %v\n", err)
return
}
endThreadWg.Done()
}()
}
startThreadWg.Wait()
close(startChan)
endThreadWg.Wait()
}
func printPathError(err error) {
fmt.Println("Error", err)
fmt.Println("Unwrapped error", unwrap(err))
fmt.Println("Backtrace:")
if pathrsErr, ok := err.(*pathrs.Error); ok {
fmt.Println(pathrsErr.Backtrace())
}
//os.Exit(1)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment