Repository: opencontainers/runc
Pull request #3204 (2021-09-09 04:49:49)

Add support for seccomp actions ActKillThread and ActKillProcess
Carry of #2564.

Two new seccomp actions have been added to the libseccomp-golang
dependency, which can be now supported by runc, too.

ActKillThread kills the thread that violated the rule. It is the same as
ActKill. All other threads from the same thread group will continue to
execute.

ActKillProcess kills the process that violated the rule. All threads in
the thread group are also terminated. This action is only usable when
libseccomp API level 3 or higher is supported.

Signed-off-by: Sascha Grunert <sgrunert@redhat.com>
Signed-off-by: Aleksa Sarai <cyphar@cyphar.com>


Patch:
diff --git a/go.mod b/go.mod
index 9dc4e367..64d19452 100644
--- a/go.mod
+++ b/go.mod
@@ -10,7 +10,7 @@ require (
 	github.com/coreos/go-systemd/v22 v22.3.2
 	github.com/cyphar/filepath-securejoin v0.2.3
 	github.com/docker/go-units v0.4.0
-	github.com/godbus/dbus/v5 v5.0.5
+	github.com/godbus/dbus/v5 v5.0.4
 	github.com/moby/sys/mountinfo v0.4.1
 	github.com/mrunalp/fileutils v0.5.0
 	github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417
diff --git a/go.sum b/go.sum
index 7b387677..186bf535 100644
--- a/go.sum
+++ b/go.sum
@@ -19,9 +19,8 @@ github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw
 github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
 github.com/frankban/quicktest v1.11.3 h1:8sXhOn0uLys67V8EsXLc6eszDs8VXWxL3iRvebPhedY=
 github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k=
+github.com/godbus/dbus/v5 v5.0.4 h1:9349emZab16e7zQvpmsbtjc18ykshndd8y2PG3sgJbA=
 github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
-github.com/godbus/dbus/v5 v5.0.5 h1:9Eg0XUhQxtkV8ykTMKtMMYY72g4NgxtRq4jgh4Ih5YM=
-github.com/godbus/dbus/v5 v5.0.5/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
 github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
 github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
 github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
diff --git a/init.go b/init.go
index 61026e22..d3949295 100644
--- a/init.go
+++ b/init.go
@@ -1,11 +1,13 @@
 package main
 
 import (
+	"fmt"
 	"os"
 	"runtime"
 	"strconv"
 
 	"github.com/opencontainers/runc/libcontainer"
+	"github.com/opencontainers/runc/libcontainer/logs"
 	_ "github.com/opencontainers/runc/libcontainer/nsenter"
 	"github.com/sirupsen/logrus"
 )
@@ -17,19 +19,25 @@ func init() {
 		runtime.GOMAXPROCS(1)
 		runtime.LockOSThread()
 
-		logLevel, err := logrus.ParseLevel(os.Getenv("_LIBCONTAINER_LOGLEVEL"))
+		level := os.Getenv("_LIBCONTAINER_LOGLEVEL")
+		logLevel, err := logrus.ParseLevel(level)
 		if err != nil {
-			panic(err)
+			panic(fmt.Sprintf("libcontainer: failed to parse log level: %q: %v", level, err))
 		}
 
-		logPipeFd, err := strconv.Atoi(os.Getenv("_LIBCONTAINER_LOGPIPE"))
+		logPipeFdStr := os.Getenv("_LIBCONTAINER_LOGPIPE")
+		logPipeFd, err := strconv.Atoi(logPipeFdStr)
 		if err != nil {
-			panic(err)
+			panic(fmt.Sprintf("libcontainer: failed to convert environment variable _LIBCONTAINER_LOGPIPE=%s to int: %s", logPipeFdStr, err))
+		}
+		err = logs.ConfigureLogging(logs.Config{
+			LogPipeFd: logPipeFd,
+			LogFormat: "json",
+			LogLevel:  logLevel,
+		})
+		if err != nil {
+			panic(fmt.Sprintf("libcontainer: failed to configure logging: %v", err))
 		}
-
-		logrus.SetLevel(logLevel)
-		logrus.SetOutput(os.NewFile(uintptr(logPipeFd), "logpipe"))
-		logrus.SetFormatter(new(logrus.JSONFormatter))
 		logrus.Debug("child process in init()")
 
 		factory, _ := libcontainer.New("")
diff --git a/libcontainer/cgroups/systemd/dbus.go b/libcontainer/cgroups/systemd/dbus.go
index 3e547e28..e69469b7 100644
--- a/libcontainer/cgroups/systemd/dbus.go
+++ b/libcontainer/cgroups/systemd/dbus.go
@@ -2,7 +2,6 @@ package systemd
 
 import (
 	"context"
-	"fmt"
 	"sync"
 
 	systemdDbus "github.com/coreos/go-systemd/v22/dbus"
@@ -53,10 +52,7 @@ func (d *dbusConnManager) getConnection() (*systemdDbus.Conn, error) {
 
 	conn, err := d.newConnection()
 	if err != nil {
-		// When dbus-user-session is not installed, we can't detect whether we should try to connect to user dbus or system dbus, so d.dbusRootless is set to false.
-		// This may fail with a cryptic error "read unix @->/run/systemd/private: read: connection reset by peer: unknown."
-		// https://github.com/moby/moby/issues/42793
-		return nil, fmt.Errorf("failed to connect to dbus (hint: for rootless containers, maybe you need to install dbus-user-session package, see https://github.com/opencontainers/runc/blob/master/docs/cgroup-v2.md): %w", err)
+		return nil, err
 	}
 	dbusC = conn
 	return conn, nil
diff --git a/libcontainer/configs/config.go b/libcontainer/configs/config.go
index e0db8e01..329f05cc 100644
--- a/libcontainer/configs/config.go
+++ b/libcontainer/configs/config.go
@@ -50,6 +50,8 @@ const (
 	Trace
 	Log
 	Notify
+	KillThread
+	KillProcess
 )
 
 // Operator is a comparison operator to be used when matching syscall arguments in Seccomp
diff --git a/libcontainer/logs/logs.go b/libcontainer/logs/logs.go
index 95deb0d6..07592176 100644
--- a/libcontainer/logs/logs.go
+++ b/libcontainer/logs/logs.go
@@ -3,28 +3,37 @@ package logs
 import (
 	"bufio"
 	"encoding/json"
+	"errors"
+	"fmt"
 	"io"
+	"os"
+	"sync"
 
 	"github.com/sirupsen/logrus"
 )
 
+var (
+	configureMutex sync.Mutex
+	// loggingConfigured will be set once logging has been configured via invoking `ConfigureLogging`.
+	// Subsequent invocations of `ConfigureLogging` would be no-op
+	loggingConfigured = false
+)
+
+type Config struct {
+	LogLevel    logrus.Level
+	LogFormat   string
+	LogFilePath string
+	LogPipeFd   int
+	LogCaller   bool
+}
+
 func ForwardLogs(logPipe io.ReadCloser) chan error {
 	done := make(chan error, 1)
 	s := bufio.NewScanner(logPipe)
 
-	logger := logrus.StandardLogger()
-	if logger.ReportCaller {
-		// Need a copy of the standard logger, but with ReportCaller
-		// turned off, as the logs are merely forwarded and their
-		// true source is not this file/line/function.
-		logNoCaller := *logrus.StandardLogger()
-		logNoCaller.ReportCaller = false
-		logger = &logNoCaller
-	}
-
 	go func() {
 		for s.Scan() {
-			processEntry(s.Bytes(), logger)
+			processEntry(s.Bytes())
 		}
 		if err := logPipe.Close(); err != nil {
 			logrus.Errorf("error closing log source: %v", err)
@@ -38,19 +47,60 @@ func ForwardLogs(logPipe io.ReadCloser) chan error {
 	return done
 }
 
-func processEntry(text []byte, logger *logrus.Logger) {
+func processEntry(text []byte) {
 	if len(text) == 0 {
 		return
 	}
 
 	var jl struct {
-		Level logrus.Level `json:"level"`
-		Msg   string       `json:"msg"`
+		Level string `json:"level"`
+		Msg   string `json:"msg"`
 	}
 	if err := json.Unmarshal(text, &jl); err != nil {
 		logrus.Errorf("failed to decode %q to json: %v", text, err)
 		return
 	}
 
-	logger.Log(jl.Level, jl.Msg)
+	lvl, err := logrus.ParseLevel(jl.Level)
+	if err != nil {
+		logrus.Errorf("failed to parse log level %q: %v", jl.Level, err)
+		return
+	}
+	logrus.StandardLogger().Logf(lvl, jl.Msg)
+}
+
+func ConfigureLogging(config Config) error {
+	configureMutex.Lock()
+	defer configureMutex.Unlock()
+
+	if loggingConfigured {
+		return errors.New("logging has already been configured")
+	}
+
+	logrus.SetLevel(config.LogLevel)
+	logrus.SetReportCaller(config.LogCaller)
+
+	// XXX: while 0 is a valid fd (usually stdin), here we assume
+	// that we never deliberately set LogPipeFd to 0.
+	if config.LogPipeFd > 0 {
+		logrus.SetOutput(os.NewFile(uintptr(config.LogPipeFd), "logpipe"))
+	} else if config.LogFilePath != "" {
+		f, err := os.OpenFile(config.LogFilePath, os.O_CREATE|os.O_WRONLY|os.O_APPEND|os.O_SYNC, 0o644)
+		if err != nil {
+			return err
+		}
+		logrus.SetOutput(f)
+	}
+
+	switch config.LogFormat {
+	case "text":
+		// retain logrus's default.
+	case "json":
+		logrus.SetFormatter(new(logrus.JSONFormatter))
+	default:
+		return fmt.Errorf("unknown log-format %q", config.LogFormat)
+	}
+
+	loggingConfigured = true
+	return nil
 }
diff --git a/libcontainer/seccomp/seccomp_linux.go b/libcontainer/seccomp/seccomp_linux.go
index ad599e99..f552aba4 100644
--- a/libcontainer/seccomp/seccomp_linux.go
+++ b/libcontainer/seccomp/seccomp_linux.go
@@ -16,13 +16,8 @@ import (
 )
 
 var (
-	actAllow  = libseccomp.ActAllow
-	actTrap   = libseccomp.ActTrap
-	actKill   = libseccomp.ActKill
-	actTrace  = libseccomp.ActTrace.SetReturnCode(int16(unix.EPERM))
-	actLog    = libseccomp.ActLog
-	actErrno  = libseccomp.ActErrno.SetReturnCode(int16(unix.EPERM))
-	actNotify = libseccomp.ActNotify
+	actTrace = libseccomp.ActTrace.SetReturnCode(int16(unix.EPERM))
+	actErrno = libseccomp.ActErrno.SetReturnCode(int16(unix.EPERM))
 )
 
 const (
@@ -71,7 +66,7 @@ func InitSeccomp(config *configs.Seccomp) (int, error) {
 	}
 
 	// See comment on why write is not allowed. The same reason applies, as this can mean handling write too.
-	if defaultAction == actNotify {
+	if defaultAction == libseccomp.ActNotify {
 		return -1, errors.New("SCMP_ACT_NOTIFY cannot be used as default action")
 	}
 
@@ -119,25 +114,29 @@ func InitSeccomp(config *configs.Seccomp) (int, error) {
 func getAction(act configs.Action, errnoRet *uint) (libseccomp.ScmpAction, error) {
 	switch act {
 	case configs.Kill:
-		return actKill, nil
+		return libseccomp.ActKill, nil
 	case configs.Errno:
 		if errnoRet != nil {
 			return libseccomp.ActErrno.SetReturnCode(int16(*errnoRet)), nil
 		}
 		return actErrno, nil
 	case configs.Trap:
-		return actTrap, nil
+		return libseccomp.ActTrap, nil
 	case configs.Allow:
-		return actAllow, nil
+		return libseccomp.ActAllow, nil
 	case configs.Trace:
 		if errnoRet != nil {
 			return libseccomp.ActTrace.SetReturnCode(int16(*errnoRet)), nil
 		}
 		return actTrace, nil
 	case configs.Log:
-		return actLog, nil
+		return libseccomp.ActLog, nil
 	case configs.Notify:
-		return actNotify, nil
+		return libseccomp.ActNotify, nil
+	case configs.KillThread:
+		return libseccomp.ActKillThread, nil
+	case configs.KillProcess:
+		return libseccomp.ActKillProcess, nil
 	default:
 		return libseccomp.ActInvalid, errors.New("invalid action, cannot use in rule")
 	}
diff --git a/main.go b/main.go
index bb69672f..f141e79b 100644
--- a/main.go
+++ b/main.go
@@ -1,15 +1,13 @@
 package main
 
 import (
-	"errors"
 	"fmt"
 	"io"
 	"os"
-	"path/filepath"
 	"runtime"
-	"strconv"
 	"strings"
 
+	"github.com/opencontainers/runc/libcontainer/logs"
 	"github.com/opencontainers/runc/libcontainer/seccomp"
 	"github.com/opencontainers/runtime-spec/specs-go"
 
@@ -151,7 +149,7 @@ func main() {
 			return err
 		}
 
-		return configLogrus(context)
+		return logs.ConfigureLogging(createLogConfig(context))
 	}
 
 	// If the command returns an error, cli takes upon itself to print
@@ -175,42 +173,22 @@ func (f *FatalWriter) Write(p []byte) (n int, err error) {
 	return len(p), nil
 }
 
-func configLogrus(context *cli.Context) error {
-	if context.GlobalBool("debug") {
-		logrus.SetLevel(logrus.DebugLevel)
-		logrus.SetReportCaller(true)
-		// Shorten function and file names reported by the logger, by
-		// trimming common "github.com/opencontainers/runc" prefix.
-		// This is only done for text formatter.
-		_, file, _, _ := runtime.Caller(0)
-		prefix := filepath.Dir(file) + "/"
-		logrus.SetFormatter(&logrus.TextFormatter{
-			CallerPrettyfier: func(f *runtime.Frame) (string, string) {
-				function := strings.TrimPrefix(f.Function, prefix) + "()"
-				fileLine := strings.TrimPrefix(f.File, prefix) + ":" + strconv.Itoa(f.Line)
-				return function, fileLine
-			},
-		})
+func createLogConfig(context *cli.Context) logs.Config {
+	logFilePath := context.GlobalString("log")
+	logPipeFd := 0
+	if logFilePath == "" {
+		logPipeFd = 2
 	}
-
-	switch f := context.GlobalString("log-format"); f {
-	case "":
-		// do nothing
-	case "text":
-		// do nothing
-	case "json":
-		logrus.SetFormatter(new(logrus.JSONFormatter))
-	default:
-		return errors.New("invalid log-format: " + f)
+	config := logs.Config{
+		LogPipeFd:   logPipeFd,
+		LogLevel:    logrus.InfoLevel,
+		LogFilePath: logFilePath,
+		LogFormat:   context.GlobalString("log-format"),
+		LogCaller:   context.GlobalBool("debug"),
 	}
-
-	if file := context.GlobalString("log"); file != "" {
-		f, err := os.OpenFile(file, os.O_CREATE|os.O_WRONLY|os.O_APPEND|os.O_SYNC, 0o644)
-		if err != nil {
-			return err
-		}
-		logrus.SetOutput(f)
+	if context.GlobalBool("debug") {
+		config.LogLevel = logrus.DebugLevel
 	}
 
-	return nil
+	return config
 }
diff --git a/vendor/github.com/godbus/dbus/v5/README.md b/vendor/github.com/godbus/dbus/v5/README.markdown
similarity index 81%
rename from vendor/github.com/godbus/dbus/v5/README.md
rename to vendor/github.com/godbus/dbus/v5/README.markdown
index 5c241258..1fb2eaca 100644
--- a/vendor/github.com/godbus/dbus/v5/README.md
+++ b/vendor/github.com/godbus/dbus/v5/README.markdown
@@ -14,12 +14,14 @@ D-Bus message bus system.
 
 ### Installation
 
-This packages requires Go 1.12 or later. It can be installed by running the command below:
+This packages requires Go 1.7. If you installed it and set up your GOPATH, just run:
 
 ```
-go get github.com/godbus/dbus/v5
+go get github.com/godbus/dbus
 ```
 
+If you want to use the subpackages, you can install them the same way.
+
 ### Usage
 
 The complete package documentation and some simple examples are available at
@@ -28,12 +30,10 @@ The complete package documentation and some simple examples are available at
 gives a short overview over the basic usage. 
 
 #### Projects using godbus
-- [fyne](https://github.com/fyne-io/fyne) a cross platform GUI in Go inspired by Material Design.
-- [fynedesk](https://github.com/fyne-io/fynedesk) a full desktop environment for Linux/Unix using Fyne.
-- [go-bluetooth](https://github.com/muka/go-bluetooth) provides a bluetooth client over bluez dbus API.
-- [iwd](https://github.com/shibumi/iwd) go bindings for the internet wireless daemon "iwd".
 - [notify](https://github.com/esiqveland/notify) provides desktop notifications over dbus into a library.
+- [go-bluetooth](https://github.com/muka/go-bluetooth) provides a bluetooth client over bluez dbus API.
 - [playerbm](https://github.com/altdesktop/playerbm) a bookmark utility for media players.
+- [iwd](https://github.com/shibumi/iwd) go bindings for the internet wireless daemon "iwd".
 
 Please note that the API is considered unstable for now and may change without
 further notice.
diff --git a/vendor/github.com/godbus/dbus/v5/auth.go b/vendor/github.com/godbus/dbus/v5/auth.go
index eb0b2f43..283487a0 100644
--- a/vendor/github.com/godbus/dbus/v5/auth.go
+++ b/vendor/github.com/godbus/dbus/v5/auth.go
@@ -75,9 +75,9 @@ func (conn *Conn) Auth(methods []Auth) error {
 	s = s[1:]
 	for _, v := range s {
 		for _, m := range methods {
-			if name, _, status := m.FirstData(); bytes.Equal(v, name) {
+			if name, data, status := m.FirstData(); bytes.Equal(v, name) {
 				var ok bool
-				err = authWriteLine(conn.transport, []byte("AUTH"), v)
+				err = authWriteLine(conn.transport, []byte("AUTH"), v, data)
 				if err != nil {
 					return err
 				}
@@ -194,14 +194,11 @@ func (conn *Conn) tryAuth(m Auth, state authState, in *bufio.Reader) (error, boo
 			}
 			conn.uuid = string(s[1])
 			return nil, true
-		case state == waitingForOk && string(s[0]) == "DATA":
-			err = authWriteLine(conn.transport, []byte("DATA"))
-			if err != nil {
-				return err, false
-			}
 		case state == waitingForOk && string(s[0]) == "REJECTED":
 			return nil, false
-		case state == waitingForOk && string(s[0]) == "ERROR":
+		case state == waitingForOk && (string(s[0]) == "DATA" ||
+			string(s[0]) == "ERROR"):
+
 			err = authWriteLine(conn.transport, []byte("CANCEL"))
 			if err != nil {
 				return err, false
diff --git a/vendor/github.com/godbus/dbus/v5/conn.go b/vendor/github.com/godbus/dbus/v5/conn.go
index cb8966a7..29fe018a 100644
--- a/vendor/github.com/godbus/dbus/v5/conn.go
+++ b/vendor/github.com/godbus/dbus/v5/conn.go
@@ -478,24 +478,14 @@ func (conn *Conn) sendMessageAndIfClosed(msg *Message, ifClosed func()) {
 		conn.outInt(msg)
 	}
 	err := conn.outHandler.sendAndIfClosed(msg, ifClosed)
+	conn.calls.handleSendError(msg, err)
 	if err != nil {
-		conn.handleSendError(msg, err)
+		conn.serialGen.RetireSerial(msg.serial)
 	} else if msg.Type != TypeMethodCall {
 		conn.serialGen.RetireSerial(msg.serial)
 	}
 }
 
-func (conn *Conn) handleSendError(msg *Message, err error) {
-	if msg.Type == TypeMethodCall {
-		conn.calls.handleSendError(msg, err)
-	} else if msg.Type == TypeMethodReply {
-		if _, ok := err.(FormatError); ok {
-			conn.sendError(err, msg.Headers[FieldDestination].value.(string), msg.Headers[FieldReplySerial].value.(uint32))
-		}
-	}
-	conn.serialGen.RetireSerial(msg.serial)
-}
-
 // Send sends the given message to the message bus. You usually don't need to
 // use this; use the higher-level equivalents (Call / Go, Emit and Export)
 // instead. If msg is a method call and NoReplyExpected is not set, a non-nil
diff --git a/vendor/github.com/godbus/dbus/v5/decoder.go b/vendor/github.com/godbus/dbus/v5/decoder.go
index 89bfed9d..ede91575 100644
--- a/vendor/github.com/godbus/dbus/v5/decoder.go
+++ b/vendor/github.com/godbus/dbus/v5/decoder.go
@@ -10,16 +10,14 @@ type decoder struct {
 	in    io.Reader
 	order binary.ByteOrder
 	pos   int
-	fds   []int
 }
 
 // newDecoder returns a new decoder that reads values from in. The input is
 // expected to be in the given byte order.
-func newDecoder(in io.Reader, order binary.ByteOrder, fds []int) *decoder {
+func newDecoder(in io.Reader, order binary.ByteOrder) *decoder {
 	dec := new(decoder)
 	dec.in = in
 	dec.order = order
-	dec.fds = fds
 	return dec
 }
 
@@ -55,7 +53,7 @@ func (dec *decoder) Decode(sig Signature) (vs []interface{}, err error) {
 	vs = make([]interface{}, 0)
 	s := sig.str
 	for s != "" {
-		err, rem := validSingle(s, &depthCounter{})
+		err, rem := validSingle(s, 0)
 		if err != nil {
 			return nil, err
 		}
@@ -152,7 +150,7 @@ func (dec *decoder) decode(s string, depth int) interface{} {
 		if len(sig.str) == 0 {
 			panic(FormatError("variant signature is empty"))
 		}
-		err, rem := validSingle(sig.str, &depthCounter{})
+		err, rem := validSingle(sig.str, 0)
 		if err != nil {
 			panic(err)
 		}
@@ -163,11 +161,7 @@ func (dec *decoder) decode(s string, depth int) interface{} {
 		variant.value = dec.decode(sig.str, depth+1)
 		return variant
 	case 'h':
-		idx := dec.decode("u", depth).(uint32)
-		if int(idx) < len(dec.fds) {
-			return UnixFD(dec.fds[idx])
-		}
-		return UnixFDIndex(idx)
+		return UnixFDIndex(dec.decode("u", depth).(uint32))
 	case 'a':
 		if len(s) > 1 && s[1] == '{' {
 			ksig := s[2:3]
@@ -225,7 +219,7 @@ func (dec *decoder) decode(s string, depth int) interface{} {
 		v := make([]interface{}, 0)
 		s = s[1 : len(s)-1]
 		for s != "" {
-			err, rem := validSingle(s, &depthCounter{})
+			err, rem := validSingle(s, 0)
 			if err != nil {
 				panic(err)
 			}
diff --git a/vendor/github.com/godbus/dbus/v5/encoder.go b/vendor/github.com/godbus/dbus/v5/encoder.go
index 015b26cd..adfbb75c 100644
--- a/vendor/github.com/godbus/dbus/v5/encoder.go
+++ b/vendor/github.com/godbus/dbus/v5/encoder.go
@@ -5,33 +5,28 @@ import (
 	"encoding/binary"
 	"io"
 	"reflect"
-	"strings"
-	"unicode/utf8"
 )
 
 // An encoder encodes values to the D-Bus wire format.
 type encoder struct {
 	out   io.Writer
-	fds   []int
 	order binary.ByteOrder
 	pos   int
 }
 
 // NewEncoder returns a new encoder that writes to out in the given byte order.
-func newEncoder(out io.Writer, order binary.ByteOrder, fds []int) *encoder {
-	enc := newEncoderAtOffset(out, 0, order, fds)
-	return enc
+func newEncoder(out io.Writer, order binary.ByteOrder) *encoder {
+	return newEncoderAtOffset(out, 0, order)
 }
 
 // newEncoderAtOffset returns a new encoder that writes to out in the given
 // byte order. Specify the offset to initialize pos for proper alignment
 // computation.
-func newEncoderAtOffset(out io.Writer, offset int, order binary.ByteOrder, fds []int) *encoder {
+func newEncoderAtOffset(out io.Writer, offset int, order binary.ByteOrder) *encoder {
 	enc := new(encoder)
 	enc.out = out
 	enc.order = order
 	enc.pos = offset
-	enc.fds = fds
 	return enc
 }
 
@@ -80,9 +75,6 @@ func (enc *encoder) Encode(vs ...interface{}) (err error) {
 // encode encodes the given value to the writer and panics on error. depth holds
 // the depth of the container nesting.
 func (enc *encoder) encode(v reflect.Value, depth int) {
-	if depth > 64 {
-		panic(FormatError("input exceeds depth limitation"))
-	}
 	enc.align(alignment(v.Type()))
 	switch v.Kind() {
 	case reflect.Uint8:
@@ -105,14 +97,7 @@ func (enc *encoder) encode(v reflect.Value, depth int) {
 		enc.binwrite(uint16(v.Uint()))
 		enc.pos += 2
 	case reflect.Int, reflect.Int32:
-		if v.Type() == unixFDType {
-			fd := v.Int()
-			idx := len(enc.fds)
-			enc.fds = append(enc.fds, int(fd))
-			enc.binwrite(uint32(idx))
-		} else {
-			enc.binwrite(int32(v.Int()))
-		}
+		enc.binwrite(int32(v.Int()))
 		enc.pos += 4
 	case reflect.Uint, reflect.Uint32:
 		enc.binwrite(uint32(v.Uint()))
@@ -127,21 +112,9 @@ func (enc *encoder) encode(v reflect.Value, depth int) {
 		enc.binwrite(v.Float())
 		enc.pos += 8
 	case reflect.String:
-		str := v.String()
-		if !utf8.ValidString(str) {
-			panic(FormatError("input has a not-utf8 char in string"))
-		}
-		if strings.IndexByte(str, byte(0)) != -1 {
-			panic(FormatError("input has a null char('\\000') in string"))
-		}
-		if v.Type() == objectPathType {
-			if !ObjectPath(str).IsValid() {
-				panic(FormatError("invalid object path"))
-			}
-		}
-		enc.encode(reflect.ValueOf(uint32(len(str))), depth)
+		enc.encode(reflect.ValueOf(uint32(len(v.String()))), depth)
 		b := make([]byte, v.Len()+1)
-		copy(b, str)
+		copy(b, v.String())
 		b[len(b)-1] = 0
 		n, err := enc.out.Write(b)
 		if err != nil {
@@ -151,23 +124,20 @@ func (enc *encoder) encode(v reflect.Value, depth int) {
 	case reflect.Ptr:
 		enc.encode(v.Elem(), depth)
 	case reflect.Slice, reflect.Array:
+		if depth >= 64 {
+			panic(FormatError("input exceeds container depth limit"))
+		}
 		// Lookahead offset: 4 bytes for uint32 length (with alignment),
 		// plus alignment for elements.
 		n := enc.padding(0, 4) + 4
 		offset := enc.pos + n + enc.padding(n, alignment(v.Type().Elem()))
 
 		var buf bytes.Buffer
-		bufenc := newEncoderAtOffset(&buf, offset, enc.order, enc.fds)
+		bufenc := newEncoderAtOffset(&buf, offset, enc.order)
 
 		for i := 0; i < v.Len(); i++ {
 			bufenc.encode(v.Index(i), depth+1)
 		}
-
-		if buf.Len() > 1<<26 {
-			panic(FormatError("input exceeds array size limitation"))
-		}
-
-		enc.fds = bufenc.fds
 		enc.encode(reflect.ValueOf(uint32(buf.Len())), depth)
 		length := buf.Len()
 		enc.align(alignment(v.Type().Elem()))
@@ -176,10 +146,13 @@ func (enc *encoder) encode(v reflect.Value, depth int) {
 		}
 		enc.pos += length
 	case reflect.Struct:
+		if depth >= 64 && v.Type() != signatureType {
+			panic(FormatError("input exceeds container depth limit"))
+		}
 		switch t := v.Type(); t {
 		case signatureType:
 			str := v.Field(0)
-			enc.encode(reflect.ValueOf(byte(str.Len())), depth)
+			enc.encode(reflect.ValueOf(byte(str.Len())), depth+1)
 			b := make([]byte, str.Len()+1)
 			copy(b, str.String())
 			b[len(b)-1] = 0
@@ -203,6 +176,9 @@ func (enc *encoder) encode(v reflect.Value, depth int) {
 	case reflect.Map:
 		// Maps are arrays of structures, so they actually increase the depth by
 		// 2.
+		if depth >= 63 {
+			panic(FormatError("input exceeds container depth limit"))
+		}
 		if !isKeyType(v.Type().Key()) {
 			panic(InvalidTypeError{v.Type()})
 		}
@@ -213,13 +189,12 @@ func (enc *encoder) encode(v reflect.Value, depth int) {
 		offset := enc.pos + n + enc.padding(n, 8)
 
 		var buf bytes.Buffer
-		bufenc := newEncoderAtOffset(&buf, offset, enc.order, enc.fds)
+		bufenc := newEncoderAtOffset(&buf, offset, enc.order)
 		for _, k := range keys {
 			bufenc.align(8)
 			bufenc.encode(k, depth+2)
 			bufenc.encode(v.MapIndex(k), depth+2)
 		}
-		enc.fds = bufenc.fds
 		enc.encode(reflect.ValueOf(uint32(buf.Len())), depth)
 		length := buf.Len()
 		enc.align(8)
diff --git a/vendor/github.com/godbus/dbus/v5/export.go b/vendor/github.com/godbus/dbus/v5/export.go
index 52233471..2447b51d 100644
--- a/vendor/github.com/godbus/dbus/v5/export.go
+++ b/vendor/github.com/godbus/dbus/v5/export.go
@@ -26,27 +26,6 @@ var (
 	}
 )
 
-func MakeNoObjectError(path ObjectPath) Error {
-	return Error{
-		"org.freedesktop.DBus.Error.NoSuchObject",
-		[]interface{}{fmt.Sprintf("No such object '%s'", string(path))},
-	}
-}
-
-func MakeUnknownMethodError(methodName string) Error {
-	return Error{
-		"org.freedesktop.DBus.Error.UnknownMethod",
-		[]interface{}{fmt.Sprintf("Unknown / invalid method '%s'", methodName)},
-	}
-}
-
-func MakeUnknownInterfaceError(ifaceName string) Error {
-	return Error{
-		"org.freedesktop.DBus.Error.UnknownInterface",
-		[]interface{}{fmt.Sprintf("Object does not implement the interface '%s'", ifaceName)},
-	}
-}
-
 func MakeFailedError(err error) *Error {
 	return &Error{
 		"org.freedesktop.DBus.Error.Failed",
@@ -149,11 +128,6 @@ func (conn *Conn) handleCall(msg *Message) {
 	ifaceName, _ := msg.Headers[FieldInterface].value.(string)
 	sender, hasSender := msg.Headers[FieldSender].value.(string)
 	serial := msg.serial
-
-	if len(name) == 0 {
-		conn.sendError(ErrMsgUnknownMethod, sender, serial)
-	}
-
 	if ifaceName == "org.freedesktop.DBus.Peer" {
 		switch name {
 		case "Ping":
@@ -161,26 +135,29 @@ func (conn *Conn) handleCall(msg *Message) {
 		case "GetMachineId":
 			conn.sendReply(sender, serial, conn.uuid)
 		default:
-			conn.sendError(MakeUnknownMethodError(name), sender, serial)
+			conn.sendError(ErrMsgUnknownMethod, sender, serial)
 		}
 		return
 	}
+	if len(name) == 0 {
+		conn.sendError(ErrMsgUnknownMethod, sender, serial)
+	}
 
 	object, ok := conn.handler.LookupObject(path)
 	if !ok {
-		conn.sendError(MakeNoObjectError(path), sender, serial)
+		conn.sendError(ErrMsgNoObject, sender, serial)
 		return
 	}
 
 	iface, exists := object.LookupInterface(ifaceName)
 	if !exists {
-		conn.sendError(MakeUnknownInterfaceError(ifaceName), sender, serial)
+		conn.sendError(ErrMsgUnknownInterface, sender, serial)
 		return
 	}
 
 	m, exists := iface.LookupMethod(name)
 	if !exists {
-		conn.sendError(MakeUnknownMethodError(name), sender, serial)
+		conn.sendError(ErrMsgUnknownMethod, sender, serial)
 		return
 	}
 	args, err := conn.decodeArguments(m, sender, msg)
diff --git a/vendor/github.com/godbus/dbus/v5/message.go b/vendor/github.com/godbus/dbus/v5/message.go
index dd86aff4..6a925367 100644
--- a/vendor/github.com/godbus/dbus/v5/message.go
+++ b/vendor/github.com/godbus/dbus/v5/message.go
@@ -118,7 +118,11 @@ type header struct {
 	Variant
 }
 
-func DecodeMessageWithFDs(rd io.Reader, fds []int) (msg *Message, err error) {
+// DecodeMessage tries to decode a single message in the D-Bus wire format
+// from the given reader. The byte order is figured out from the first byte.
+// The possibly returned error can be an error of the underlying reader, an
+// InvalidMessageError or a FormatError.
+func DecodeMessage(rd io.Reader) (msg *Message, err error) {
 	var order binary.ByteOrder
 	var hlength, length uint32
 	var typ, flags, proto byte
@@ -138,7 +142,7 @@ func DecodeMessageWithFDs(rd io.Reader, fds []int) (msg *Message, err error) {
 		return nil, InvalidMessageError("invalid byte order")
 	}
 
-	dec := newDecoder(rd, order, fds)
+	dec := newDecoder(rd, order)
 	dec.pos = 1
 
 	msg = new(Message)
@@ -162,7 +166,7 @@ func DecodeMessageWithFDs(rd io.Reader, fds []int) (msg *Message, err error) {
 	if hlength+length+16 > 1<<27 {
 		return nil, InvalidMessageError("message is too long")
 	}
-	dec = newDecoder(io.MultiReader(bytes.NewBuffer(b), rd), order, fds)
+	dec = newDecoder(io.MultiReader(bytes.NewBuffer(b), rd), order)
 	dec.pos = 12
 	vs, err = dec.Decode(Signature{"a(yv)"})
 	if err != nil {
@@ -192,7 +196,7 @@ func DecodeMessageWithFDs(rd io.Reader, fds []int) (msg *Message, err error) {
 	sig, _ := msg.Headers[FieldSignature].value.(Signature)
 	if sig.str != "" {
 		buf := bytes.NewBuffer(body)
-		dec = newDecoder(buf, order, fds)
+		dec = newDecoder(buf, order)
 		vs, err := dec.Decode(sig)
 		if err != nil {
 			return nil, err
@@ -203,32 +207,12 @@ func DecodeMessageWithFDs(rd io.Reader, fds []int) (msg *Message, err error) {
 	return
 }
 
-// DecodeMessage tries to decode a single message in the D-Bus wire format
-// from the given reader. The byte order is figured out from the first byte.
-// The possibly returned error can be an error of the underlying reader, an
-// InvalidMessageError or a FormatError.
-func DecodeMessage(rd io.Reader) (msg *Message, err error) {
-	return DecodeMessageWithFDs(rd, make([]int, 0));
-}
-
-type nullwriter struct{}
-
-func (nullwriter) Write(p []byte) (cnt int, err error) {
-	return len(p), nil
-}
-
-func (msg *Message) CountFds() (int, error) {
-	if len(msg.Body) == 0 {
-		return 0, nil
-	}
-	enc := newEncoder(nullwriter{}, nativeEndian, make([]int, 0))
-	err := enc.Encode(msg.Body...)
-	return len(enc.fds), err
-}
-
-func (msg *Message) EncodeToWithFDs(out io.Writer, order binary.ByteOrder) (fds []int, err error) {
+// EncodeTo encodes and sends a message to the given writer. The byte order must
+// be either binary.LittleEndian or binary.BigEndian. If the message is not
+// valid or an error occurs when writing, an error is returned.
+func (msg *Message) EncodeTo(out io.Writer, order binary.ByteOrder) error {
 	if err := msg.IsValid(); err != nil {
-		return make([]int, 0), err
+		return err
 	}
 	var vs [7]interface{}
 	switch order {
@@ -237,16 +221,12 @@ func (msg *Message) EncodeToWithFDs(out io.Writer, order binary.ByteOrder) (fds
 	case binary.BigEndian:
 		vs[0] = byte('B')
 	default:
-		return make([]int, 0), errors.New("dbus: invalid byte order")
+		return errors.New("dbus: invalid byte order")
 	}
 	body := new(bytes.Buffer)
-	fds = make([]int, 0)
-	enc := newEncoder(body, order, fds)
+	enc := newEncoder(body, order)
 	if len(msg.Body) != 0 {
-		err = enc.Encode(msg.Body...)
-		if err != nil {
-			return
-		}
+		enc.Encode(msg.Body...)
 	}
 	vs[1] = msg.Type
 	vs[2] = msg.Flags
@@ -259,28 +239,17 @@ func (msg *Message) EncodeToWithFDs(out io.Writer, order binary.ByteOrder) (fds
 	}
 	vs[6] = headers
 	var buf bytes.Buffer
-	enc = newEncoder(&buf, order, enc.fds)
-	err = enc.Encode(vs[:]...)
-	if err != nil {
-		return
-	}
+	enc = newEncoder(&buf, order)
+	enc.Encode(vs[:]...)
 	enc.align(8)
 	body.WriteTo(&buf)
 	if buf.Len() > 1<<27 {
-		return make([]int, 0), InvalidMessageError("message is too long")
+		return InvalidMessageError("message is too long")
 	}
 	if _, err := buf.WriteTo(out); err != nil {
-		return make([]int, 0), err
+		return err
 	}
-	return enc.fds, nil
-}
-
-// EncodeTo encodes and sends a message to the given writer. The byte order must
-// be either binary.LittleEndian or binary.BigEndian. If the message is not
-// valid or an error occurs when writing, an error is returned.
-func (msg *Message) EncodeTo(out io.Writer, order binary.ByteOrder) (err error) {
-	_, err = msg.EncodeToWithFDs(out, order);
-	return err;
+	return nil
 }
 
 // IsValid checks whether msg is a valid message and returns an
diff --git a/vendor/github.com/godbus/dbus/v5/sig.go b/vendor/github.com/godbus/dbus/v5/sig.go
index 41a03981..2d326ceb 100644
--- a/vendor/github.com/godbus/dbus/v5/sig.go
+++ b/vendor/github.com/godbus/dbus/v5/sig.go
@@ -34,7 +34,7 @@ type Signature struct {
 func SignatureOf(vs ...interface{}) Signature {
 	var s string
 	for _, v := range vs {
-		s += getSignature(reflect.TypeOf(v), &depthCounter{})
+		s += getSignature(reflect.TypeOf(v))
 	}
 	return Signature{s}
 }
@@ -42,19 +42,11 @@ func SignatureOf(vs ...interface{}) Signature {
 // SignatureOfType returns the signature of the given type. It panics if the
 // type is not representable in D-Bus.
 func SignatureOfType(t reflect.Type) Signature {
-	return Signature{getSignature(t, &depthCounter{})}
+	return Signature{getSignature(t)}
 }
 
 // getSignature returns the signature of the given type and panics on unknown types.
-func getSignature(t reflect.Type, depth *depthCounter) (sig string) {
-	if !depth.Valid() {
-		panic("container nesting too deep")
-	}
-	defer func() {
-		if len(sig) > 255 {
-			panic("signature exceeds the length limitation")
-		}
-	}()
+func getSignature(t reflect.Type) string {
 	// handle simple types first
 	switch t.Kind() {
 	case reflect.Uint8:
@@ -82,7 +74,7 @@ func getSignature(t reflect.Type, depth *depthCounter) (sig string) {
 	case reflect.Float64:
 		return "d"
 	case reflect.Ptr:
-		return getSignature(t.Elem(), depth)
+		return getSignature(t.Elem())
 	case reflect.String:
 		if t == objectPathType {
 			return "o"
@@ -98,20 +90,17 @@ func getSignature(t reflect.Type, depth *depthCounter) (sig string) {
 		for i := 0; i < t.NumField(); i++ {
 			field := t.Field(i)
 			if field.PkgPath == "" && field.Tag.Get("dbus") != "-" {
-				s += getSignature(t.Field(i).Type, depth.EnterStruct())
+				s += getSignature(t.Field(i).Type)
 			}
 		}
-		if len(s) == 0 {
-			panic("empty struct")
-		}
 		return "(" + s + ")"
 	case reflect.Array, reflect.Slice:
-		return "a" + getSignature(t.Elem(), depth.EnterArray())
+		return "a" + getSignature(t.Elem())
 	case reflect.Map:
 		if !isKeyType(t.Key()) {
 			panic(InvalidTypeError{t})
 		}
-		return "a{" + getSignature(t.Key(), depth.EnterArray().EnterDictEntry()) + getSignature(t.Elem(), depth.EnterArray().EnterDictEntry()) + "}"
+		return "a{" + getSignature(t.Key()) + getSignature(t.Elem()) + "}"
 	case reflect.Interface:
 		return "v"
 	}
@@ -129,7 +118,7 @@ func ParseSignature(s string) (sig Signature, err error) {
 	}
 	sig.str = s
 	for err == nil && len(s) != 0 {
-		err, s = validSingle(s, &depthCounter{})
+		err, s = validSingle(s, 0)
 	}
 	if err != nil {
 		sig = Signature{""}
@@ -155,7 +144,7 @@ func (s Signature) Empty() bool {
 
 // Single returns whether the signature represents a single, complete type.
 func (s Signature) Single() bool {
-	err, r := validSingle(s.str, &depthCounter{})
+	err, r := validSingle(s.str, 0)
 	return err != nil && r == ""
 }
 
@@ -175,38 +164,15 @@ func (e SignatureError) Error() string {
 	return fmt.Sprintf("dbus: invalid signature: %q (%s)", e.Sig, e.Reason)
 }
 
-type depthCounter struct {
-	arrayDepth, structDepth, dictEntryDepth int
-}
-
-func (cnt *depthCounter) Valid() bool {
-	return cnt.arrayDepth <= 32 && cnt.structDepth <= 32 && cnt.dictEntryDepth <= 32
-}
-
-func (cnt depthCounter) EnterArray() *depthCounter {
-	cnt.arrayDepth++
-	return &cnt
-}
-
-func (cnt depthCounter) EnterStruct() *depthCounter {
-	cnt.structDepth++
-	return &cnt
-}
-
-func (cnt depthCounter) EnterDictEntry() *depthCounter {
-	cnt.dictEntryDepth++
-	return &cnt
-}
-
 // Try to read a single type from this string. If it was successful, err is nil
 // and rem is the remaining unparsed part. Otherwise, err is a non-nil
 // SignatureError and rem is "". depth is the current recursion depth which may
 // not be greater than 64 and should be given as 0 on the first call.
-func validSingle(s string, depth *depthCounter) (err error, rem string) {
+func validSingle(s string, depth int) (err error, rem string) {
 	if s == "" {
 		return SignatureError{Sig: s, Reason: "empty signature"}, ""
 	}
-	if !depth.Valid() {
+	if depth > 64 {
 		return SignatureError{Sig: s, Reason: "container nesting too deep"}, ""
 	}
 	switch s[0] {
@@ -221,10 +187,10 @@ func validSingle(s string, depth *depthCounter) (err error, rem string) {
 			i++
 			rem = s[i+1:]
 			s = s[2:i]
-			if err, _ = validSingle(s[:1], depth.EnterArray().EnterDictEntry()); err != nil {
+			if err, _ = validSingle(s[:1], depth+1); err != nil {
 				return err, ""
 			}
-			err, nr := validSingle(s[1:], depth.EnterArray().EnterDictEntry())
+			err, nr := validSingle(s[1:], depth+1)
 			if err != nil {
 				return err, ""
 			}
@@ -233,7 +199,7 @@ func validSingle(s string, depth *depthCounter) (err error, rem string) {
 			}
 			return nil, rem
 		}
-		return validSingle(s[1:], depth.EnterArray())
+		return validSingle(s[1:], depth+1)
 	case '(':
 		i := findMatching(s, '(', ')')
 		if i == -1 {
@@ -242,7 +208,7 @@ func validSingle(s string, depth *depthCounter) (err error, rem string) {
 		rem = s[i+1:]
 		s = s[1:i]
 		for err == nil && s != "" {
-			err, s = validSingle(s, depth.EnterStruct())
+			err, s = validSingle(s, depth+1)
 		}
 		if err != nil {
 			rem = ""
@@ -270,7 +236,7 @@ func findMatching(s string, left, right rune) int {
 // typeFor returns the type of the given signature. It ignores any left over
 // characters and panics if s doesn't start with a valid type signature.
 func typeFor(s string) (t reflect.Type) {
-	err, _ := validSingle(s, &depthCounter{})
+	err, _ := validSingle(s, 0)
 	if err != nil {
 		panic(err)
 	}
diff --git a/vendor/github.com/godbus/dbus/v5/transport_generic.go b/vendor/github.com/godbus/dbus/v5/transport_generic.go
index a08e2813..718a1ff0 100644
--- a/vendor/github.com/godbus/dbus/v5/transport_generic.go
+++ b/vendor/github.com/godbus/dbus/v5/transport_generic.go
@@ -41,12 +41,10 @@ func (t genericTransport) ReadMessage() (*Message, error) {
 }
 
 func (t genericTransport) SendMessage(msg *Message) error {
-	fds, err := msg.CountFds()
-	if err != nil {
-		return err
-	}
-	if fds != 0 {
-		return errors.New("dbus: unix fd passing not enabled")
+	for _, v := range msg.Body {
+		if _, ok := v.(UnixFD); ok {
+			return errors.New("dbus: unix fd passing not enabled")
+		}
 	}
 	return msg.EncodeTo(t, nativeEndian)
 }
diff --git a/vendor/github.com/godbus/dbus/v5/transport_unix.go b/vendor/github.com/godbus/dbus/v5/transport_unix.go
index 2212e7fa..c7cd02f9 100644
--- a/vendor/github.com/godbus/dbus/v5/transport_unix.go
+++ b/vendor/github.com/godbus/dbus/v5/transport_unix.go
@@ -113,7 +113,7 @@ func (t *unixTransport) ReadMessage() (*Message, error) {
 	if _, err := io.ReadFull(t.rdr, headerdata[4:]); err != nil {
 		return nil, err
 	}
-	dec := newDecoder(bytes.NewBuffer(headerdata), order, make([]int, 0))
+	dec := newDecoder(bytes.NewBuffer(headerdata), order)
 	dec.pos = 12
 	vs, err := dec.Decode(Signature{"a(yv)"})
 	if err != nil {
@@ -147,7 +147,7 @@ func (t *unixTransport) ReadMessage() (*Message, error) {
 		if err != nil {
 			return nil, err
 		}
-		msg, err := DecodeMessageWithFDs(bytes.NewBuffer(all), fds)
+		msg, err := DecodeMessage(bytes.NewBuffer(all))
 		if err != nil {
 			return nil, err
 		}
@@ -179,21 +179,21 @@ func (t *unixTransport) ReadMessage() (*Message, error) {
 }
 
 func (t *unixTransport) SendMessage(msg *Message) error {
-	fdcnt, err := msg.CountFds()
-	if err != nil {
-		return err
+	fds := make([]int, 0)
+	for i, v := range msg.Body {
+		if fd, ok := v.(UnixFD); ok {
+			msg.Body[i] = UnixFDIndex(len(fds))
+			fds = append(fds, int(fd))
+		}
 	}
-	if fdcnt != 0 {
+	if len(fds) != 0 {
 		if !t.hasUnixFDs {
 			return errors.New("dbus: unix fd passing not enabled")
 		}
-		msg.Headers[FieldUnixFDs] = MakeVariant(uint32(fdcnt))
-		buf := new(bytes.Buffer)
-		fds, err := msg.EncodeToWithFDs(buf, nativeEndian)
-		if err != nil {
-			return err
-		}
+		msg.Headers[FieldUnixFDs] = MakeVariant(uint32(len(fds)))
 		oob := syscall.UnixRights(fds...)
+		buf := new(bytes.Buffer)
+		msg.EncodeTo(buf, nativeEndian)
 		n, oobn, err := t.UnixConn.WriteMsgUnix(buf.Bytes(), oob, nil)
 		if err != nil {
 			return err
diff --git a/vendor/modules.txt b/vendor/modules.txt
index 453630b3..e47d9431 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -28,7 +28,7 @@ github.com/cyphar/filepath-securejoin
 # github.com/docker/go-units v0.4.0
 ## explicit
 github.com/docker/go-units
-# github.com/godbus/dbus/v5 v5.0.5
+# github.com/godbus/dbus/v5 v5.0.4
 ## explicit
 github.com/godbus/dbus/v5
 # github.com/golang/protobuf v1.5.0


Test patch:
diff --git a/libcontainer/logs/logs_linux_test.go b/libcontainer/logs/logs_linux_test.go
index d6563fd2..7e2b59d9 100644
--- a/libcontainer/logs/logs_linux_test.go
+++ b/libcontainer/logs/logs_linux_test.go
@@ -11,51 +11,44 @@ import (
 	"github.com/sirupsen/logrus"
 )
 
-const msgErr = `"level":"error"`
-
 func TestLoggingToFile(t *testing.T) {
 	l := runLogForwarding(t)
 
-	msg := `"level":"info","msg":"kitten"`
-	logToLogWriter(t, l, msg)
+	logToLogWriter(t, l, `{"level": "info","msg":"kitten"}`)
 	finish(t, l)
-	check(t, l, msg, msgErr)
+	check(t, l, "kitten")
 }
 
 func TestLogForwardingDoesNotStopOnJsonDecodeErr(t *testing.T) {
 	l := runLogForwarding(t)
 
-	logToLogWriter(t, l, `"invalid-json-with-kitten"`)
-	checkWait(t, l, msgErr, "")
+	logToLogWriter(t, l, "invalid-json-with-kitten")
+	checkWait(t, l, "failed to decode")
 
 	truncateLogFile(t, l.file)
 
-	msg := `"level":"info","msg":"puppy"`
-	logToLogWriter(t, l, msg)
+	logToLogWriter(t, l, `{"level": "info","msg":"puppy"}`)
 	finish(t, l)
-	check(t, l, msg, msgErr)
+	check(t, l, "puppy")
 }
 
 func TestLogForwardingDoesNotStopOnLogLevelParsingErr(t *testing.T) {
 	l := runLogForwarding(t)
 
-	msg := `"level":"alert","msg":"puppy"`
-	logToLogWriter(t, l, msg)
-	checkWait(t, l, msgErr, msg)
+	logToLogWriter(t, l, `{"level": "alert","msg":"puppy"}`)
+	checkWait(t, l, "failed to parse log level")
 
 	truncateLogFile(t, l.file)
 
-	msg = `"level":"info","msg":"puppy"`
-	logToLogWriter(t, l, msg)
+	logToLogWriter(t, l, `{"level": "info","msg":"puppy"}`)
 	finish(t, l)
-	check(t, l, msg, msgErr)
+	check(t, l, "puppy")
 }
 
 func TestLogForwardingStopsAfterClosingTheWriter(t *testing.T) {
 	l := runLogForwarding(t)
 
-	msg := `"level":"info","msg":"sync"`
-	logToLogWriter(t, l, msg)
+	logToLogWriter(t, l, `{"level": "info","msg":"sync"}`)
 
 	// Do not use finish() here as we check done pipe ourselves.
 	l.w.Close()
@@ -65,12 +58,12 @@ func TestLogForwardingStopsAfterClosingTheWriter(t *testing.T) {
 		t.Fatal("log forwarding did not stop after closing the pipe")
 	}
 
-	check(t, l, msg, msgErr)
+	check(t, l, "sync")
 }
 
 func logToLogWriter(t *testing.T, l *log, message string) {
 	t.Helper()
-	_, err := l.w.Write([]byte("{" + message + "}\n"))
+	_, err := l.w.Write([]byte(message + "\n"))
 	if err != nil {
 		t.Fatalf("failed to write %q to log writer: %v", message, err)
 	}
@@ -78,7 +71,7 @@ func logToLogWriter(t *testing.T, l *log, message string) {
 
 type log struct {
 	w    io.WriteCloser
-	file *os.File
+	file string
 	done chan error
 }
 
@@ -97,16 +90,19 @@ func runLogForwarding(t *testing.T) *log {
 	if err != nil {
 		t.Fatal(err)
 	}
-	t.Cleanup(func() {
-		tempFile.Close()
-		os.Remove(tempFile.Name())
-	})
+	tempFile.Close()
+	logFile := tempFile.Name()
+	t.Cleanup(func() { os.Remove(logFile) })
+
+	logConfig := Config{LogLevel: logrus.InfoLevel, LogFormat: "json", LogFilePath: logFile}
+	loggingConfigured = false
+	if err := ConfigureLogging(logConfig); err != nil {
+		t.Fatal(err)
+	}
 
-	logrus.SetOutput(tempFile)
-	logrus.SetFormatter(&logrus.JSONFormatter{})
 	doneForwarding := ForwardLogs(logR)
 
-	return &log{w: logW, done: doneForwarding, file: tempFile}
+	return &log{w: logW, done: doneForwarding, file: logFile}
 }
 
 func finish(t *testing.T, l *log) {
@@ -117,40 +113,43 @@ func finish(t *testing.T, l *log) {
 	}
 }
 
-func truncateLogFile(t *testing.T, file *os.File) {
+func truncateLogFile(t *testing.T, logFile string) {
 	t.Helper()
+	file, err := os.OpenFile(logFile, os.O_RDWR, 0o600)
+	if err != nil {
+		t.Fatalf("failed to open log file: %v", err)
+		return
+	}
+	defer file.Close()
 
-	err := file.Truncate(0)
+	err = file.Truncate(0)
 	if err != nil {
 		t.Fatalf("failed to truncate log file: %v", err)
 	}
 }
 
-// check checks that the file contains txt and does not contain notxt.
-func check(t *testing.T, l *log, txt, notxt string) {
+// check checks that file contains txt
+func check(t *testing.T, l *log, txt string) {
 	t.Helper()
-	contents, err := ioutil.ReadFile(l.file.Name())
+	contents, err := ioutil.ReadFile(l.file)
 	if err != nil {
 		t.Fatal(err)
 	}
-	if txt != "" && !bytes.Contains(contents, []byte(txt)) {
-		t.Fatalf("%s does not contain %s", contents, txt)
-	}
-	if notxt != "" && bytes.Contains(contents, []byte(notxt)) {
-		t.Fatalf("%s does contain %s", contents, notxt)
+	if !bytes.Contains(contents, []byte(txt)) {
+		t.Fatalf("%q does not contain %q", string(contents), txt)
 	}
 }
 
-// checkWait is like check, but if the file is empty,
+// checkWait checks that file contains txt. If the file is empty,
 // it waits until it's not.
-func checkWait(t *testing.T, l *log, txt string, notxt string) {
+func checkWait(t *testing.T, l *log, txt string) {
 	t.Helper()
 	const (
 		delay = 100 * time.Millisecond
 		iter  = 3
 	)
 	for i := 0; ; i++ {
-		st, err := l.file.Stat()
+		st, err := os.Stat(l.file)
 		if err != nil {
 			t.Fatal(err)
 		}
@@ -158,10 +157,10 @@ func checkWait(t *testing.T, l *log, txt string, notxt string) {
 			break
 		}
 		if i == iter {
-			t.Fatalf("waited %s for file %s to be non-empty but it still is", iter*delay, l.file.Name())
+			t.Fatalf("waited %s for file %s to be non-empty but it still is", iter*delay, l.file)
 		}
 		time.Sleep(delay)
 	}
 
-	check(t, l, txt, notxt)
+	check(t, l, txt)
 }