Skip to content

[Bug]: cpuset file is read from a relative path, so cpuSetFileContent is always empty #1598

Description

@rd-stephan-roelke

Problem Description

fsmS.cpuSetFileContent builds the procfs path without a leading slash:

go-sensor/fsm.go

Lines 479 to 488 in 4a5a8af

func (r *fsmS) cpuSetFileContent(pid int) string {
path := filepath.Join("proc", strconv.Itoa(pid), "cpuset")
data, err := os.ReadFile(path)
if err != nil {
r.logger.Info("error while reading ", path, ":", err.Error())
return ""
}
return string(data)
}

func (r *fsmS) cpuSetFileContent(pid int) string {
      path := filepath.Join("proc", strconv.Itoa(pid), "cpuset")
      data, err := os.ReadFile(path)
      if err != nil {
              r.logger.Info("error while reading ", path, ":", err.Error())
              return ""
      }

      return string(data)
}

filepath.Join("proc", ...) yields a path relative to the working directory of the instrumented process, so the read only succeeds if the application happens to run with its working directory set to /. In every other case the read fails,
cpuSetFileContent returns "", and the cpuSetFileContent field of the announce payload (discoveryS in agent.go) is sent to the host agent empty.

Symptom. Applications that pass their own logger via instana.SetLogger and log at Info level see this on every announce, and again on every agent reconnect:

error while reading proc/1/cpuset:open proc/1/cpuset: no such file or directory

The number is the PID of the instrumented process — 1 for a typical containerised service. The message reads like a failure but is logged at Info, which makes it look more alarming than it is.

Expected behaviour. The cpuset file is read from /proc/<pid>/cpuset irrespective of the application's working directory, and nothing is logged when the file is readable.

Actual behaviour. The read always fails unless the working directory is /, an error is logged, and the announce payload carries an empty cpuSetFileContent.

Why this looks like a typo rather than intended behaviour. Every other procfs access in the tracer uses an absolute path:

  • fsm.go:165routeFilename := "/proc/net/route"
  • fsm.go:405os.Stat("/proc")
  • fsm.go:425fmt.Sprintf("/proc/%d/fd/%d", ...)
  • util.go:156"/proc/" + strconv.Itoa(os.Getpid()) + "/cmdline"
  • process/stats_reader_linux.go:20procPath = "/proc"

Affected versions. Reproduced on v1.74.0; the line is unchanged on main (commit 4a5a8af). It was introduced in v1.38.0 — absent in v1.37.0, present from v1.38.0 onwards (FSM refactoring, Nov 2022). Linux, both cgroup v1 and cgroup v2
(/proc/<pid>/cpuset exists in both).

Possible fix. Joining against an absolute base looks sufficient:

path := filepath.Join("/proc", strconv.Itoa(pid), "cpuset")

Instana Customer Name

No response

Minimal, Complete, Verifiable, Example

package main

import (
      "fmt"
      "net"
      "net/http"
      "os"
      "time"

      instana "github.com/instana/go-sensor"
)

func main() {
      // Minimal stand-in for a host agent: answers the discovery probe with the
      // "Instana Agent" server header and the announce request with our PID.
      // Port 0 avoids clashing with a real agent on 42699.
      ln, err := net.Listen("tcp", "127.0.0.1:0")
      if err != nil {
              panic(err)
      }

      go http.Serve(ln, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
              w.Header().Set("Server", "Instana Agent")
              fmt.Fprintf(w, `{"pid":%d}`, os.Getpid())
      }))

      addr := ln.Addr().(*net.TCPAddr)

      wd, _ := os.Getwd()
      fmt.Println("working directory:", wd)

      instana.InitCollector(&instana.Options{
              Service:   "cpuset-repro",
              LogLevel:  instana.Info,
              AgentHost: addr.IP.String(),
              AgentPort: addr.Port,
      })

      time.Sleep(5 * time.Second)
}

Run this on Linux from any directory. It logs error while reading proc/<pid>/cpuset: ... even though /proc/<pid>/cpuset exists and is readable.

Go Version

go1.27.0

go.mod

no necessary for this bug

go env

no necessary for this bug

Metadata

Metadata

Labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions