Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
96 changes: 96 additions & 0 deletions cmd/docker-entrypoint/main.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
//go:build linux

package main

import (
"fmt"
"os"
"os/exec"
"os/user"
"strconv"
"syscall"
)

var dockerEnvVarDefaults = map[string]string{
Expand All @@ -24,21 +29,112 @@
os.Stderr.WriteString(" - " + key + "\n")
}
}

// Setup user and group
uid, gid, err := setupUserAndGroup()
if err != nil {
os.Stderr.WriteString(fmt.Sprintf("Failed to setup user/group: %v\n", err))
os.Exit(1)
}

if len(os.Args) < 2 {
os.Stderr.WriteString("No command provided to run.\n")
os.Exit(1)
}

if uid != 0 {
os.Stderr.WriteString(fmt.Sprintf("Switching to user with UID=%d, GID=%d\n", uid, gid))
}
os.Stderr.WriteString("Running command: " + os.Args[1] + " " + fmt.Sprint(os.Args[2:]) + "\n")

cmd := exec.Command(os.Args[1], os.Args[2:]...)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
cmd.Stdin = os.Stdin

// Set the user and group for the command if not root
if uid != 0 {
cmd.SysProcAttr = &syscall.SysProcAttr{
Credential: &syscall.Credential{
Uid: uint32(uid),
Gid: uint32(gid),
},
}
}

if err := cmd.Run(); err != nil {
if exitError, ok := err.(*exec.ExitError); ok {
os.Exit(exitError.ExitCode())
}
panic(err)
}
}

// setupUserAndGroup handles PUID/PGID setup
func setupUserAndGroup() (int, int, error) {
puidStr := os.Getenv("PUID")
pgidStr := os.Getenv("PGID")

// Default to running as root if PUID is empty or 0
if puidStr == "" || puidStr == "0" {
return 0, 0, nil
}

puid, err := strconv.ParseUint(puidStr, 10, 32)
if err != nil {
return 0, 0, fmt.Errorf("invalid PUID: %v", err)
}

pgid, err := strconv.ParseUint(pgidStr, 10, 32)
if err != nil {
return 0, 0, fmt.Errorf("invalid PGID: %v", err)
}

username := "abc"
groupname := "abc"

// Check if user already exists
if !userExists(username) {
// Create group if it doesn't exist
if !groupExists(groupname) {
if err := createGroup(groupname, int(pgid)); err != nil {

Check failure

Code scanning / CodeQL

Incorrect conversion between integer types High

Incorrect conversion of an unsigned 32-bit integer from
strconv.ParseUint
to a lower bit size type int without an upper bound check.

Copilot Autofix

AI 6 months ago

To fix the problem, we should add explicit bounds checking after parsing the PGID value to ensure it fits within the valid range for a GID and for the int type. The typical valid range for a GID is 0 to math.MaxInt32 (2,147,483,647), since negative GIDs are not valid and the int type may be 32 bits on some systems. We should check that the parsed value is greater than 0 (or at least non-negative, depending on requirements) and less than or equal to math.MaxInt32. If the value is out of bounds, we should return an error. The same check should be applied to PUID for consistency and safety. This change should be made in the setupUserAndGroup function, after parsing puid and pgid but before converting them to int and passing them to createGroup and createUser. We will need to import the math package if it is not already imported.


Suggested changeset 1
cmd/docker-entrypoint/main.go

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/cmd/docker-entrypoint/main.go b/cmd/docker-entrypoint/main.go
--- a/cmd/docker-entrypoint/main.go
+++ b/cmd/docker-entrypoint/main.go
@@ -11,2 +11,3 @@
 	"syscall"
+	"math"
 )
@@ -86,2 +87,5 @@
 	}
+	if puid == 0 || puid > uint64(math.MaxInt32) {
+		return 0, 0, fmt.Errorf("PUID must be between 1 and %d", math.MaxInt32)
+	}
 
@@ -91,2 +95,5 @@
 	}
+	if pgid == 0 || pgid > uint64(math.MaxInt32) {
+		return 0, 0, fmt.Errorf("PGID must be between 1 and %d", math.MaxInt32)
+	}
 
EOF
@@ -11,2 +11,3 @@
"syscall"
"math"
)
@@ -86,2 +87,5 @@
}
if puid == 0 || puid > uint64(math.MaxInt32) {
return 0, 0, fmt.Errorf("PUID must be between 1 and %d", math.MaxInt32)
}

