lima icon indicating copy to clipboard operation
lima copied to clipboard

[socketVMNet] Disable symlink detection for the socketVMNet directory

Open mritd opened this issue 2 years ago • 10 comments

Description

Currently, when Lima is installed for the first time on macOS, it will automatically create a ~/.lima/_config/networks.yaml configuration file, in which socketVMNet is automatically filled with a non-symlink directory.

But when we update socketVMNet through brew command, the old version directory may be deleted, which will cause Lima to fail to start.

If we set the socketVMNet directory to /opt/homebrew/opt/socket_vmnet/bin/socket_vmnet(this directory is a symlink maintained by brew.), it will also cause startup failure due to internal detection mechanism.

Can we use some compatible code to allow the socketVMNet directory to use symlink?

mritd avatar Mar 27 '23 11:03 mritd

@lima-vm/maintainers Can we just trust the symlink when it is owned by the admin group?

AkihiroSuda avatar Mar 28 '23 18:03 AkihiroSuda

@lima-vm/maintainers Can we just trust the symlink when it is owned by the admin group?

We would also need to check the target where the symlink points to, and all parent directories of the target, to make sure all of them are only writable by admin users. And do this recursively if any of those directories turn out to be symlinks.

jandubois avatar Mar 28 '23 19:03 jandubois

do you think that the socket_vmnet verification should be really strict as it is now? could it be relaxed?

https://github.com/lima-vm/lima/pull/2662

avoidik avatar Sep 27 '24 10:09 avoidik

do you think that the socket_vmnet verification should be really strict as it is now? could it be relaxed?

It has already been relaxed in #1220 to make it easier for Homebrew users. I feel uneasy about that already because it is not different from allowing password-less sudo access for the admin user. Which maybe is acceptable, but it should be something the user explicitly configures, and not a side-effect of the configuration of socket_vmnet.

So if anything, I think the verification should be stricter.

You should be able to delete the sudoers line from ~/.lima/_config/networks.yaml and allow password-less sudo, and the verification should be disabled already.

Just paste something like %admin ALL=(ALL) NOPASSWD:ALL into /etc/sudoers.d/nopasswd.

jandubois avatar Sep 27 '24 18:09 jandubois

as stated in the https://github.com/lima-vm/lima/pull/2662#issuecomment-2380644324 this will work if only my user is a member of the admin group, for example, if my primary group is "staff", it won't work even if my user name is in the sudoers file, due to:

https://github.com/lima-vm/lima/blob/619a4cad33af3c02dc71db82a437c4a3a908d434/pkg/networks/validate.go#L103

avoidik avatar Sep 28 '24 13:09 avoidik

I believe loosening the restrictions to allow ownership by admin instead of only root was a mistake, and will lobby to tighten them again.

There are ways to install/run the daemon securely as an unmanaged launchdaemon.

For convenience Lima allows you to create sudoers rules to run just the commands needed to start/stop the daemon as root. This is only secure if the files are owned by root. Otherwise this becomes a backdoor that allows an attacker to run any command on the system as root.

If this is not a concern, then you can enable password-less sudo and Lima will skip all file ownership checks. You don't even need the sudoers file. I've just tested it myself:

$ limactl create --tty=false template://vmnet
…
INFO[0000] Run `limactl start vmnet` to start the instance.

$ limactl start vmnet
INFO[0000] Using the existing instance "vmnet"
FATA[0000] can't read "/private/etc/sudoers.d/lima": failed to run [sudo --user root --group wheel --non-interactive true]: exit status 1: (Hint: run `limactl sudoers >etc_sudoers.d_lima && sudo install -o root etc_sudoers.d_lima "/private/etc/sudo

$ yq -i 'del(.paths.sudoers)' ~/.lima/_config/networks.yaml

$ echo "%admin ALL=(ALL) NOPASSWD:ALL" | sudo tee /etc/sudoers.d/nopasswd >/dev/null
Password:

$ limactl start vmnet
INFO[0000] Using the existing instance "vmnet"
INFO[0000] Starting socket_vmnet daemon for "shared" network
INFO[0000] Starting the instance "vmnet" with VM driver "qemu"

jandubois avatar Sep 28 '24 18:09 jandubois

This is all valid if a user is a member of the admin group (%admin).

My user is not a member of the admin group for the sake of said security, however is added in the sudoers list as user.name ALL=(ALL) NOPASSWD:ALL. In this case it's failing.

avoidik avatar Sep 28 '24 18:09 avoidik

In this case it's failing.

Can you provide the output?

Also, what happens when you run sudo -k -n --user root --group wheel true?

jandubois avatar Sep 28 '24 18:09 jandubois

however is added in the sudoers list as user.name ALL=(ALL) NOPASSWD:ALL. In this case it's failing.

