VYPR
Moderate severityNVD Advisory· Published Oct 2, 2024· Updated Oct 2, 2024

CVE-2024-8038

CVE-2024-8038

Description

Vulnerable juju introspection abstract UNIX domain socket. An abstract UNIX domain socket responsible for introspection is available without authentication locally to network namespace users. This enables denial of service attacks.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
github.com/juju/jujuGo
< 0.0.0-20240829052008-43f0fc59790d0.0.0-20240829052008-43f0fc59790d

Affected products

1

Patches

1
43f0fc59790d

fix: use unix domain socket file for introspection socket

https://github.com/juju/jujuHarry PidcockAug 28, 2024via ghsa
17 files changed · +124 111
  • agent/addons/addons.go+7 11 modified
    @@ -4,12 +4,12 @@
     package addons
     
     import (
    +	"path"
     	"runtime"
     
     	"github.com/juju/clock"
     	"github.com/juju/errors"
     	"github.com/juju/loggo"
    -	"github.com/juju/names/v4"
     	"github.com/juju/worker/v3"
     	"github.com/juju/worker/v3/dependency"
     	"github.com/prometheus/client_golang/prometheus"
    @@ -22,17 +22,14 @@ import (
     
     var logger = loggo.GetLogger("juju.cmd.jujud.agent.addons")
     
    -// DefaultIntrospectionSocketName returns the socket name to use for the
    -// abstract domain socket that the introspection worker serves requests
    -// over.
    -func DefaultIntrospectionSocketName(entityTag names.Tag) string {
    -	return "jujud-" + entityTag.String()
    -}
    +// IntrospectionSocketName is the name of the socket file inside
    +// the agent's directory used for introspection calls.
    +const IntrospectionSocketName = "introspection.socket"
     
     // IntrospectionConfig defines the various components that the introspection
     // worker reports on or needs to start up.
     type IntrospectionConfig struct {
    -	AgentTag           names.Tag
    +	AgentDir           string
     	Engine             *dependency.Engine
     	StatePoolReporter  introspection.Reporter
     	PubSubReporter     introspection.Reporter
    @@ -44,8 +41,7 @@ type IntrospectionConfig struct {
     	CentralHub         introspection.StructuredHub
     	LeaseFSM           introspection.Leases
     
    -	NewSocketName func(names.Tag) string
    -	WorkerFunc    func(config introspection.Config) (worker.Worker, error)
    +	WorkerFunc func(config introspection.Config) (worker.Worker, error)
     }
     
     // StartIntrospection creates the introspection worker. It cannot and should
    @@ -60,7 +56,7 @@ func StartIntrospection(cfg IntrospectionConfig) error {
     		return nil
     	}
     
    -	socketName := cfg.NewSocketName(cfg.AgentTag)
    +	socketName := path.Join(cfg.AgentDir, IntrospectionSocketName)
     	w, err := cfg.WorkerFunc(introspection.Config{
     		SocketName:         socketName,
     		DepEngine:          cfg.Engine,
    
  • agent/addons/addons_test.go+4 12 modified
    @@ -10,7 +10,6 @@ import (
     	"github.com/juju/clock"
     	"github.com/juju/errors"
     	"github.com/juju/loggo"
    -	"github.com/juju/names/v4"
     	"github.com/juju/testing"
     	jc "github.com/juju/testing/checkers"
     	"github.com/juju/worker/v3"
    @@ -55,8 +54,7 @@ func (s *introspectionSuite) TestStartError(c *gc.C) {
     	}
     
     	cfg := addons.IntrospectionConfig{
    -		AgentTag:      names.NewMachineTag("42"),
    -		NewSocketName: addons.DefaultIntrospectionSocketName,
    +		AgentDir: c.MkDir(),
     		WorkerFunc: func(_ introspection.Config) (worker.Worker, error) {
     			return nil, errors.New("boom")
     		},
    @@ -85,9 +83,8 @@ func (s *introspectionSuite) TestStartSuccess(c *gc.C) {
     	c.Assert(err, jc.ErrorIsNil)
     
     	cfg := addons.IntrospectionConfig{
    -		AgentTag:      names.NewMachineTag("42"),
    -		Engine:        engine,
    -		NewSocketName: func(tag names.Tag) string { return "bananas" },
    +		AgentDir: c.MkDir(),
    +		Engine:   engine,
     		WorkerFunc: func(cfg introspection.Config) (worker.Worker, error) {
     			fake.config = cfg
     			return fake, nil
    @@ -98,7 +95,7 @@ func (s *introspectionSuite) TestStartSuccess(c *gc.C) {
     	c.Assert(err, jc.ErrorIsNil)
     
     	c.Check(fake.config.DepEngine, gc.Equals, engine)
    -	c.Check(fake.config.SocketName, gc.Equals, "bananas")
    +	c.Check(fake.config.SocketName, jc.HasSuffix, "introspection.socket")
     
     	// Stopping the engine causes the introspection worker to stop.
     	engine.Kill()
    @@ -110,11 +107,6 @@ func (s *introspectionSuite) TestStartSuccess(c *gc.C) {
     	}
     }
     
    -func (s *introspectionSuite) TestDefaultIntrospectionSocketName(c *gc.C) {
    -	name := addons.DefaultIntrospectionSocketName(names.NewMachineTag("42"))
    -	c.Assert(name, gc.Equals, "jujud-machine-42")
    -}
    -
     type dummyWorker struct {
     	config introspection.Config
     	done   chan struct{}
    
  • cmd/containeragent/main_nix.go+1 1 modified
    @@ -177,7 +177,7 @@ func main() {
     			return cmd.Main(&run.RunCommand{MachineLock: lock}, ctx, args[1:])
     		},
     		jujuIntrospect: func(ctx *cmd.Context, args []string) int {
    -			return cmd.Main(introspect.New(nil), ctx, args[1:])
    +			return cmd.Main(introspect.New(), ctx, args[1:])
     		},
     	}
     	os.Exit(mainWrapper(f, os.Args))
    
  • cmd/containeragent/unit/agent.go+1 2 modified
    @@ -291,10 +291,9 @@ func (c *containerUnitAgent) workers(sigTermCh chan os.Signal) (worker.Worker, e
     		return nil, err
     	}
     	if err := addons.StartIntrospection(addons.IntrospectionConfig{
    -		AgentTag:           c.CurrentConfig().Tag(),
    +		AgentDir:           agentConfig.Dir(),
     		Engine:             eng,
     		MachineLock:        c.machineLock,
    -		NewSocketName:      addons.DefaultIntrospectionSocketName,
     		PrometheusGatherer: c.prometheusRegistry,
     		WorkerFunc:         introspection.NewWorker,
     		Clock:              c.clk,
    
  • cmd/jujud/agent/caasoperator.go+1 2 modified
    @@ -258,10 +258,9 @@ func (op *CaasOperatorAgent) Workers() (worker.Worker, error) {
     		return nil, err
     	}
     	if err := addons.StartIntrospection(addons.IntrospectionConfig{
    -		AgentTag:           op.CurrentConfig().Tag(),
    +		AgentDir:           agentConfig.Dir(),
     		Engine:             engine,
     		MachineLock:        op.machineLock,
    -		NewSocketName:      addons.DefaultIntrospectionSocketName,
     		PrometheusGatherer: op.prometheusRegistry,
     		WorkerFunc:         introspection.NewWorker,
     		Clock:              clock.WallClock,
    
  • cmd/jujud/agent/machine.go+3 7 modified
    @@ -270,7 +270,6 @@ func (a *machineAgentCmd) Info() *cmd.Info {
     func MachineAgentFactoryFn(
     	agentConfWriter agentconf.AgentConfigWriter,
     	bufferedLogger *logsender.BufferedLogWriter,
    -	newIntrospectionSocketName func(names.Tag) string,
     	preUpgradeSteps upgrades.PreUpgradeStepsFunc,
     	rootDir string,
     ) machineAgentFactoryFnType {
    @@ -286,7 +285,6 @@ func MachineAgentFactoryFn(
     				Logger:        logger,
     			}),
     			looputil.NewLoopDeviceManager(),
    -			newIntrospectionSocketName,
     			preUpgradeSteps,
     			rootDir,
     			isCaasAgent,
    @@ -301,7 +299,6 @@ func NewMachineAgent(
     	bufferedLogger *logsender.BufferedLogWriter,
     	runner *worker.Runner,
     	loopDeviceManager looputil.LoopDeviceManager,
    -	newIntrospectionSocketName func(names.Tag) string,
     	preUpgradeSteps upgrades.PreUpgradeStepsFunc,
     	rootDir string,
     	isCaasAgent bool,
    @@ -321,7 +318,6 @@ func NewMachineAgent(
     		rootDir:                     rootDir,
     		initialUpgradeCheckComplete: gate.NewLock(),
     		loopDeviceManager:           loopDeviceManager,
    -		newIntrospectionSocketName:  newIntrospectionSocketName,
     		prometheusRegistry:          prometheusRegistry,
     		mongoTxnCollector:           mongometrics.NewTxnCollector(),
     		mongoDialCollector:          mongometrics.NewDialCollector(),
    @@ -558,9 +554,10 @@ func (a *MachineAgent) makeEngineCreator(
     	agentName string, previousAgentVersion version.Number,
     ) func() (worker.Worker, error) {
     	return func() (worker.Worker, error) {
    +		agentConfig := a.CurrentConfig()
     		engineConfigFunc := engine.DependencyEngineConfig
     		metrics := engine.NewMetrics()
    -		controllerMetricsSink := metrics.ForModel(a.CurrentConfig().Model())
    +		controllerMetricsSink := metrics.ForModel(agentConfig.Model())
     		engine, err := dependency.NewEngine(engineConfigFunc(controllerMetricsSink))
     		if err != nil {
     			return nil, err
    @@ -648,12 +645,11 @@ func (a *MachineAgent) makeEngineCreator(
     			return nil, err
     		}
     		if err := addons.StartIntrospection(addons.IntrospectionConfig{
    -			AgentTag:           a.CurrentConfig().Tag(),
    +			AgentDir:           agentConfig.Dir(),
     			Engine:             engine,
     			StatePoolReporter:  &statePoolReporter,
     			PubSubReporter:     pubsubReporter,
     			MachineLock:        a.machineLock,
    -			NewSocketName:      a.newIntrospectionSocketName,
     			PrometheusGatherer: a.prometheusRegistry,
     			PresenceRecorder:   presenceRecorder,
     			WorkerFunc:         introspection.NewWorker,
    
  • cmd/jujud/agent/util_test.go+0 1 modified
    @@ -192,7 +192,6 @@ func NewTestMachineAgentFactory(
     			rootDir:                     rootDir,
     			initialUpgradeCheckComplete: gate.NewLock(),
     			loopDeviceManager:           &mockLoopDeviceManager{},
    -			newIntrospectionSocketName:  addons.DefaultIntrospectionSocketName,
     			prometheusRegistry:          prometheusRegistry,
     			mongoTxnCollector:           mongometrics.NewTxnCollector(),
     			mongoDialCollector:          mongometrics.NewDialCollector(),
    
  • cmd/jujud/introspect/introspect.go+5 12 modified
    @@ -10,6 +10,7 @@ import (
     	"net/http/httputil"
     	"net/url"
     	"os"
    +	"path"
     	"path/filepath"
     	"strings"
     
    @@ -19,6 +20,7 @@ import (
     	"github.com/juju/names/v4"
     	"github.com/kr/pretty"
     
    +	"github.com/juju/juju/agent"
     	"github.com/juju/juju/agent/addons"
     	apiagent "github.com/juju/juju/api/agent/agent"
     	jujucmd "github.com/juju/juju/cmd"
    @@ -35,16 +37,11 @@ type IntrospectCommand struct {
     	verbose bool
     	post    bool
     	form    url.Values
    -
    -	// IntrospectionSocketName returns the socket name
    -	// for a given tag. If IntrospectionSocketName is nil,
    -	// agent.DefaultIntrospectionSocketName is used.
    -	IntrospectionSocketName func(names.Tag) string
     }
     
     // New initializes IntrospectCommand.
    -func New(sockNameGetter func(names.Tag) string) cmd.Command {
    -	return &IntrospectCommand{IntrospectionSocketName: sockNameGetter}
    +func New() cmd.Command {
    +	return &IntrospectCommand{}
     }
     
     const introspectCommandDoc = `
    @@ -127,11 +124,7 @@ func (c *IntrospectCommand) Run(ctx *cmd.Context) error {
     		return err
     	}
     
    -	getSocketName := c.IntrospectionSocketName
    -	if getSocketName == nil {
    -		getSocketName = addons.DefaultIntrospectionSocketName
    -	}
    -	socketName := "@" + getSocketName(tag)
    +	socketName := path.Join(agent.Dir(c.dataDir, tag), addons.IntrospectionSocketName)
     	if c.listen != "" {
     		listener, err := net.Listen("tcp", c.listen)
     		if err != nil {
    
  • cmd/jujud/introspect/introspect_test.go+29 23 modified
    @@ -21,7 +21,6 @@ import (
     
     	"github.com/juju/cmd/v3"
     	"github.com/juju/cmd/v3/cmdtesting"
    -	"github.com/juju/names/v4"
     	jc "github.com/juju/testing/checkers"
     	gc "gopkg.in/check.v1"
     
    @@ -57,11 +56,7 @@ func (*IntrospectCommandSuite) assertInitError(c *gc.C, expect string, args ...s
     }
     
     func (*IntrospectCommandSuite) run(c *gc.C, args ...string) (*cmd.Context, error) {
    -	return cmdtesting.RunCommand(c, &introspect.IntrospectCommand{
    -		IntrospectionSocketName: func(tag names.Tag) string {
    -			return filepath.Join(config.DataDir, "jujud-"+tag.String())
    -		},
    -	}, args...)
    +	return cmdtesting.RunCommand(c, &introspect.IntrospectCommand{}, args...)
     }
     
     func (s *IntrospectCommandSuite) TestAutoDetectMachineAgent(c *gc.C) {
    @@ -70,7 +65,7 @@ func (s *IntrospectCommandSuite) TestAutoDetectMachineAgent(c *gc.C) {
     	c.Assert(err, jc.ErrorIsNil)
     
     	_, err = s.run(c, "query")
    -	c.Assert(err, gc.ErrorMatches, ".*jujud-machine-1024.*")
    +	c.Assert(err, gc.ErrorMatches, ".*machine-1024.*")
     }
     
     func (s *IntrospectCommandSuite) TestAutoDetectMachineAgentFails(c *gc.C) {
    @@ -84,11 +79,14 @@ func (s *IntrospectCommandSuite) TestAutoDetectMachineAgentFails(c *gc.C) {
     
     func (s *IntrospectCommandSuite) TestAgentSpecified(c *gc.C) {
     	_, err := s.run(c, "query", "--agent=unit-foo-0")
    -	c.Assert(err, gc.ErrorMatches, ".*jujud-unit-foo-0.*")
    +	c.Assert(err, gc.ErrorMatches, ".*unit-foo-0.*")
     }
     
     func (s *IntrospectCommandSuite) TestQuery(c *gc.C) {
    -	listener, err := net.Listen("unix", "@"+filepath.Join(config.DataDir, "jujud-machine-0"))
    +	agentDir := filepath.Join(config.DataDir, "agents", "machine-0")
    +	err := os.MkdirAll(agentDir, 0755)
    +	c.Assert(err, jc.ErrorIsNil)
    +	listener, err := net.Listen("unix", filepath.Join(agentDir, "introspection.socket"))
     	c.Assert(err, jc.ErrorIsNil)
     	defer listener.Close()
     
    @@ -102,7 +100,10 @@ func (s *IntrospectCommandSuite) TestQuery(c *gc.C) {
     }
     
     func (s *IntrospectCommandSuite) TestQueryFails(c *gc.C) {
    -	listener, err := net.Listen("unix", "@"+filepath.Join(config.DataDir, "jujud-machine-0"))
    +	agentDir := filepath.Join(config.DataDir, "agents", "machine-0")
    +	err := os.MkdirAll(agentDir, 0755)
    +	c.Assert(err, jc.ErrorIsNil)
    +	listener, err := net.Listen("unix", filepath.Join(agentDir, "introspection.socket"))
     	c.Assert(err, jc.ErrorIsNil)
     	defer listener.Close()
     
    @@ -122,7 +123,10 @@ func (s *IntrospectCommandSuite) TestQueryFails(c *gc.C) {
     }
     
     func (s *IntrospectCommandSuite) TestGetToPostEndpoint(c *gc.C) {
    -	listener, err := net.Listen("unix", "@"+filepath.Join(config.DataDir, "jujud-machine-0"))
    +	agentDir := filepath.Join(config.DataDir, "agents", "machine-0")
    +	err := os.MkdirAll(agentDir, 0755)
    +	c.Assert(err, jc.ErrorIsNil)
    +	listener, err := net.Listen("unix", filepath.Join(agentDir, "introspection.socket"))
     	c.Assert(err, jc.ErrorIsNil)
     	defer listener.Close()
     
    @@ -137,7 +141,10 @@ func (s *IntrospectCommandSuite) TestGetToPostEndpoint(c *gc.C) {
     }
     
     func (s *IntrospectCommandSuite) TestPost(c *gc.C) {
    -	listener, err := net.Listen("unix", "@"+filepath.Join(config.DataDir, "jujud-machine-0"))
    +	agentDir := filepath.Join(config.DataDir, "agents", "machine-0")
    +	err := os.MkdirAll(agentDir, 0755)
    +	c.Assert(err, jc.ErrorIsNil)
    +	listener, err := net.Listen("unix", filepath.Join(agentDir, "introspection.socket"))
     	c.Assert(err, jc.ErrorIsNil)
     	defer listener.Close()
     
    @@ -155,8 +162,11 @@ single="value"
     }
     
     func (s *IntrospectCommandSuite) TestListen(c *gc.C) {
    -	socketName := filepath.Join(config.DataDir, "jujud-machine-0")
    -	listener, err := net.Listen("unix", "@"+socketName)
    +	agentDir := filepath.Join(config.DataDir, "agents", "machine-0")
    +	err := os.MkdirAll(agentDir, 0755)
    +	c.Assert(err, jc.ErrorIsNil)
    +	socketName := filepath.Join(agentDir, "introspection.socket")
    +	listener, err := net.Listen("unix", socketName)
     	c.Assert(err, jc.ErrorIsNil)
     	defer listener.Close()
     
    @@ -166,7 +176,7 @@ func (s *IntrospectCommandSuite) TestListen(c *gc.C) {
     
     	ctx, cancel := context.WithCancel(context.Background())
     	defer cancel()
    -	cmd := exec.CommandContext(ctx, os.Args[0], "-run-listen="+socketName)
    +	cmd := exec.CommandContext(ctx, os.Args[0], "-run-listen="+config.DataDir)
     	stderr, err := cmd.StderrPipe()
     	c.Assert(err, jc.ErrorIsNil)
     	defer stderr.Close()
    @@ -176,7 +186,7 @@ func (s *IntrospectCommandSuite) TestListen(c *gc.C) {
     	scanner := bufio.NewScanner(stderr)
     	c.Assert(scanner.Scan(), jc.IsTrue)
     	line := scanner.Text()
    -	c.Assert(line, gc.Matches, "Exposing @.* introspection socket on 127.0.0.1:.*")
    +	c.Assert(line, gc.Matches, "Exposing .* introspection socket on 127.0.0.1:.*")
     
     	fields := strings.Fields(line)
     	addr := fields[len(fields)-1]
    @@ -221,16 +231,12 @@ func newServer(l net.Listener) *http.Server {
     	return srv
     }
     
    -var flagListen = flag.String("run-listen", "", "Name of the Unix socket to connect the introspect command to using --listen=:0")
    +var flagListen = flag.String("run-listen", "", "DataDir of the Unix socket to connect the introspect command to using --listen=:0")
     
     func TestRunListen(t *stdtesting.T) {
     	if *flagListen != "" {
    -		introspectCommand := &introspect.IntrospectCommand{
    -			IntrospectionSocketName: func(names.Tag) string {
    -				return *flagListen
    -			},
    -		}
    -		args := append(flag.Args(), "--listen=127.0.0.1:0", "--agent=machine-0")
    +		introspectCommand := &introspect.IntrospectCommand{}
    +		args := append(flag.Args(), "--data-dir="+*flagListen, "--listen=127.0.0.1:0", "--agent=machine-0")
     		if err := cmdtesting.InitCommand(introspectCommand, args); err != nil {
     			t.Fatal(err)
     		}
    
  • cmd/jujud/main.go+1 2 modified
    @@ -26,7 +26,6 @@ import (
     	"github.com/juju/utils/v3/exec"
     	"github.com/juju/version/v2"
     
    -	"github.com/juju/juju/agent/addons"
     	k8sexec "github.com/juju/juju/caas/kubernetes/provider/exec"
     	jujucmd "github.com/juju/juju/cmd"
     	agentcmd "github.com/juju/juju/cmd/jujud/agent"
    @@ -40,6 +39,7 @@ import (
     	coreos "github.com/juju/juju/core/os"
     	jujunames "github.com/juju/juju/juju/names"
     	"github.com/juju/juju/juju/sockets"
    +
     	// Import the providers.
     	_ "github.com/juju/juju/provider/all"
     	"github.com/juju/juju/upgrades"
    @@ -261,7 +261,6 @@ func jujuDMain(args []string, ctx *cmd.Context) (code int, err error) {
     	machineAgentFactory := agentcmd.MachineAgentFactoryFn(
     		agentConf,
     		bufferedLogger,
    -		addons.DefaultIntrospectionSocketName,
     		upgrades.PreUpgradeSteps,
     		"",
     	)
    
  • featuretests/dblog_test.go+0 2 modified
    @@ -18,7 +18,6 @@ import (
     	gc "gopkg.in/check.v1"
     
     	"github.com/juju/juju/agent"
    -	"github.com/juju/juju/agent/addons"
     	apiclient "github.com/juju/juju/api/client/client"
     	"github.com/juju/juju/api/common"
     	"github.com/juju/juju/caas/kubernetes/provider"
    @@ -106,7 +105,6 @@ func (s *dblogSuite) assertAgentLogsGoToDB(c *gc.C, tag names.Tag, isCaas bool)
     	machineAgentFactory := agentcmd.MachineAgentFactoryFn(
     		aCfg,
     		logger,
    -		addons.DefaultIntrospectionSocketName,
     		noPreUpgradeSteps,
     		c.MkDir(),
     	)
    
  • state/backups/files.go+25 5 modified
    @@ -4,6 +4,8 @@
     package backups
     
     import (
    +	"fmt"
    +	"io/fs"
     	"os"
     	"path/filepath"
     	"sort"
    @@ -107,17 +109,35 @@ func GetFilesToBackUp(rootDir string, paths *Paths) ([]string, error) {
     	}
     
     	// Handle user SSH files (might not exist).
    -	SSHDir := filepath.Join(rootDir, sshDir)
    -	if _, err := os.Stat(SSHDir); err != nil {
    +	authorizedKeysFile := filepath.Join(rootDir, sshDir, authKeysFile)
    +	if _, err := os.Stat(authorizedKeysFile); err != nil {
     		if !os.IsNotExist(err) {
     			return nil, errors.Trace(err)
     		}
    -		logger.Errorf("skipping missing dir %q", SSHDir)
    +		logger.Errorf("skipping missing file %q", authorizedKeysFile)
     	} else {
    -		backupFiles = append(backupFiles, filepath.Join(SSHDir, authKeysFile))
    +		backupFiles = append(backupFiles, authorizedKeysFile)
     	}
     
    -	return backupFiles, nil
    +	var finalBackupFiles []string
    +	for _, file := range backupFiles {
    +		err := filepath.Walk(file, func(path string, info fs.FileInfo, err error) error {
    +			if err != nil {
    +				return err
    +			}
    +			if info.IsDir() {
    +				return nil
    +			}
    +			if info.Mode().IsRegular() || info.Mode()&os.ModeSymlink != 0 {
    +				finalBackupFiles = append(finalBackupFiles, path)
    +			}
    +			return nil
    +		})
    +		if err != nil {
    +			return nil, fmt.Errorf("cannot walk %q: %w", file, err)
    +		}
    +	}
    +	return finalBackupFiles, nil
     }
     
     // replaceableFolders for testing purposes.
    
  • state/backups/files_test.go+28 15 modified
    @@ -17,6 +17,7 @@ import (
     	jc "github.com/juju/testing/checkers"
     	gc "gopkg.in/check.v1"
     
    +	"github.com/juju/juju/juju/sockets"
     	"github.com/juju/juju/mongo"
     	"github.com/juju/juju/state/backups"
     	"github.com/juju/juju/testing"
    @@ -60,6 +61,12 @@ func (s *filesSuite) createFiles(c *gc.C, paths backups.Paths, root, machineID s
     		c.Assert(err, jc.ErrorIsNil)
     		file.Close()
     	}
    +	socket := func(dirname, name string) {
    +		path := filepath.Join(dirname, name)
    +		l, err := sockets.Listen(sockets.Socket{Network: "unix", Address: path})
    +		c.Assert(err, jc.ErrorIsNil)
    +		l.Close()
    +	}
     
     	dirname := mkdir(paths.DataDir)
     	touch(dirname, "system-identity")
    @@ -71,10 +78,12 @@ func (s *filesSuite) createFiles(c *gc.C, paths backups.Paths, root, machineID s
     	} else {
     		touch(dirname, "shared-secret")
     	}
    -	mkdir(filepath.Join(paths.DataDir, "tools"))
    +	dirname = mkdir(filepath.Join(paths.DataDir, "tools"))
    +	touch(dirname, "a-tool")
     
    -	dirname = mkdir(filepath.Join(paths.DataDir, "agents"))
    -	touch(dirname, "machine-"+machineID+".conf")
    +	dirname = mkdir(filepath.Join(paths.DataDir, "agents", "machine-"+machineID))
    +	touch(dirname, "agent.conf")
    +	socket(dirname, "introspection.socket")
     
     	dirname = mkdir("/home/ubuntu/.ssh")
     	touch(dirname, "authorized_keys")
    @@ -125,17 +134,23 @@ func (s *filesSuite) TestGetFilesToBackUp(c *gc.C) {
     
     	expected := []string{
     		filepath.Join(s.root, "/home/ubuntu/.ssh/authorized_keys"),
    -		filepath.Join(s.root, "/var/lib/juju/agents/machine-0.conf"),
    -		filepath.Join(s.root, "/var/lib/juju/agents/machine-1.conf"),
    +		filepath.Join(s.root, "/var/lib/juju/agents/machine-0/agent.conf"),
    +		filepath.Join(s.root, "/var/lib/juju/agents/machine-1/agent.conf"),
     		filepath.Join(s.root, "/var/lib/juju/nonce.txt"),
     		filepath.Join(s.root, "/var/lib/juju/server.pem"),
     		filepath.Join(s.root, "/var/lib/juju/shared-secret"),
     		filepath.Join(s.root, "/var/lib/juju/system-identity"),
    -		filepath.Join(s.root, "/var/lib/juju/tools"),
    -		filepath.Join(s.root, "/var/lib/juju/init/juju-db"),
    +		filepath.Join(s.root, "/var/lib/juju/tools/a-tool"),
    +		filepath.Join(s.root, "/var/lib/juju/init/juju-db/juju-db.service"),
     	}
     	c.Check(files, jc.SameContents, expected)
     	s.checkSameStrings(c, files, expected)
    +
    +	// Check the introspection sockets are not Tar'd up.
    +	_, err = os.Stat(filepath.Join(s.root, "/var/lib/juju/agents/machine-0/introspection.socket"))
    +	c.Assert(err, jc.ErrorIsNil)
    +	_, err = os.Stat(filepath.Join(s.root, "/var/lib/juju/agents/machine-1/introspection.socket"))
    +	c.Assert(err, jc.ErrorIsNil)
     }
     
     func (s *filesSuite) TestDirectoriesCleaned(c *gc.C) {
    @@ -249,15 +264,13 @@ func (s *filesSuite) TestGetFilesToBackUpMissing(c *gc.C) {
     	c.Assert(err, jc.ErrorIsNil)
     
     	expected := []string{
    -		filepath.Join(s.root, "/var/lib/juju/agents/machine-0.conf"),
    +		filepath.Join(s.root, "/var/lib/juju/agents/machine-0/agent.conf"),
     		filepath.Join(s.root, "/var/lib/juju/server.pem"),
     		filepath.Join(s.root, "/var/lib/juju/shared-secret"),
     		filepath.Join(s.root, "/var/lib/juju/system-identity"),
    -		filepath.Join(s.root, "/var/lib/juju/tools"),
    -		filepath.Join(s.root, "/var/lib/juju/init/juju-db"),
    +		filepath.Join(s.root, "/var/lib/juju/tools/a-tool"),
    +		filepath.Join(s.root, "/var/lib/juju/init/juju-db/juju-db.service"),
     	}
    -	// This got re-created.
    -	expected = append(expected, filepath.Join(s.root, "/home/ubuntu/.ssh/authorized_keys"))
     	c.Check(files, jc.SameContents, expected)
     	s.checkSameStrings(c, files, expected)
     }
    @@ -274,13 +287,13 @@ func (s *filesSuite) TestGetFilesToBackUpSnap(c *gc.C) {
     
     	expected := []string{
     		filepath.Join(s.root, "/home/ubuntu/.ssh/authorized_keys"),
    -		filepath.Join(s.root, "/var/lib/juju/agents/machine-0.conf"),
    +		filepath.Join(s.root, "/var/lib/juju/agents/machine-0/agent.conf"),
     		filepath.Join(s.root, "/var/lib/juju/nonce.txt"),
     		filepath.Join(s.root, "/var/lib/juju/server.pem"),
     		filepath.Join(s.root, "/var/snap/juju-db/common/shared-secret"),
     		filepath.Join(s.root, "/var/lib/juju/system-identity"),
    -		filepath.Join(s.root, "/var/lib/juju/tools"),
    -		filepath.Join(s.root, "/var/lib/juju/init/juju-db"),
    +		filepath.Join(s.root, "/var/lib/juju/tools/a-tool"),
    +		filepath.Join(s.root, "/var/lib/juju/init/juju-db/juju-db.service"),
     	}
     	c.Check(files, jc.SameContents, expected)
     	s.checkSameStrings(c, files, expected)
    
  • worker/deployer/unit_agent.go+1 2 modified
    @@ -225,9 +225,8 @@ func (a *UnitAgent) start() (worker.Worker, error) {
     		a.mu.Unlock()
     	}()
     	if err := addons.StartIntrospection(addons.IntrospectionConfig{
    -		AgentTag:           a.CurrentConfig().Tag(),
    +		AgentDir:           a.CurrentConfig().Dir(),
     		Engine:             engine,
    -		NewSocketName:      addons.DefaultIntrospectionSocketName,
     		PrometheusGatherer: a.prometheusRegistry,
     		MachineLock:        machineLock,
     		WorkerFunc:         introspection.NewWorker,
    
  • worker/introspection/script.go+5 1 modified
    @@ -42,7 +42,11 @@ const shellFuncs = `
     juju_agent_call () {
       local agent=$1
       shift
    -  juju-introspect --agent=$agent $@
    +  if [ -x "$(which sudo)" ]; then
    +    sudo juju-introspect --agent=$agent $@
    +  else
    +    juju-introspect --agent=$agent $@
    +  fi
     }
     
     juju_machine_agent_name () {
    
  • worker/introspection/worker.go+7 9 modified
    @@ -23,6 +23,7 @@ import (
     	"github.com/juju/juju/cmd/output"
     	"github.com/juju/juju/core/machinelock"
     	"github.com/juju/juju/core/presence"
    +	"github.com/juju/juju/juju/sockets"
     	"github.com/juju/juju/pubsub/agent"
     	"github.com/juju/juju/worker/introspection/pprof"
     )
    @@ -98,7 +99,7 @@ func (c *Config) Validate() error {
     // socketListener is a worker and constructed with NewWorker.
     type socketListener struct {
     	tomb               tomb.Tomb
    -	listener           *net.UnixListener
    +	listener           net.Listener
     	depEngine          DepEngineReporter
     	statePool          Reporter
     	pubsub             Reporter
    @@ -122,17 +123,14 @@ func NewWorker(config Config) (worker.Worker, error) {
     		return nil, errors.NotSupportedf("os %q", runtime.GOOS)
     	}
     
    -	path := "@" + config.SocketName
    -	addr, err := net.ResolveUnixAddr("unix", path)
    -	if err != nil {
    -		return nil, errors.Annotate(err, "unable to resolve unix socket")
    -	}
    -
    -	l, err := net.ListenUnix("unix", addr)
    +	l, err := sockets.Listen(sockets.Socket{
    +		Network: "unix",
    +		Address: config.SocketName,
    +	})
     	if err != nil {
     		return nil, errors.Annotate(err, "unable to listen on unix socket")
     	}
    -	logger.Debugf("introspection worker listening on %q", path)
    +	logger.Debugf("introspection worker listening on %q", config.SocketName)
     
     	w := &socketListener{
     		listener:           l,
    
  • worker/introspection/worker_test.go+6 4 modified
    @@ -11,6 +11,7 @@ import (
     	"net/http"
     	"net/url"
     	"os"
    +	"path"
     	"runtime"
     	"strings"
     	"time"
    @@ -64,8 +65,9 @@ func (s *suite) TestStartStop(c *gc.C) {
     		c.Skip("introspection worker not supported on non-linux")
     	}
     
    +	socketName := path.Join(c.MkDir(), "introspection-test")
     	w, err := introspection.NewWorker(introspection.Config{
    -		SocketName:         "introspection-test",
    +		SocketName:         socketName,
     		PrometheusGatherer: prometheus.NewRegistry(),
     	})
     	c.Assert(err, jc.ErrorIsNil)
    @@ -105,7 +107,7 @@ func (s *introspectionSuite) SetUpTest(c *gc.C) {
     }
     
     func (s *introspectionSuite) startWorker(c *gc.C) {
    -	s.name = fmt.Sprintf("introspection-test-%d", os.Getpid())
    +	s.name = path.Join(c.MkDir(), fmt.Sprintf("introspection-test-%d", os.Getpid()))
     	w, err := introspection.NewWorker(introspection.Config{
     		SocketName:         s.name,
     		DepEngine:          s.reporter,
    @@ -124,7 +126,7 @@ func (s *introspectionSuite) startWorker(c *gc.C) {
     }
     
     func (s *introspectionSuite) call(c *gc.C, path string) *http.Response {
    -	client := unixSocketHTTPClient("@" + s.name)
    +	client := unixSocketHTTPClient(s.name)
     	c.Assert(strings.HasPrefix(path, "/"), jc.IsTrue)
     	targetURL, err := url.Parse("http://unix.socket" + path)
     	c.Assert(err, jc.ErrorIsNil)
    @@ -135,7 +137,7 @@ func (s *introspectionSuite) call(c *gc.C, path string) *http.Response {
     }
     
     func (s *introspectionSuite) post(c *gc.C, path string, values url.Values) *http.Response {
    -	client := unixSocketHTTPClient("@" + s.name)
    +	client := unixSocketHTTPClient(s.name)
     	c.Assert(strings.HasPrefix(path, "/"), jc.IsTrue)
     	targetURL, err := url.Parse("http://unix.socket" + path)
     	c.Assert(err, jc.ErrorIsNil)
    

Vulnerability mechanics

Synthesis attempt was rejected by the grounding validator. Re-run pending.

References

7

News mentions

0

No linked articles in our index yet.