Skip to content

Commit e60338a

Browse files
thrashr888claude
andcommitted
fix: properly detect KVM permissions, not just existence
The previous check only verified /dev/kvm exists, which caused confusing errors when the user lacked permission to access it. Now we try to open /dev/kvm with read/write to verify actual access. When permission is denied, status shows helpful guidance: KVM: permission denied Note: /dev/kvm exists but you don't have permission to access it. To fix this, add yourself to the 'kvm' group: sudo usermod -aG kvm $USER Then log out and back in (or run: newgrp kvm) This allows proper fallback to Docker backend on Linux systems where KVM exists but the user isn't in the kvm group. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent 63143df commit e60338a

2 files changed

Lines changed: 77 additions & 13 deletions

File tree

src/setup.rs

Lines changed: 53 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -49,13 +49,20 @@ pub fn default_data_dir() -> PathBuf {
4949
pub fn check_installation() -> SetupStatus {
5050
let data_dir = default_data_dir();
5151

52+
// Check KVM status - distinguish between "not present" and "permission denied"
53+
let kvm_path = std::path::PathBuf::from("/dev/kvm");
54+
let kvm_exists = kvm_path.exists();
55+
let kvm_accessible = check_kvm();
56+
let kvm_permission_denied = kvm_exists && !kvm_accessible;
57+
5258
SetupStatus {
5359
kernel_installed: find_kernel(&data_dir).is_some(),
5460
rootfs_base_installed: data_dir.join("images/rootfs/base.ext4").exists(),
5561
rootfs_python_installed: data_dir.join("images/rootfs/python.ext4").exists(),
5662
rootfs_node_installed: data_dir.join("images/rootfs/node.ext4").exists(),
5763
firecracker_installed: find_firecracker().is_some(),
58-
kvm_available: check_kvm(),
64+
kvm_available: kvm_accessible,
65+
kvm_permission_denied,
5966
docker_available: check_docker(),
6067
}
6168
}
@@ -70,6 +77,8 @@ pub struct SetupStatus {
7077
pub rootfs_node_installed: bool,
7178
pub firecracker_installed: bool,
7279
pub kvm_available: bool,
80+
/// True if /dev/kvm exists but user lacks permission to access it
81+
pub kvm_permission_denied: bool,
7382
pub docker_available: bool,
7483
}
7584

@@ -107,14 +116,25 @@ impl SetupStatus {
107116
"not installed"
108117
}
109118
);
110-
println!(
111-
" KVM: {}",
112-
if self.kvm_available {
113-
"available"
114-
} else {
115-
"not available"
116-
}
117-
);
119+
// Show KVM status with helpful message if permission denied
120+
let kvm_status = if self.kvm_available {
121+
"available"
122+
} else if self.kvm_permission_denied {
123+
"permission denied"
124+
} else {
125+
"not available"
126+
};
127+
println!(" KVM: {}", kvm_status);
128+
129+
// Show guidance for KVM permission issues
130+
if self.kvm_permission_denied {
131+
println!();
132+
println!(" Note: /dev/kvm exists but you don't have permission to access it.");
133+
println!(" To fix this, add yourself to the 'kvm' group:");
134+
println!(" sudo usermod -aG kvm $USER");
135+
println!(" Then log out and back in (or run: newgrp kvm)");
136+
}
137+
118138
println!(
119139
" Docker: {}",
120140
if self.docker_available {
@@ -175,9 +195,31 @@ fn find_firecracker() -> Option<PathBuf> {
175195
None
176196
}
177197

178-
/// Check if KVM is available
198+
/// Check if KVM is available and accessible
199+
///
200+
/// Returns true only if /dev/kvm exists AND the current user has read/write access.
201+
/// This prevents the confusing case where status says "KVM: available" but operations fail.
179202
fn check_kvm() -> bool {
180-
PathBuf::from("/dev/kvm").exists()
203+
let kvm_path = std::path::PathBuf::from("/dev/kvm");
204+
if !kvm_path.exists() {
205+
return false;
206+
}
207+
208+
// Check if we can actually access KVM (not just that it exists)
209+
// Try to open with read/write to verify permissions
210+
#[cfg(unix)]
211+
{
212+
use std::fs::OpenOptions;
213+
OpenOptions::new()
214+
.read(true)
215+
.write(true)
216+
.open(&kvm_path)
217+
.is_ok()
218+
}
219+
#[cfg(not(unix))]
220+
{
221+
false
222+
}
181223
}
182224

183225
/// Check if Docker is available

src/vmm.rs

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -489,9 +489,31 @@ impl VmManager {
489489
Ok(())
490490
}
491491

492-
/// Check if KVM is available
492+
/// Check if KVM is available and accessible
493+
///
494+
/// Returns true only if /dev/kvm exists AND the current user has read/write access.
495+
/// This prevents the confusing case where status says "KVM: available" but operations fail.
493496
fn check_kvm() -> bool {
494-
PathBuf::from("/dev/kvm").exists()
497+
let kvm_path = PathBuf::from("/dev/kvm");
498+
if !kvm_path.exists() {
499+
return false;
500+
}
501+
502+
// Check if we can actually access KVM (not just that it exists)
503+
// Try to open with read/write to verify permissions
504+
#[cfg(unix)]
505+
{
506+
use std::fs::OpenOptions;
507+
OpenOptions::new()
508+
.read(true)
509+
.write(true)
510+
.open(&kvm_path)
511+
.is_ok()
512+
}
513+
#[cfg(not(unix))]
514+
{
515+
false
516+
}
495517
}
496518

497519
/// Start a sandbox

0 commit comments

Comments
 (0)