I just realized that you have a . in your username. That is not going to work with sudoers. As a workaround you can create a group for this, add yourself to the group, and give the group password-less sudo.


EDIT: Actually, I'm not sure if the user.name itself is an issue; maybe it is creating /etc/sudoers.d/user.name that doesn't work, if that is what you are doing.

Anyways, seeing the actual error message might help.

jandubois avatar Sep 28 '24 20:09 jandubois

@jandubois I assume you're referring to a caveat when a sudoers file has a dot somewhere in its file name, in this case my sudoers file name has no dots in it

the output of the sudo -k -n --user root --group wheel true is 0, which is expected in the root user's context, however I do not run limactl as a root user (and it's actually impossible to run it as root):

the socket_vmnet is running as root:

$ sudo brew services list --json | jq -r '.[] | select(.name == "socket_vmnet")'
{
  "name": "socket_vmnet",
  "status": "started",
  "user": "root",
  "file": "/Library/LaunchDaemons/homebrew.mxcl.socket_vmnet.plist",
  "exit_code": 0
}

my sudoers config allows me to use password-less sudo:

$ tail /etc/sudoers.d/*
==> /etc/sudoers.d/lima <==

%everyone ALL=(root:wheel) NOPASSWD:NOSETENV: \
    /opt/homebrew/Cellar/socket_vmnet/1.1.4/bin/socket_vmnet --pidfile=/private/var/run/lima/host_socket_vmnet.pid --socket-group=everyone --vmnet-mode=host --vmnet-gateway=192.168.106.1 --vmnet-dhcp-end=192.168.106.254 --vmnet-mask=255.255.255.0 /private/var/run/lima/socket_vmnet.host, \
    /usr/bin/pkill -F /private/var/run/lima/host_socket_vmnet.pid

# Manage "shared" network daemons

%everyone ALL=(root:wheel) NOPASSWD:NOSETENV: \
    /opt/homebrew/Cellar/socket_vmnet/1.1.4/bin/socket_vmnet --pidfile=/private/var/run/lima/shared_socket_vmnet.pid --socket-group=everyone --vmnet-mode=shared --vmnet-gateway=192.168.105.1 --vmnet-dhcp-end=192.168.105.254 --vmnet-mask=255.255.255.0 /private/var/run/lima/socket_vmnet.shared, \
    /usr/bin/pkill -F /private/var/run/lima/shared_socket_vmnet.pid

==> /etc/sudoers.d/user <==
user.name ALL=(ALL) NOPASSWD: ALL

I'm able to create a new limactl VM:

$ limactl create --tty=false template://vmnet
INFO[0000] Terminal is not available, proceeding without opening an editor
INFO[0000] Attempting to download the image              arch=aarch64 digest="sha256:5ecac6447be66a164626744a87a27fd4e6c6606dc683e0a233870af63df4276a" location="https://cloud-images.ubuntu.com/releases/24.04/release-20240821/ubuntu-24.04-server-cloudimg-arm64.img"
INFO[0000] Using cache "/Users/user.name/Library/Caches/lima/download/by-url-sha256/346ee1ff9e381b78ba08e2a29445960b5cd31c51f896fc346b82e26e345a5b9a/data"
INFO[0000] Attempting to download the nerdctl archive    arch=aarch64 digest="sha256:77c747f09853ee3d229d77e8de0dd3c85622537d82be57433dc1fca4493bab95" location="https://github.com/containerd/nerdctl/releases/download/v1.7.6/nerdctl-full-1.7.6-linux-arm64.tar.gz"
INFO[0000] Using cache "/Users/user.name/Library/Caches/lima/download/by-url-sha256/21cc8dfa548ea8a678135bd6984c9feb9f8a01901d10b11bb491f6f4e7537158/data"
INFO[0000] Run `limactl start vmnet` to start the instance.

but I cannot start it:

$ limactl start vmnet
INFO[0000] Using the existing instance "vmnet"
FATA[0000] networks.yaml field `paths.socketVMNet` error: dir "/opt/homebrew/Cellar/socket_vmnet/1.1.4" owner XXXis not an admin
$ ls -ld /opt/homebrew/Cellar/socket_vmnet/1.1.4
drwxr-xr-x@ 11 user.name  admin  352 Sep 28 15:07 /opt/homebrew/Cellar/socket_vmnet/1.1.4

as you may see, the socket_vmnet directory is owned by the user.name:admin, and for some reason limactl assumes the user.name is also a member of the admin group, which is not the case:

$ id -n -g
staff

avoidik avatar Sep 30 '24 08:09 avoidik

The issue I have had reported before is now fixed 👍

avoidik avatar Nov 13 '24 00:11 avoidik