GO1.24: New Std-Lib os.Root

Golang 1.24 introduces `os.Root`, enhancing file safety by limiting access to specified directories. This prevents directory traversal vulnerabilities. #GoLang #osRoot

 

Golang 1.24 has entered a freeze period, and many features are now available in Go 1.24 Release Notes. In the next few days, I’ll learn about the new features and changes that will be added to Golang 1.24. If you want to know about the latest developments in Go, please follow me.
In this article, we will learn about the new Standard library os.Root.

Proposal

Directory traversal vulnerabilities are a typical class of vulnerability in which an attacker tricks a program into opening a file it did not intend. These attacks often provide a relative pathname such as ../../../etc/passwd, which results in access outside an intended location. CVE-2024-3400 is a recent, real-world example of directory traversal leading to an actively exploited remote code execution vulnerability.

There are already similar implementations in other languages and operating systems, such as:

  • Python’s chroot: Limit the root directory to a specific directory through os.chroot().
  • Linux file system namespace: limit the view of the process through mount and chroot.

We can write a demo to test it.
First, construct a “confidential” file

1
echo 'password123' >> /tmp/password

Then, write a Golang function that opens a file in the current directory.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
func main() {  
    fileName := os.Args[1]  
    //readFile  
    localFilePath := "."  
    filePath := fmt.Sprintf("%s/%s", localFilePath, fileName)  
    content, err := os.ReadFile(filePath)  
    if err != nil {  
       fmt.Printf("Error reading file %s: %s\n", fileName, err)  
       return  
    }  
    fmt.Printf("File %s opened successfully. file content %s\n", fileName, content)  
}

However because of the unreliable parameters passed in, the code could access places outside the scope of the privilege.

1
2
3
4
5
6

➜  os_root git:(main)pwd
/Users/hxzhouh/workspace/github/me/blog-example/go/go1.24/os_root
➜  os_root git:(main) ✗ ./main ../../../../../../../../../tmp/password
./../../../../../../../../../tmp/password
File ../../../../../../../../../tmp/password opened successfully. file content password123

In Go 1.24, a new type of OS.Root was added, allowing file system operations in a specific directory. The entire system is centered around this new type. The corresponding core function is OS.OpenRoot, which opens a directory and returns an OS.Root. Methods on os.Root` are only allowed to operate within a directory and are not allowed to point to paths to locations outside the directory**, including paths that follow symbolic links outside the directory. (Defends against the scope of the attack mentioned in the background of the previous proposal)
Let’s modify the code in the same way that Go1.24 did

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
func main() {  
    fileName := os.Args[1]  
    root, err := os.OpenRoot(".")  
    if err != nil {  
       panic(err)  
    }  
    file, err := root.Open(fileName)  
    if err != nil {  
       fmt.Println(fmt.Sprintf("Error opening file %s: %s\n", fileName, err.Error()))  
       return  
    }  
    content := make([]byte, 1024)  
    c, err := file.Read(content)  
    if err != nil {  
       panic(err)  
    }  
    content = content[:c]  
    fmt.Printf("File %s opened successfully. file content %s\n", fileName, content)  
}

Running again

1
2
3
4
5
➜  os_root git:(main) ✗ gotip version 
go version devel go1.24-fafd447 Wed Dec 11 15:57:34 2024 -0800 darwin/arm64
➜  os_root git:(main) ✗ gotip build -o go1.24  main.go                      
➜  os_root git:(main) ✗ ./go1.24 ../../../../../../../../../tmp/password 
Error opening file ../../../../../../../../../tmp/password: openat ../../../../../../../../../tmp/password: path escapes from parent

An error will be reported if the folder is out of the parent hierarchy.

Please refer to the official documentation for more APi interfaces. After 1.24 is officially released, I guess many third-party libraries will be adapted as soon as possible; basically, all the other languages have this function.

Licensed under CC BY-NC-SA 4.0
Last updated on Dec 10, 2024 20:32 CST
Built with Hugo
Theme Stack designed by Jimmy