From f5dcecd427fd1c5d0ad3641cd68f4ec008cc7e56 Mon Sep 17 00:00:00 2001 From: Dan Norris Date: Wed, 22 Mar 2023 16:22:58 -0400 Subject: [PATCH] Configure the network namespace before executing jailer Right now there is a bug when trying to start a Firecracker VM with jailer using a CNI where the VM is never joined to the correct network namespace. This is because in its current form, the CNI execution occurs when `fcinit.SetupNetwork` runs, which occurs _after_ the jailer has already created a chroot and dropped privleges. This fixes the problem by executing the `fcinit.SetupNetwork` call _before_ running jailer and removing that hook from the `FcInit` functions later on. It also passes through the UID and GID options to the `tc-redirect-tap` plugin and includes the `IgnoreUnknown` directive so that chained CNI plugins work. Signed-off-by: Dan Norris --- machine.go | 22 +++++++++++++++++++++- network.go | 18 ++++++++++++++++++ 2 files changed, 39 insertions(+), 1 deletion(-) diff --git a/machine.go b/machine.go index a812b986..67313f42 100644 --- a/machine.go +++ b/machine.go @@ -376,6 +376,26 @@ func NewMachine(ctx context.Context, cfg Config, opts ...Opt) (*Machine, error) if cfg.JailerCfg != nil { m.Handlers.Validation = m.Handlers.Validation.Append(JailerConfigValidationHandler) + + if cfg.NetNS == "" && cfg.NetworkInterfaces.cniInterface() != nil { + cfg.NetNS = filepath.Join(defaultNetNSDir, cfg.VMID) + + // If the network namespace is set, we need to setup the network prior to running the jailer. + err := cfg.ValidateNetwork() + if err != nil { + return nil, fmt.Errorf("failed to validate network configuration: %w", err) + } + m.Handlers.Validation = m.Handlers.Validation.Remove(ValidateNetworkCfgHandlerName) + m.Handlers.FcInit = m.Handlers.FcInit.Remove(SetupNetworkHandlerName) + + jailLog := log.New() + err, cleanupFuncs := cfg.NetworkInterfaces.setupNetwork(ctx, cfg.VMID, cfg.NetNS, log.NewEntry(jailLog), cfg.JailerCfg.UID, cfg.JailerCfg.GID) + m.cleanupFuncs = append(m.cleanupFuncs, cleanupFuncs...) + if err != nil { + return nil, fmt.Errorf("failed to setup network prior to jailing: %w", err) + } + } + if err := jail(ctx, m, &cfg); err != nil { return nil, err } @@ -492,7 +512,7 @@ func (m *Machine) GetFirecrackerVersion(ctx context.Context) (string, error) { } func (m *Machine) setupNetwork(ctx context.Context) error { - err, cleanupFuncs := m.Cfg.NetworkInterfaces.setupNetwork(ctx, m.Cfg.VMID, m.Cfg.NetNS, m.logger) + err, cleanupFuncs := m.Cfg.NetworkInterfaces.setupNetwork(ctx, m.Cfg.VMID, m.Cfg.NetNS, m.logger, nil, nil) m.cleanupFuncs = append(m.cleanupFuncs, cleanupFuncs...) return err } diff --git a/network.go b/network.go index 35352996..da2a2713 100644 --- a/network.go +++ b/network.go @@ -98,6 +98,8 @@ func (networkInterfaces NetworkInterfaces) setupNetwork( vmID string, netNSPath string, logger *log.Entry, + uid *int, + gid *int, ) (error, []func() error) { var cleanupFuncs []func() error @@ -111,6 +113,22 @@ func (networkInterfaces NetworkInterfaces) setupNetwork( cniNetworkInterface.CNIConfiguration.containerID = vmID cniNetworkInterface.CNIConfiguration.netNSPath = netNSPath cniNetworkInterface.CNIConfiguration.setDefaults() + if uid != nil && gid != nil { + cniNetworkInterface.CNIConfiguration.Args = [][2]string{ + { + "IgnoreUnknown", + "true", + }, + { + "TC_REDIRECT_TAP_UID", + fmt.Sprintf("%d", *uid), + }, + { + "TC_REDIRECT_TAP_GID", + fmt.Sprintf("%d", *gid), + }, + } + } // Make sure the netns is setup. If the path doesn't yet exist, it will be // initialized with a new empty netns.