Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[master] FATA[0002] networks.yaml field paths.varRun error: path "." is not an absolute path #2313

Closed
AkihiroSuda opened this issue May 1, 2024 · 3 comments · Fixed by #2317
Labels
bug Something isn't working component/network/vmnet
Milestone

Comments

@AkihiroSuda
Copy link
Member

AkihiroSuda commented May 1, 2024

Description

In the master branch of Lima (05ed151), limactl start template://vmnet fails with an existing networks.yaml

$ limactl start template://vmnet 
? Creating an instance "vmnet" Proceed with the current configuration
FATA[0002] networks.yaml field `paths.varRun` error: path "." is not an absolute path

~/.lima/_config/networks.yaml:

# Path to socket_vmnet executable. Because socket_vmnet is invoked via sudo it should be
# installed where only root can modify/replace it. This means also none of the
# parent directories should be writable by the user.
#
# The varRun directory also must not be writable by the user because it will
# include the socket_vmnet pid file. Those will be terminated via sudo, so replacing
# the pid file would allow killing of arbitrary privileged processes. varRun
# however MUST be writable by the daemon user.
#
# None of the paths segments may be symlinks, why it has to be /private/var
# instead of /var etc.
paths:
# socketVMNet requires Lima >= 0.12 .
# socketVMNet has precedence over vdeVMNet.
  socketVMNet: "/opt/socket_vmnet/bin/socket_vmnet"
# vdeSwitch and vdeVMNet are DEPRECATED.
  vdeSwitch: /opt/vde/bin/vde_switch
  vdeVMNet: /opt/vde/bin/vde_vmnet
  varRun: /private/var/run/lima
  sudoers: /private/etc/sudoers.d/lima

group: everyone

networks:
  user-v2:
    mode: user-v2
    gateway: 192.168.104.1
    netmask: 255.255.255.0
    # user-v2 network is experimental network mode which supports all functionalities of default usernet network and also allows vm -> vm communication.
    # Doesn't support configuration of custom gateway; hardcoded to 192.168.5.0/24
  shared:
    mode: shared
    gateway: 192.168.105.1
    dhcpEnd: 192.168.105.254
    netmask: 255.255.255.0
  bridged:
    mode: bridged
    interface: en0
    # bridged mode doesn't have a gateway; dhcp is managed by outside network
  host:
    mode: host
    gateway: 192.168.106.1
    dhcpEnd: 192.168.106.254
    netmask: 255.255.255.0
@AkihiroSuda AkihiroSuda added this to the v0.22.0 milestone May 1, 2024
@AkihiroSuda AkihiroSuda added bug Something isn't working component/network/vmnet labels May 1, 2024
@AkihiroSuda
Copy link
Member Author

A workaround is to remove the VDE lines from networks.yaml

@AkihiroSuda
Copy link
Member Author

@jandubois Could you take a look? 🙏
The validation code is hard to understand

func (config *YAML) Validate() error {
// validate all paths.* values
paths := reflect.ValueOf(&config.Paths).Elem()
pathsMap := make(map[string]string, paths.NumField())
var socketVMNetNotFound bool
for i := 0; i < paths.NumField(); i++ {
// extract YAML name from struct tag; strip options like "omitempty"
name := paths.Type().Field(i).Tag.Get("yaml")
if i := strings.IndexRune(name, ','); i > -1 {
name = name[:i]
}
path := paths.Field(i).Interface().(string)
pathsMap[name] = path
// varPath will be created securely, but any existing parent directories must already be secure
if name == "varRun" {
path = findBaseDirectory(path)
}
err := validatePath(path, name == "varRun")
if err != nil {
if errors.Is(err, os.ErrNotExist) {
switch name {
// sudoers file does not need to exist; otherwise `limactl sudoers` couldn't bootstrap
case "sudoers":
continue
case "socketVMNet":
socketVMNetNotFound = true
continue
}
}
return fmt.Errorf("networks.yaml field `paths.%s` error: %w", name, err)
}
}
if socketVMNetNotFound {
return fmt.Errorf("networks.yaml: %q (`paths.socketVMNet`) has to be installed", pathsMap["socketVMNet"])
}
// TODO(jandubois): validate network definitions
return nil
}

@jandubois
Copy link
Member

The problem is not the validation code, but the YAML parsing:

cache.err = yaml.UnmarshalWithOptions(b, &cache.config, yaml.Strict())

Since we pass the yaml.Strict() option, the Paths field will not be unmarshalled, so SocketVMNet, VarRun, and Sudoers will all be empty strings.

And filepath.Dir("") will return . (called by findBaseDirectory), explaining the error message.

I'm somewhat surprised that UnmarshalWithOptions does not return an error in that case, and does fill in the Group and Networks fields.

Anyways, 2 possible fixes are:

  • remove the yaml.Strict() option
  • keep the unused fields in the Paths struct

Given that the yaml.Strict() option doesn't seem to result in a proper error, I would tend towards the first option. If we can fix the error reporting, then I would favour the second one.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working component/network/vmnet
Projects
None yet
2 participants