Out-of-bounds read - Go

Out-of-bounds read - Go

Need

Prevention of out-of-bounds read vulnerabilities

Context

  • Usage of Go 1.16 for developing high-performance and scalable applications
  • Usage of Gin framework for building web applications in Go

Description

Non compliant code

        package main

import (
	"fmt"
	"github.com/gin-gonic/gin"
)

func main() {
	r := gin.Default()
	r.GET("/read", func(c *gin.Context) {
		data := []int{1, 2, 3, 4, 5}
		index := c.Query("index")
		indexVal, _ := strconv.Atoi(index)
		fmt.Println(data[indexVal])
	})
	r.Run() // run on 0.0.0.0:8080
}
        
        

In the above code, we have a simple Gin based HTTP server that has a single GET endpoint "/read". This endpoint reads an index from the query parameters and uses it to access an element in the data array.

The vulnerability lies in the fact that there is no boundary checking for the index value. This means, if a user provides an index that is outside the bounds of the data array, the application will attempt to read memory that it shouldn't, leading to an out-of-bounds read vulnerability.

For instance, if a user sends a GET request to "/read?index=10", the application will attempt to access data[10], which is outside the bounds of the data array (which only has indices 0-4). This will result in an out-of-bounds read, which can lead to undefined behavior and potential security risks.

Steps

  • Validate the input to ensure it is within the bounds of the data array.
  • Check if the index value is a valid integer.
  • Handle any potential errors when converting the index value to an integer.
  • Implement proper error handling to handle out-of-bounds read scenarios.
  • Return an appropriate response to the client if the index is out of bounds.

Compliant code

        package main

import (
	"fmt"
	"github.com/gin-gonic/gin"
	"net/http"
	"strconv"
)

func main() {
	r := gin.Default()
	r.GET("/read", func(c *gin.Context) {
		data := []int{1, 2, 3, 4, 5}
		index := c.Query("index")
		indexVal, err := strconv.Atoi(index)
		if err != nil {
			c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid index value"})
			return
		}
		if indexVal < 0 || indexVal >= len(data) {
			c.JSON(http.StatusBadRequest, gin.H{"error": "Index out of bounds"})
			return
		}
		fmt.Println(data[indexVal])
	})
	r.Run() // run on 0.0.0.0:8080
}
        
        

The updated code includes several checks to prevent out-of-bounds read vulnerabilities.

1. Input Validation: The code checks if the index value provided in the request is a valid integer. If the strconv.Atoi function returns an error, it means that the index value is not a valid integer. In this case, the code returns a 400 Bad Request response with an error message "Invalid index value".

2. Bounds Checking: The code checks if the index value is within the bounds of the data array. If the index value is less than 0 or greater than or equal to the length of the data array, it means that the index is out of bounds. In this case, the code returns a 400 Bad Request response with an error message "Index out of bounds".

These checks ensure that the system only reads data within the intended buffer, preventing out-of-bounds read vulnerabilities.

References