@@ -91,2 +95,5 @@
}
if pgid == 0 || pgid > uint64(math.MaxInt32) {
return 0, 0, fmt.Errorf("PGID must be between 1 and %d", math.MaxInt32)
}

Copilot is powered by AI and may make mistakes. Always verify output.
return 0, 0, fmt.Errorf("failed to create group %s: %v", groupname, err)
}
os.Stderr.WriteString(fmt.Sprintf("Created group %s with GID %d\n", groupname, pgid))
}

// Create user
if err := createUser(username, groupname, int(puid)); err != nil {

Check failure

Code scanning / CodeQL

Incorrect conversion between integer types High

Incorrect conversion of an unsigned 32-bit integer from
strconv.ParseUint
to a lower bit size type int without an upper bound check.

Copilot Autofix

AI 6 months ago

To fix this issue, we must ensure that the value parsed from the environment variable fits within the range of a signed int before converting it. The best way is to check that the parsed value is less than or equal to math.MaxInt32 (and greater than zero, if negative values are not allowed), and only then perform the conversion. If the value is out of bounds, we should return an error or use a safe default. This check should be added before any conversion of puid or pgid to int in the setupUserAndGroup function. We also need to import the math package to access math.MaxInt32.


Suggested changeset 1
cmd/docker-entrypoint/main.go

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/cmd/docker-entrypoint/main.go b/cmd/docker-entrypoint/main.go
--- a/cmd/docker-entrypoint/main.go
+++ b/cmd/docker-entrypoint/main.go
@@ -11,2 +11,3 @@
 	"syscall"
+	"math"
 )
@@ -86,2 +87,5 @@
 	}
+	if puid > uint64(math.MaxInt32) {
+		return 0, 0, fmt.Errorf("PUID %d is out of range (must be <= %d)", puid, math.MaxInt32)
+	}
 
@@ -91,2 +95,5 @@
 	}
+	if pgid > uint64(math.MaxInt32) {
+		return 0, 0, fmt.Errorf("PGID %d is out of range (must be <= %d)", pgid, math.MaxInt32)
+	}
 
@@ -112,3 +119,3 @@
 
-	return puid, pgid, nil
+	return int(puid), int(pgid), nil
 }
EOF
@@ -11,2 +11,3 @@
"syscall"
"math"
)
@@ -86,2 +87,5 @@
}
if puid > uint64(math.MaxInt32) {
return 0, 0, fmt.Errorf("PUID %d is out of range (must be <= %d)", puid, math.MaxInt32)
}

@@ -91,2 +95,5 @@
}
if pgid > uint64(math.MaxInt32) {
return 0, 0, fmt.Errorf("PGID %d is out of range (must be <= %d)", pgid, math.MaxInt32)
}

@@ -112,3 +119,3 @@

return puid, pgid, nil
return int(puid), int(pgid), nil
}
Copilot is powered by AI and may make mistakes. Always verify output.
return 0, 0, fmt.Errorf("failed to create user %s: %v", username, err)
}
os.Stderr.WriteString(fmt.Sprintf("Created user %s with UID %d\n", username, puid))
}

return puid, pgid, nil
}

// userExists checks if a user exists by name
func userExists(username string) bool {
_, err := user.Lookup(username)
return err == nil
}

// groupExists checks if a group exists by running getent group
func groupExists(groupname string) bool {
cmd := exec.Command("getent", "group", groupname)
return cmd.Run() == nil
}

// createGroup creates a group with the specified GID
func createGroup(groupname string, gid int) error {
cmd := exec.Command("groupadd", "-g", strconv.Itoa(gid), groupname)
cmd.Stderr = os.Stderr
return cmd.Run()
}

// createUser creates a user with the specified UID and group
func createUser(username, groupname string, uid int) error {
cmd := exec.Command("useradd", "-m", "-u", strconv.Itoa(uid), "-g", groupname, username)
cmd.Stderr = os.Stderr
return cmd.Run()
}