Guard against symbolic links escaping the document base.
This commit is contained in:
parent
bb0a04d2c7
commit
06c6d190a6
1 changed files with 39 additions and 2 deletions
41
handler.go
41
handler.go
|
@ -19,6 +19,22 @@ import (
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Utility function below borrowed from
|
||||||
|
// https://stackoverflow.com/questions/28024731/check-if-given-path-is-a-subdirectory-of-another-in-golang
|
||||||
|
func isSubdir(subdir, superdir string) (bool, error) {
|
||||||
|
up := ".." + string(os.PathSeparator)
|
||||||
|
|
||||||
|
// path-comparisons using filepath.Abs don't work reliably according to docs (no unique representation).
|
||||||
|
rel, err := filepath.Rel(superdir, subdir)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
if !strings.HasPrefix(rel, up) && rel != ".." {
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
|
||||||
func handleGeminiRequest(conn net.Conn, config Config, accessLogEntries chan LogEntry, errorLog *log.Logger, wg *sync.WaitGroup) {
|
func handleGeminiRequest(conn net.Conn, config Config, accessLogEntries chan LogEntry, errorLog *log.Logger, wg *sync.WaitGroup) {
|
||||||
defer conn.Close()
|
defer conn.Close()
|
||||||
defer wg.Done()
|
defer wg.Done()
|
||||||
|
@ -69,8 +85,29 @@ func handleGeminiRequest(conn net.Conn, config Config, accessLogEntries chan Log
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Resolve URI path to actual filesystem path
|
// Resolve URI path to actual filesystem path, including following symlinks
|
||||||
path := resolvePath(URL.Path, config)
|
raw_path := resolvePath(URL.Path, config)
|
||||||
|
path, err := filepath.EvalSymlinks(raw_path)
|
||||||
|
if err!= nil {
|
||||||
|
errorLog.Println("Error evaluating path " + raw_path + " for symlinks: " + err.Error())
|
||||||
|
conn.Write([]byte("51 Not found!\r\n"))
|
||||||
|
log.Status = 51
|
||||||
|
}
|
||||||
|
|
||||||
|
// If symbolic links have been used to escape the intended document directory,
|
||||||
|
// deny all knowledge
|
||||||
|
isSub, err := isSubdir(path, config.DocBase)
|
||||||
|
if err != nil {
|
||||||
|
errorLog.Println("Error testing whether path " + path + " is below DocBase: " + err.Error())
|
||||||
|
}
|
||||||
|
if !isSub {
|
||||||
|
errorLog.Println("Refusing to follow simlink from " + raw_path + " outside of DocBase!")
|
||||||
|
}
|
||||||
|
if err != nil || !isSub {
|
||||||
|
conn.Write([]byte("51 Not found!\r\n"))
|
||||||
|
log.Status = 51
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// Paranoid security measures:
|
// Paranoid security measures:
|
||||||
// Fail ASAP if the URL has mapped to a sensitive file
|
// Fail ASAP if the URL has mapped to a sensitive file
|
||||||
|
|
Loading…
Reference in a new issue