Compare commits

...

50 Commits

Author SHA1 Message Date
Zvonko Kaiser
c980b6e191 release: Bump version to 3.20.0
Bump VERSION and helm-chart versions

Signed-off-by: Zvonko Kaiser <zkaiser@nvidia.com>
2025-08-20 18:18:05 +02:00
Markus Rudy
30aff429df Merge pull request #11647 from Park-Jiyeonn/opt/sealed-secret-prefix-check
Optimize sealed secret scanning to avoid full file reads
2025-08-20 17:18:20 +02:00
Alex Lyn
014ab2fce6 Merge pull request #11693 from BbolroC/revert-initdata-annotation
runtime-rs: Fix issues for initdata
2025-08-20 21:17:52 +08:00
Fabiano Fidêncio
dd1752ac1c Merge pull request #11634 from mythi/coco-kernel-v6.16
versions: update kernel-confidential to Linux v6.16.1
2025-08-20 13:01:05 +02:00
Fupan Li
29ab8df881 Merge pull request #11514 from Apokleos/ci-for-libs
CI: Introduce CI for libs to Improve code quality and reduce noises
2025-08-20 18:59:27 +08:00
Hyounggyu Choi
0ac8f1f70e Merge pull request #11705 from Apokleos/remove-default-guesthookpath
kata-types: remove default setting of guest_hook_path
2025-08-20 11:15:25 +02:00
Mikko Ylinen
a0ae1b6608 packaging: kernel: libdw-dev and python3 to builder image
These new dependencies are needed by Linux 6.16+.

Signed-off-by: Mikko Ylinen <mikko.ylinen@intel.com>
2025-08-20 11:34:09 +03:00
Mikko Ylinen
412a384aad versions: update kernel-confidential to Linux v6.16.1
Linux v6.16 brings some useful features for the confidential guests.
Most importantly, it adds an ABI to extend runtime measurement registers
(RTMR) for the TEE platforms supporting it. This is currently enabled
on Intel TDX only.

The kernel version bump from v6.12.x to v6.16 forces some CONFIG_*
changes too:

MEMORY_HOTPLUG_DEFAULT_ONLINE was dropped in favor of more config
choices. The equivalent option is MHP_DEFAULT_ONLINE_TYPE_ONLINE_AUTO.

X86_5LEVEL was made unconditional. Since this was only a TDX
configuration, dropping it completely as part of v6.16 is fine.

CRYPTO_NULL2 was merged with CRYPTO_NULL. This was only added in
confidential guest fragments (cryptsetup) so we can drop it in this update.

CRYPTO_FIPS now depends on CRYPTO_SELFTESTS which further depends on
EXPERT which we don't have. Enable both in a separate config fragment
for confidential guests. This can be moved to a common setting once
other targets bump to post v6.16.

CRYPTO_SHA256_SSE3 arch optimizations were reworked and are now enabled
by default. Instead of adding it to whitelist.conf, just drop it completely
since it was only enabled as part of "measured boot" feature for
confidential guests. CONFIG_CRYPTO_CRC32_S390 was reworked the same way.
In this case, whitelist.conf is needed.

Signed-off-by: Mikko Ylinen <mikko.ylinen@intel.com>
2025-08-20 11:32:48 +03:00
Hyounggyu Choi
0daafecef2 Revert "runtime-rs: Correct the coresponding initdata annotation const"
This reverts commit 37685c41c7.

This renames the relevant constant for initdata.

Signed-off-by: Hyounggyu Choi <Hyounggyu.Choi@ibm.com>
2025-08-20 10:15:23 +02:00
Hyounggyu Choi
f0db4032f2 Revert "kata-types: Align the initdata annotation with kata-runtime's definition"
This reverts commit ede773db17.

`cc_init_data` should be under a hypervisor category because
it is a hypervisor-specific feature. The annotation including
`runtime` also breaks a logic for `is_annotation_enabled()`.

Signed-off-by: Hyounggyu Choi <Hyounggyu.Choi@ibm.com>
2025-08-20 10:15:23 +02:00
Hyounggyu Choi
208cec429a runtime-rs: Introduce CoCo-specific enable_annotations
We need to include `cc_init_data` in the enable_annotations
array to pass the data. Since initdata is a CoCo-specific
feature, this commit introduces a new array,
`DEFENABLEANNOTATIONS_COCO`, which contains the required
string and applies it to the relevant CoCo configuration.

Signed-off-by: Hyounggyu Choi <Hyounggyu.Choi@ibm.com>
2025-08-20 10:15:23 +02:00
Hyounggyu Choi
1f978ecc31 runtime-rs: Fix issues for empty initdata annotation test
Currently, there are 2 issues for the empty initdata annotation
test:

- Empty string handling
- "\[CDH\] \[ERROR\]: Get Resource failed" not appearing

`add_hypervisor_initdata_overrides()` does not handle
an empty string, which might lead to panic like:

```
called `Result::unwrap()` on an `Err` value: gz decoder failed
Caused by:
    failed to fill whole buffer
```

This commit makes the function return an empty string
for a given empty input and updates the assertion string
to one that appears in both go-runtime and runtime-rs.

Signed-off-by: Alex Lyn <alex.lyn@antgroup.com>
Signed-off-by: Hyounggyu Choi <Hyounggyu.Choi@ibm.com>
2025-08-20 10:15:23 +02:00
alex.lyn
b23d094928 CI: Introduce CI for libs to Improve code quality and reduce noises
Currently, runtime-rs related code within the libs directory lacks
sufficient CI protection. We frequently observe the following issues:
- Inconsistent Code Formatting: Code that has not been properly
  formatted
is merged.
- Failing Tests: Code with failing unit or integration tests is merged.

To address these issues, we need introduce stricter CI checks for the
libs directory. This may specifically include:
- Code Formatting Checks
- Mandatory Test Runs

Fixes #11512

Signed-off-by: alex.lyn <alex.lyn@antgroup.com>
2025-08-20 15:36:09 +08:00
alex.lyn
0f19465b3a shim-interface: Do cargo check and reduce warnings
Reduce shim-interface's warings caused by non-formatted or unchecked operations.

Signed-off-by: alex.lyn <alex.lyn@antgroup.com>
2025-08-20 15:36:09 +08:00
alex.lyn
e05197e81c safe-path: Do cargo check and reduce warnings
Reduce warings caused by non-formatted or unchecked operations.

Signed-off-by: alex.lyn <alex.lyn@antgroup.com>
2025-08-20 15:36:09 +08:00
alex.lyn
683d673f4f protocols: Do cargo format to make codes clean
Fix protocols' warings by correctly do cargo check/format.

Signed-off-by: alex.lyn <alex.lyn@antgroup.com>
2025-08-20 15:36:09 +08:00
alex.lyn
38242d3a61 kata-types: Do cargo check and reduce warnings
Reduce noises caused by non-formated codes.

Signed-off-by: alex.lyn <alex.lyn@antgroup.com>
2025-08-20 15:36:09 +08:00
alex.lyn
283fd45045 kata-sys-utils: fix warnings for s390x
The warning reports as bwlow:
```
   --> kata-sys-util/src/protection.rs:145:9
    |
145 |         return Err(ProtectionError::NoPerms)?;
    |         ^^^^^^^ help: remove it
    |
...
error: `to_string` applied to a type that implements `Display` in
`format!` args
   --> kata-sys-util/src/protection.rs:151:16
    |
151 |             err.to_string()
    |                ^^^^^^^^^^^^ help: remove this
```

Signed-off-by: alex.lyn <alex.lyn@antgroup.com>
2025-08-20 15:36:09 +08:00
alex.lyn
730b0f1769 kata-sys-utils: Do cargo check codes and reduce warnings
Fix kata-sys-utils warings by correctly do cargo check and test it well.

Signed-off-by: alex.lyn <alex.lyn@antgroup.com>
2025-08-20 15:35:42 +08:00
Fabiano Fidêncio
585d0be342 Merge pull request #11691 from alextibbles/update-lts-kernel
versions: update to latest LTS kernel 6.12.42
2025-08-20 08:55:06 +02:00
Fupan Li
b748688e69 Merge pull request #11698 from Apokleos/filter-arpneibhors
runtime-rs: Add only static ARP entries with handle_neighours
2025-08-20 14:05:20 +08:00
Alex Lyn
c4af9be411 kata-types: remove default setting of guest_hook_path
To make it aligned with the setting of runtime-go, we should keep
it as empty when users doesn't enable and set its specified path.

Signed-off-by: Alex Lyn <alex.lyn@antgroup.com>
2025-08-20 13:56:42 +08:00
Zvonko Kaiser
bce8efca67 gpu: Rebuild initrd and image for kernel bump
We need to make sure that we use the latest kernel
and rebuild the initrd and image for the nvidia-gpu
use-cases otherwise the tests will fail since
the modules are not build against the new kernel and
they simply fail to load.

Signed-off-by: Zvonko Kaiser <zkaiser@nvidia.com>
2025-08-19 17:32:42 -04:00
Alex Tibbles
e20f6b2f9d versions: update to latest LTS kernel 6.12.42
Fixes #11690

Signed-off-by: Alex Tibbles <alex@bleg.org>
2025-08-19 17:32:42 -04:00
Fabiano Fidêncio
3503bcdb50 Merge pull request #11701 from alextibbles/go-stdlib-#11700
versions: sync go.mod with versions.yaml for go 1.23.12
2025-08-19 22:14:57 +02:00
Alex Tibbles
a03dc3129d versions: sync go.mod with versions.yaml for go 1.23.12
OSV-Scanner highlights go.mod references to go stdlib 1.23.0 contrary to intention in versions.yaml, so synchronize them.
Make a converse comment for versions.yaml.

Fixes: #11700

Signed-off-by: Alex Tibbles <alex@bleg.org>
2025-08-19 11:30:19 -04:00
Hyounggyu Choi
93ec470928 runtime/tests: Update annotation for initdata
Let's rename the runtime-rs initdata annotation from
`io.katacontainers.config.runtime.cc_init_data` to
`io.katacontainers.config.hypervisor.cc_init_data`.

Rationale:
- initdata itself is a hypervisor-specific feature
- the new name aligns with the annotation handling logic:
c92bb1aa88/src/libs/kata-types/src/annotations/mod.rs (L514-L968)

This commit updates the annotation for go-runtime and tests accordingly.

Signed-off-by: Hyounggyu Choi <Hyounggyu.Choi@ibm.com>
2025-08-19 15:17:01 +02:00
Alex Lyn
903e608c23 runtime-rs: Add only static ARP entries with handle_neighours
To make it aligned with runtime-go, we need add only static ARP
entries into the targets.

Fixes #11697

Signed-off-by: Alex Lyn <alex.lyn@antgroup.com>
2025-08-19 20:09:20 +08:00
Steve Horsman
c92bb1aa88 Merge pull request #11684 from zvonkok/gpu-required
gatekeeper: GPU test required
2025-08-15 10:30:19 +01:00
Hyounggyu Choi
28bd0cf405 Merge pull request #11640 from rafsal-rahim/bm-initdata-s390x
Feat | Implement initdata for bare-metal/qemu for s390x
2025-08-15 10:42:32 +02:00
Zvonko Kaiser
3a4e1917d2 gatekeeper: Make GPU test required
We now run a simple RAG pipeline with each PR to make
sure we do not break GPU support.

Signed-off-by: Zvonko Kaiser <zkaiser@nvidia.com>
2025-08-14 18:35:39 -04:00
Aurélien Bombo
3a5e2060aa Merge pull request #11683 from kata-containers/sprt/static-checks-default-branch
ci: static-checks: Don't hardcode default repo branch
2025-08-14 17:01:18 -05:00
Zvonko Kaiser
55ee8abf0b Merge pull request #11658 from kata-containers/amd64-nvidia-gpu-cicd-step2
gpu: AMD64 NVIDIA GPU CI/CD Part 2
2025-08-14 17:51:26 -04:00
Aurélien Bombo
0fa7d5b293 ci: static-checks: Don't hardcode default repo branch
This would cause weird issues for downstreams which default branch is not
"main".

Signed-off-by: Aurélien Bombo <abombo@microsoft.com>
2025-08-14 13:22:20 -05:00
Zvonko Kaiser
dcb62a7f91 Merge pull request #11525 from was-saw/qemu-seccomp
runtime-rs: add seccomp support for qemu
2025-08-14 12:35:32 -04:00
Zvonko Kaiser
8be41a4e80 gpu: Add embeding service
For a simple RAG pipeline add a embeding service

Signed-off-by: Zvonko Kaiser <zkaiser@nvidia.com>
2025-08-14 16:34:21 +00:00
RuoqingHe
65a9fe0063 Merge pull request #11670 from kevinzs2048/add-aavmf
CI: change the directory for Arm64 firmware
2025-08-14 21:30:21 +08:00
stevenhorsman
43cdde4c5d test/k8s: Extend initdata tests to run on s390x
Enable testing of initdata on the qemu-coco-dev and qemu-se
runtime classes, so we can validate the function on s390x

Signed-off-by: stevenhorsman <steven@uk.ibm.com>
2025-08-14 17:10:58 +05:30
rafsalrahim
9891b111d1 runtime: Add initdata support to s390x
- Added support for initdata device on s390x.
- Generalized devno generation for QEMU CCW devices.

Signed-off-by: rafsalrahim <rafsal.rahim@ibm.com>
2025-08-14 17:10:58 +05:30
wangxinge
d147e2491b runtime-rs: add seccomp support for qemu
This commit support the seccomp_sandbox option from the configuration.toml file
and add the logic for appending command-line arguments based on this new configuration parameter.

Fixes: #11524

Signed-off-by: wangxinge <wangxinge@bupt.edu.cn>
2025-08-14 18:45:03 +08:00
Xuewei Niu
479cce8406 Merge pull request #11536 from was-saw/clh/fc-seccomp
runtime-rs: add seccomp support for cloud hypervisor and firecracker
2025-08-14 18:23:14 +08:00
Dan Mihai
ea74024b93 Merge pull request #11663 from burgerdev/arp
genpolicy: support AddARPNeighbors
2025-08-13 14:54:36 -07:00
Kevin Zhao
aadad0c9b6 CI: change the directory for Arm64 firmware
Previouly it is reusing the ovmf, which will enter some
issue for path checking, so move to aavmf as it should
be.

Signed-off-by: Kevin Zhao <kevin.zhao@linaro.org>
2025-08-13 23:39:44 +02:00
Fabiano Fidêncio
cfd0ebe85f Merge pull request #11675 from katexochen/snp-guest-policy
runtime: make SNP guest policy configurable
2025-08-13 22:20:51 +02:00
Steve Horsman
c7f4c9a3bb Merge pull request #11676 from stevenhorsman/golang-1.23.12-bump
versions: Bump golang to 1.23.12
2025-08-13 15:24:17 +01:00
Park.Jiyeon
2f50c85b12 agent: avoid full file reads when scanning sealed secrets.
Read only the sealed secret prefix instead of the whole file.
Improves performance and reduces memory usage in I/O-heavy environments.

Fixes: #11643

Signed-off-by: Park.Jiyeon <jiyeonnn2@icloud.com>
2025-08-13 20:32:03 +08:00
Paul Meyer
5635410dd3 runtime: make SNP guest policy configurable
Dependening on the platform configuration, users might want to
set a more secure policy than the QEMU default.

Signed-off-by: Paul Meyer <katexochen0@gmail.com>
2025-08-13 09:06:36 +02:00
stevenhorsman
1a6f1fc3ac versions: Bump golang to 1.23.12
Bump go version to remediate vuln GO-2025-3849

Signed-off-by: stevenhorsman <steven@uk.ibm.com>
2025-08-12 14:46:29 +01:00
wangxinge
f3a669ee2d runtime-rs: add seccomp support for cloud hypervisor and firecracker
The seccomp feature for Cloud Hypervisor and Firecracker is enabled by default.
This commit introduces an option to disable seccomp for both and updates the built-in configuration.toml file accordingly.

Fixes: #11535

Signed-off-by: wangxinge <wangxinge@bupt.edu.cn>
2025-08-11 17:59:30 +08:00
Markus Rudy
3eb0641431 genpolicy: add rule for AddARPNeighbors
When the network interface provisioned by the CNI has static ARP table entries,
the runtime calls AddARPNeighbor to propagate these to the agent. As of today,
these calls are simply rejected.

In order to allow the calls, we do some sanity checks on the arguments:

We must ensure that we don't unexpectedly route traffic to the host that was
not intended to leave the VM. In a first approximation, this applies to
loopback IPs and devices. However, there may be other sensitive ranges (for
example, VPNs between VMs), so there should be some flexibility for users to
restrict this further. This is why we introduce a setting, similar to
UpdateRoutes, that allows restricting the neighbor IPs further.

The only valid state of an ARP neighbor entry is NUD_PERMANENT, which has a
value of 128 [1]. This is already enforced by the runtime.

According to rtnetlink(7), valid flag values are 8 and 128, respectively [2],
thus we allow any combination of these.

[1]: https://github.com/torvalds/linux/blob/4790580/include/uapi/linux/neighbour.h#L72
[2]: https://github.com/torvalds/linux/blob/4790580/include/uapi/linux/neighbour.h#L49C20-L53

Fixes: #11664

Signed-off-by: Markus Rudy <mr@edgeless.systems>
2025-08-06 17:24:36 +02:00
75 changed files with 1351 additions and 487 deletions

View File

@@ -42,6 +42,10 @@ jobs:
path: src/runtime-rs
needs:
- rust
- name: libs
path: src/libs
needs:
- rust
- name: agent-ctl
path: src/tools/agent-ctl
needs:

View File

@@ -1 +1 @@
3.19.1
3.20.0

View File

@@ -22,6 +22,8 @@ use protocols::{
};
use safe_path::scoped_join;
use std::fs;
use std::fs::File;
use std::io::{self, Read};
use std::path::Path;
use std::{os::unix::fs::symlink, path::PathBuf};
use tokio::sync::OnceCell;
@@ -235,8 +237,8 @@ pub async fn unseal_file(path: &str) -> Result<()> {
}
let secret_name = entry.file_name();
let contents = fs::read_to_string(&target_path)?;
if contents.starts_with(SEALED_SECRET_PREFIX) {
if content_starts_with_prefix(&target_path, SEALED_SECRET_PREFIX).await? {
let contents = fs::read_to_string(&target_path)?;
// Get the directory name of the sealed secret file
let dir_name = target_path
.parent()
@@ -262,6 +264,17 @@ pub async fn unseal_file(path: &str) -> Result<()> {
Ok(())
}
pub async fn content_starts_with_prefix(path: &Path, prefix: &str) -> io::Result<bool> {
let mut file = File::open(path)?;
let mut buffer = vec![0u8; prefix.len()];
match file.read_exact(&mut buffer) {
Ok(()) => Ok(buffer == prefix.as_bytes()),
Err(ref e) if e.kind() == io::ErrorKind::UnexpectedEof => Ok(false),
Err(e) => Err(e),
}
}
pub async fn secure_mount(
volume_type: &str,
options: &std::collections::HashMap<String, String>,
@@ -294,7 +307,7 @@ mod tests {
use std::fs::File;
use std::io::{Read, Write};
use std::sync::Arc;
use tempfile::tempdir;
use tempfile::{tempdir, NamedTempFile};
use test_utils::skip_if_not_root;
use tokio::signal::unix::{signal, SignalKind};
struct TestService;
@@ -416,4 +429,34 @@ mod tests {
rt.shutdown_background();
std::thread::sleep(std::time::Duration::from_secs(2));
}
#[tokio::test]
async fn test_content_starts_with_prefix() {
// Normal case: content matches the prefix
let mut f = NamedTempFile::new().unwrap();
write!(f, "sealed.hello_world").unwrap();
assert!(content_starts_with_prefix(f.path(), "sealed.")
.await
.unwrap());
// Does not match the prefix
let mut f2 = NamedTempFile::new().unwrap();
write!(f2, "notsealed.hello_world").unwrap();
assert!(!content_starts_with_prefix(f2.path(), "sealed.")
.await
.unwrap());
// File length < prefix.len()
let mut f3 = NamedTempFile::new().unwrap();
write!(f3, "seal").unwrap();
assert!(!content_starts_with_prefix(f3.path(), "sealed.")
.await
.unwrap());
// Empty file
let f4 = NamedTempFile::new().unwrap();
assert!(!content_starts_with_prefix(f4.path(), "sealed.")
.await
.unwrap());
}
}

View File

@@ -34,8 +34,7 @@ pub fn is_ephemeral_volume(mount: &Mount) -> bool {
mount.destination(),
),
(Some("bind"), Some(source), dest) if get_linux_mount_info(source)
.map_or(false, |info| info.fs_type == "tmpfs") &&
(Some("bind"), Some(source), dest) if get_linux_mount_info(source).is_ok_and(|info| info.fs_type == "tmpfs") &&
(is_empty_dir(source) || dest.as_path() == Path::new("/dev/shm"))
)
}

View File

@@ -823,11 +823,11 @@ mod tests {
#[test]
fn test_get_linux_mount_info() {
let info = get_linux_mount_info("/sys/fs/cgroup").unwrap();
let info = get_linux_mount_info("/dev/shm").unwrap();
assert_eq!(&info.device, "tmpfs");
assert_eq!(&info.fs_type, "tmpfs");
assert_eq!(&info.path, "/sys/fs/cgroup");
assert_eq!(&info.path, "/dev/shm");
assert!(matches!(
get_linux_mount_info(""),

View File

@@ -168,7 +168,7 @@ pub fn is_valid_numa_cpu(cpus: &[u32]) -> Result<bool> {
let numa_nodes = get_numa_nodes()?;
for cpu in cpus {
if numa_nodes.get(cpu).is_none() {
if !numa_nodes.contains_key(cpu) {
return Ok(false);
}
}

View File

@@ -66,7 +66,7 @@ impl PCIDevices for NvidiaPCIDevice {
}
}
return nvidia_devices;
nvidia_devices
}
}

View File

@@ -7,7 +7,7 @@
use std::collections::HashMap;
use std::fs;
use std::io;
use std::path::PathBuf;
use std::path::{Path, PathBuf};
use mockall::automock;
use pci_ids::{Classes, Vendors};
@@ -61,24 +61,22 @@ pub(crate) trait MemoryResourceTrait {
impl MemoryResourceTrait for MemoryResources {
fn get_total_addressable_memory(&self, round_up: bool) -> (u64, u64) {
let mut num_bar = 0;
let mut mem_size_32bit = 0u64;
let mut mem_size_64bit = 0u64;
let mut keys: Vec<_> = self.keys().cloned().collect();
keys.sort();
for key in keys {
if key as usize >= PCI_IOV_NUM_BAR || num_bar == PCI_IOV_NUM_BAR {
for (num_bar, key) in keys.into_iter().enumerate() {
if key >= PCI_IOV_NUM_BAR || num_bar == PCI_IOV_NUM_BAR {
break;
}
num_bar += 1;
if let Some(region) = self.get(&key) {
let flags = region.flags & PCI_BASE_ADDRESS_MEM_TYPE_MASK;
let mem_type_32bit = flags == PCI_BASE_ADDRESS_MEM_TYPE32;
let mem_type_64bit = flags == PCI_BASE_ADDRESS_MEM_TYPE64;
let mem_size = (region.end - region.start + 1) as u64;
let mem_size = region.end - region.start + 1;
if mem_type_32bit {
mem_size_32bit += mem_size;
@@ -138,10 +136,10 @@ impl PCIDeviceManager {
for entry in device_dirs {
let device_dir = entry?;
let device_address = device_dir.file_name().to_string_lossy().to_string();
if let Ok(device) = self.get_device_by_pci_bus_id(&device_address, vendor, &mut cache) {
if let Some(dev) = device {
pci_devices.push(dev);
}
if let Ok(Some(dev)) =
self.get_device_by_pci_bus_id(&device_address, vendor, &mut cache)
{
pci_devices.push(dev);
}
}
@@ -238,7 +236,7 @@ impl PCIDeviceManager {
Ok(Some(pci_device))
}
fn parse_resources(&self, device_path: &PathBuf) -> io::Result<MemoryResources> {
fn parse_resources(&self, device_path: &Path) -> io::Result<MemoryResources> {
let content = fs::read_to_string(device_path.join("resource"))?;
let mut resources: MemoryResources = MemoryResources::new();
for (i, line) in content.lines().enumerate() {
@@ -405,6 +403,8 @@ mod tests {
#[test]
fn test_parse_resources() {
setup_mock_device_files();
let manager = PCIDeviceManager::new(MOCK_PCI_DEVICES_ROOT);
let device_path = PathBuf::from(MOCK_PCI_DEVICES_ROOT).join("0000:ff:1f.0");
@@ -418,6 +418,8 @@ mod tests {
assert_eq!(resource.start, 0x00000000);
assert_eq!(resource.end, 0x0000ffff);
assert_eq!(resource.flags, 0x00000404);
cleanup_mock_device_files();
}
#[test]
@@ -435,10 +437,7 @@ mod tests {
file.write_all(&vec![0; 512]).unwrap();
// It should be true
assert!(is_pcie_device(
&format!("ff:00.0"),
MOCK_SYS_BUS_PCI_DEVICES
));
assert!(is_pcie_device("ff:00.0", MOCK_SYS_BUS_PCI_DEVICES));
// Clean up
let _ = fs::remove_file(config_path);

View File

@@ -142,14 +142,11 @@ pub fn arch_guest_protection(
#[allow(dead_code)]
pub fn available_guest_protection() -> Result<GuestProtection, ProtectionError> {
if !Uid::effective().is_root() {
return Err(ProtectionError::NoPerms)?;
Err(ProtectionError::NoPerms)?;
}
let facilities = crate::cpu::retrieve_cpu_facilities().map_err(|err| {
ProtectionError::CheckFailed(format!(
"Error retrieving cpu facilities file : {}",
err.to_string()
))
ProtectionError::CheckFailed(format!("Error retrieving cpu facilities file : {}", err))
})?;
// Secure Execution

View File

@@ -8,7 +8,6 @@ use std::collections::HashMap;
use std::fs::File;
use std::io::{self, BufReader, Result};
use std::result::{self};
use std::u32;
use serde::Deserialize;
@@ -273,7 +272,8 @@ pub const KATA_ANNO_CFG_HYPERVISOR_VIRTIO_FS_EXTRA_ARGS: &str =
/// A sandbox annotation to specify as the msize for 9p shares.
pub const KATA_ANNO_CFG_HYPERVISOR_MSIZE_9P: &str = "io.katacontainers.config.hypervisor.msize_9p";
/// The initdata annotation passed in when CVM launchs
pub const KATA_ANNO_CFG_RUNTIME_INIT_DATA: &str = "io.katacontainers.config.runtime.cc_init_data";
pub const KATA_ANNO_CFG_HYPERVISOR_INIT_DATA: &str =
"io.katacontainers.config.hypervisor.cc_init_data";
/// GPU specific annotations for remote hypervisor to help with instance selection
/// It's for minimum number of GPUs required for the VM.
@@ -462,12 +462,12 @@ impl Annotation {
/// update config info by annotation
pub fn update_config_by_annotation(&self, config: &mut TomlConfig) -> Result<()> {
if let Some(hv) = self.annotations.get(KATA_ANNO_CFG_RUNTIME_HYPERVISOR) {
if config.hypervisor.get(hv).is_some() {
if config.hypervisor.contains_key(hv) {
config.runtime.hypervisor_name = hv.to_string();
}
}
if let Some(ag) = self.annotations.get(KATA_ANNO_CFG_RUNTIME_AGENT) {
if config.agent.get(ag).is_some() {
if config.agent.contains_key(ag) {
config.runtime.agent_name = ag.to_string();
}
}
@@ -894,7 +894,7 @@ impl Annotation {
hv.security_info.validate_path(value)?;
hv.security_info.guest_hook_path = value.to_string();
}
KATA_ANNO_CFG_RUNTIME_INIT_DATA => {
KATA_ANNO_CFG_HYPERVISOR_INIT_DATA => {
hv.security_info.initdata =
add_hypervisor_initdata_overrides(value).unwrap();
}
@@ -943,8 +943,7 @@ impl Annotation {
}
}
KATA_ANNO_CFG_HYPERVISOR_VIRTIO_FS_EXTRA_ARGS => {
let args: Vec<String> =
value.to_string().split(',').map(str::to_string).collect();
let args: Vec<String> = value.split(',').map(str::to_string).collect();
for arg in args {
hv.shared_fs.virtio_fs_extra_args.push(arg.to_string());
}
@@ -970,7 +969,7 @@ impl Annotation {
// update agent config
KATA_ANNO_CFG_KERNEL_MODULES => {
let kernel_mod: Vec<String> =
value.to_string().split(';').map(str::to_string).collect();
value.split(';').map(str::to_string).collect();
for modules in kernel_mod {
ag.kernel_modules.push(modules.to_string());
}
@@ -991,14 +990,16 @@ impl Annotation {
return Err(u32_err);
}
},
KATA_ANNO_CFG_RUNTIME_CREATE_CONTAINTER_TIMEOUT => match self.get_value::<u32>(key) {
Ok(v) => {
ag.request_timeout_ms = v.unwrap_or_default() * 1000;
KATA_ANNO_CFG_RUNTIME_CREATE_CONTAINTER_TIMEOUT => {
match self.get_value::<u32>(key) {
Ok(v) => {
ag.request_timeout_ms = v.unwrap_or_default() * 1000;
}
Err(_e) => {
return Err(u32_err);
}
}
Err(_e) => {
return Err(u32_err);
}
},
}
// update runtime config
KATA_ANNO_CFG_RUNTIME_NAME => {
let runtime = vec!["virt-container", "linux-container", "wasm-container"];
@@ -1031,8 +1032,7 @@ impl Annotation {
}
},
KATA_ANNO_CFG_EXPERIMENTAL => {
let args: Vec<String> =
value.to_string().split(',').map(str::to_string).collect();
let args: Vec<String> = value.split(',').map(str::to_string).collect();
for arg in args {
config.runtime.experimental.push(arg.to_string());
}

View File

@@ -115,7 +115,10 @@ pub struct Agent {
/// This timeout value is used to set the maximum duration for the agent to process a CreateContainerRequest.
/// It's also used to ensure that workloads, especially those involving large image pulls within the guest,
/// have sufficient time to complete.
#[serde(default = "default_request_timeout", rename = "create_container_timeout")]
#[serde(
default = "default_request_timeout",
rename = "create_container_timeout"
)]
pub request_timeout_ms: u32,
/// Agent health check request timeout value in millisecond
@@ -127,12 +130,12 @@ pub struct Agent {
/// These modules will be loaded in the guest kernel using modprobe(8).
/// The following example can be used to load two kernel modules with parameters:
/// - kernel_modules=["e1000e InterruptThrottleRate=3000,3000,3000 EEE=1", "i915 enable_ppgtt=0"]
/// The first word is considered as the module name and the rest as its parameters.
/// Container will not be started when:
/// The first word is considered as the module name and the rest as its parameters.
/// Container will not be started when:
/// - A kernel module is specified and the modprobe command is not installed in the guest
/// or it fails loading the module.
/// - The module is not available in the guest or it doesn't met the guest kernel
/// requirements, like architecture and version.
/// requirements, like architecture and version.
#[serde(default)]
pub kernel_modules: Vec<String>,

View File

@@ -6,7 +6,6 @@
use std::io::Result;
use std::path::Path;
use std::sync::Arc;
use std::u32;
use super::{default, register_hypervisor_plugin};
use crate::config::default::MAX_DRAGONBALL_VCPUS;

File diff suppressed because it is too large Load Diff

View File

@@ -9,7 +9,6 @@ use std::fs;
use std::io::{self, Result};
use std::path::{Path, PathBuf};
use std::sync::{Arc, Mutex};
use std::u32;
use lazy_static::lazy_static;

View File

@@ -8,6 +8,7 @@ use flate2::read::GzDecoder;
use serde::{Deserialize, Serialize};
use sha2::{Digest, Sha256, Sha384, Sha512};
use std::{collections::HashMap, io::Read};
use crate::sl;
/// Currently, initdata only supports version 0.1.0.
const INITDATA_VERSION: &str = "0.1.0";
@@ -129,20 +130,20 @@ fn calculate_digest(algorithm: &str, data: &str) -> Result<Vec<u8>> {
let digest = match algorithm {
"sha256" => {
let mut hasher = Sha256::new();
hasher.update(&data);
hasher.update(data);
hasher.finalize().to_vec()
}
"sha384" => {
let mut hasher = Sha384::new();
hasher.update(&data);
hasher.update(data);
hasher.finalize().to_vec()
}
"sha512" => {
let mut hasher = Sha512::new();
hasher.update(&data);
hasher.update(data);
hasher.finalize().to_vec()
}
_ => return Err(anyhow!("unsupported Hash algorithm: {}", algorithm).into()),
_ => return Err(anyhow!("unsupported Hash algorithm: {}", algorithm)),
};
Ok(digest)
@@ -172,7 +173,7 @@ fn adjust_digest(digest: &[u8], platform: ProtectedPlatform) -> Vec<u8> {
/// Parse initdata
fn parse_initdata(initdata_str: &str) -> Result<InitData> {
let initdata: InitData = toml::from_str(&initdata_str)?;
let initdata: InitData = toml::from_str(initdata_str)?;
initdata.validate()?;
Ok(initdata)
@@ -192,7 +193,7 @@ pub fn calculate_initdata_digest(
let algorithm: &str = &initdata.algorithm;
// 2. Calculate Digest
let digest = calculate_digest(algorithm, &initdata_toml).context("calculate digest")?;
let digest = calculate_digest(algorithm, initdata_toml).context("calculate digest")?;
// 3. Adjust Digest with Platform
let digest_platform = adjust_digest(&digest, platform);
@@ -203,12 +204,18 @@ pub fn calculate_initdata_digest(
Ok(b64encoded_digest)
}
/// The argument `initda_annotation` is a Standard base64 encoded string containing a TOML formatted content.
/// The argument `initdata_annotation` is a Standard base64 encoded string containing a TOML formatted content.
/// This function decodes the base64 string, parses the TOML content into an InitData structure.
pub fn add_hypervisor_initdata_overrides(initda_annotation: &str) -> Result<String> {
pub fn add_hypervisor_initdata_overrides(initdata_annotation: &str) -> Result<String> {
// If the initdata is empty, return an empty string
if initdata_annotation.is_empty() {
info!(sl!(), "initdata_annotation is empty");
return Ok("".to_string());
}
// Base64 decode the annotation value
let b64_decoded =
base64::decode_config(initda_annotation, base64::STANDARD).context("base64 decode")?;
base64::decode_config(initdata_annotation, base64::STANDARD).context("base64 decode")?;
// Gzip decompress the decoded data
let mut gz_decoder = GzDecoder::new(&b64_decoded[..]);
@@ -231,6 +238,139 @@ mod tests {
use flate2::Compression;
use std::io::Write;
// create gzipped and base64 encoded string
fn create_encoded_input(content: &str) -> String {
let mut encoder = GzEncoder::new(Vec::new(), Compression::default());
encoder.write_all(content.as_bytes()).unwrap();
let compressed = encoder.finish().unwrap();
base64::encode_config(&compressed, base64::STANDARD)
}
#[test]
fn test_empty_annotation() {
// Test with empty string input
let result = add_hypervisor_initdata_overrides("");
assert!(result.is_ok());
assert_eq!(result.unwrap(), "");
}
#[test]
fn test_empty_data_section() {
// Test with empty data section
let toml_content = r#"
algorithm = "sha384"
version = "0.1.0"
[data]
"#;
let encoded = create_encoded_input(toml_content);
let result = add_hypervisor_initdata_overrides(&encoded);
assert!(result.is_ok());
}
#[test]
fn test_valid_complete_initdata() {
// Test with complete InitData structure
let toml_content = r#"
algorithm = "sha384"
version = "0.1.0"
[data]
"aa.toml" = '''
[token_configs]
[token_configs.coco_as]
url = 'http://kbs-service.xxx.cluster.local:8080'
[token_configs.kbs]
url = 'http://kbs-service.xxx.cluster.local:8080'
'''
"cdh.toml" = '''
socket = 'unix:///run/guest-services/cdh.sock'
credentials = []
[kbc]
name = 'cc_kbc'
url = 'http://kbs-service.xxx.cluster.local:8080'
'''
"#;
let encoded = create_encoded_input(toml_content);
let result = add_hypervisor_initdata_overrides(&encoded);
assert!(result.is_ok());
let output = result.unwrap();
assert!(!output.is_empty());
assert!(output.contains("algorithm"));
assert!(output.contains("version"));
}
#[test]
fn test_invalid_base64() {
// Test with invalid base64 string
let invalid_base64 = "This is not valid base64!";
let result = add_hypervisor_initdata_overrides(invalid_base64);
assert!(result.is_err());
let error = result.unwrap_err();
assert!(error.to_string().contains("base64 decode"));
}
#[test]
fn test_valid_base64_invalid_gzip() {
// Test with valid base64 but invalid gzip content
let not_gzipped = "This is not gzipped content";
let encoded = base64::encode_config(not_gzipped.as_bytes(), base64::STANDARD);
let result = add_hypervisor_initdata_overrides(&encoded);
assert!(result.is_err());
let error = result.unwrap_err();
assert!(error.to_string().contains("gz decoder failed"));
}
#[test]
fn test_missing_algorithm() {
// Test with missing algorithm field
let toml_content = r#"
version = "0.1.0"
[data]
"test.toml" = '''
key = "value"
'''
"#;
let encoded = create_encoded_input(toml_content);
let result = add_hypervisor_initdata_overrides(&encoded);
// This might fail depending on whether algorithm is required
if result.is_err() {
assert!(result.unwrap_err().to_string().contains("parse initdata"));
}
}
#[test]
fn test_missing_version() {
// Test with missing version field
let toml_content = r#"
algorithm = "sha384"
[data]
"test.toml" = '''
key = "value"
'''
"#;
let encoded = create_encoded_input(toml_content);
let result = add_hypervisor_initdata_overrides(&encoded);
// This might fail depending on whether version is required
if result.is_err() {
assert!(result.unwrap_err().to_string().contains("parse initdata"));
}
}
/// Test InitData creation and serialization
#[test]
fn test_init_data() {

View File

@@ -205,47 +205,48 @@ pub struct NydusImageVolume {
pub snapshot_dir: String,
}
/// Kata virtual volume to encapsulate information for extra mount options and direct volumes.
/// Represents a Kata virtual volume, encapsulating information for extra mount options and direct volumes.
///
/// It's very expensive to build direct communication channels to pass information:
/// - between snapshotters and kata-runtime/kata-agent/image-rs
/// - between CSI drivers and kata-runtime/kata-agent
/// Direct communication channels between components like snapshotters, `kata-runtime`, `kata-agent`,
/// `image-rs`, and CSI drivers are often expensive to build and maintain.
///
/// So `KataVirtualVolume` is introduced to encapsulate extra mount options and direct volume
/// information, so we can build a common infrastructure to handle them.
/// `KataVirtualVolume` is a superset of `NydusExtraOptions` and `DirectVolumeMountInfo`.
/// Therefore, `KataVirtualVolume` is introduced as a common infrastructure to encapsulate
/// additional mount options and direct volume information. It serves as a superset of
/// `NydusExtraOptions` and `DirectVolumeMountInfo`.
///
/// Value of `volume_type` determines how to interpret other fields in the structure.
/// The interpretation of other fields within this structure is determined by the `volume_type` field.
///
/// - `KATA_VIRTUAL_VOLUME_IGNORE`
/// -- all other fields should be ignored/unused.
/// # Volume Types:
///
/// - `KATA_VIRTUAL_VOLUME_DIRECT_BLOCK`
/// -- `source`: the directly assigned block device
/// -- `fs_type`: filesystem type
/// -- `options`: mount options
/// -- `direct_volume`: additional metadata to pass to the agent regarding this volume.
/// - `KATA_VIRTUAL_VOLUME_IGNORE`:
/// All other fields should be ignored/unused.
///
/// - `KATA_VIRTUAL_VOLUME_IMAGE_RAW_BLOCK` or `KATA_VIRTUAL_VOLUME_LAYER_RAW_BLOCK`
/// -- `source`: path to the raw block image for the container image or layer.
/// -- `fs_type`: filesystem type
/// -- `options`: mount options
/// -- `dm_verity`: disk dm-verity information
/// - `KATA_VIRTUAL_VOLUME_DIRECT_BLOCK`:
/// - `source`: The directly assigned block device path.
/// - `fs_type`: Filesystem type.
/// - `options`: Mount options.
/// - `direct_volume`: Additional metadata to pass to the agent regarding this volume.
///
/// - `KATA_VIRTUAL_VOLUME_IMAGE_NYDUS_BLOCK` or `KATA_VIRTUAL_VOLUME_LAYER_NYDUS_BLOCK`
/// -- `source`: path to nydus meta blob
/// -- `fs_type`: filesystem type
/// -- `nydus_image`: configuration information for nydus image.
/// -- `dm_verity`: disk dm-verity information
/// - `KATA_VIRTUAL_VOLUME_IMAGE_RAW_BLOCK` or `KATA_VIRTUAL_VOLUME_LAYER_RAW_BLOCK`:
/// - `source`: Path to the raw block image for the container image or layer.
/// - `fs_type`: Filesystem type.
/// - `options`: Mount options.
/// - `dm_verity`: Disk `dm-verity` information.
///
/// - `KATA_VIRTUAL_VOLUME_IMAGE_NYDUS_FS` or `KATA_VIRTUAL_VOLUME_LAYER_NYDUS_FS`
/// -- `source`: path to nydus meta blob
/// -- `fs_type`: filesystem type
/// -- `nydus_image`: configuration information for nydus image.
/// - `KATA_VIRTUAL_VOLUME_IMAGE_NYDUS_BLOCK` or `KATA_VIRTUAL_VOLUME_LAYER_NYDUS_BLOCK`:
/// - `source`: Path to nydus meta blob.
/// - `fs_type`: Filesystem type.
/// - `nydus_image`: Configuration information for nydus image.
/// - `dm_verity`: Disk `dm-verity` information.
///
/// - `KATA_VIRTUAL_VOLUME_IMAGE_GUEST_PULL`
/// -- `source`: image reference
/// -- `image_pull`: metadata for image pulling
/// - `KATA_VIRTUAL_VOLUME_IMAGE_NYDUS_FS` or `KATA_VIRTUAL_VOLUME_LAYER_NYDUS_FS`:
/// - `source`: Path to nydus meta blob.
/// - `fs_type`: Filesystem type.
/// - `nydus_image`: Configuration information for nydus image.
///
/// - `KATA_VIRTUAL_VOLUME_IMAGE_GUEST_PULL`:
/// - `source`: Image reference.
/// - `image_pull`: Metadata for image pulling.
#[derive(Debug, Clone, Eq, PartialEq, Default, Serialize, Deserialize)]
pub struct KataVirtualVolume {
/// Type of virtual volume.
@@ -275,7 +276,7 @@ pub struct KataVirtualVolume {
}
impl KataVirtualVolume {
/// Create a new instance of `KataVirtualVolume` with specified type.
/// Creates a new instance of `KataVirtualVolume` with the specified type.
pub fn new(volume_type: String) -> Self {
Self {
volume_type,
@@ -283,7 +284,7 @@ impl KataVirtualVolume {
}
}
/// Validate virtual volume object.
/// Validates the virtual volume object.
pub fn validate(&self) -> Result<()> {
match self.volume_type.as_str() {
KATA_VIRTUAL_VOLUME_DIRECT_BLOCK => {
@@ -365,25 +366,25 @@ impl KataVirtualVolume {
Ok(())
}
/// Serialize the virtual volume object to json.
/// Serializes the virtual volume object to a JSON string.
pub fn to_json(&self) -> Result<String> {
Ok(serde_json::to_string(self)?)
}
/// Deserialize a virtual volume object from json string.
/// Deserializes a virtual volume object from a JSON string.
pub fn from_json(value: &str) -> Result<Self> {
let volume: KataVirtualVolume = serde_json::from_str(value)?;
volume.validate()?;
Ok(volume)
}
/// Serialize the virtual volume object to json and encode the string with base64.
/// Serializes the virtual volume object to a JSON string and encodes the string with base64.
pub fn to_base64(&self) -> Result<String> {
let json = self.to_json()?;
Ok(base64::encode(json))
}
/// Decode and deserialize a virtual volume object from base64 encoded json string.
/// Decodes and deserializes a virtual volume object from a base64 encoded JSON string.
pub fn from_base64(value: &str) -> Result<Self> {
let json = base64::decode(value)?;
let volume: KataVirtualVolume = serde_json::from_slice(&json)?;
@@ -453,18 +454,18 @@ impl TryFrom<&NydusExtraOptions> for KataVirtualVolume {
}
}
/// Trait object for storage device.
/// Trait object for a storage device.
pub trait StorageDevice: Send + Sync {
/// Path
/// Returns the path of the storage device, if available.
fn path(&self) -> Option<&str>;
/// Clean up resources related to the storage device.
/// Cleans up resources related to the storage device.
fn cleanup(&self) -> Result<()>;
}
/// Join user provided volume path with kata direct-volume root path.
/// Joins a user-provided volume path with the Kata direct-volume root path.
///
/// The `volume_path` is base64-url-encoded and then safely joined to the `prefix`
/// The `volume_path` is base64-url-encoded and then safely joined to the `prefix`.
pub fn join_path(prefix: &str, volume_path: &str) -> Result<PathBuf> {
if volume_path.is_empty() {
return Err(anyhow!(std::io::ErrorKind::NotFound));
@@ -474,7 +475,7 @@ pub fn join_path(prefix: &str, volume_path: &str) -> Result<PathBuf> {
Ok(safe_path::scoped_join(prefix, b64_url_encoded_path)?)
}
/// get DirectVolume mountInfo from mountinfo.json.
/// Gets `DirectVolumeMountInfo` from `mountinfo.json`.
pub fn get_volume_mount_info(volume_path: &str) -> Result<DirectVolumeMountInfo> {
let volume_path = join_path(KATA_DIRECT_VOLUME_ROOT_PATH, volume_path)?;
let mount_info_file_path = volume_path.join(KATA_MOUNT_INFO_FILE_NAME);
@@ -484,28 +485,30 @@ pub fn get_volume_mount_info(volume_path: &str) -> Result<DirectVolumeMountInfo>
Ok(mount_info)
}
/// Check whether a mount type is a marker for Kata specific volume.
/// Checks whether a mount type is a marker for a Kata specific volume.
pub fn is_kata_special_volume(ty: &str) -> bool {
ty.len() > KATA_VOLUME_TYPE_PREFIX.len() && ty.starts_with(KATA_VOLUME_TYPE_PREFIX)
}
/// Check whether a mount type is a marker for Kata guest mount volume.
/// Checks whether a mount type is a marker for a Kata guest mount volume.
pub fn is_kata_guest_mount_volume(ty: &str) -> bool {
ty.len() > KATA_GUEST_MOUNT_PREFIX.len() && ty.starts_with(KATA_GUEST_MOUNT_PREFIX)
}
/// Check whether a mount type is a marker for Kata ephemeral volume.
/// Checks whether a mount type is a marker for a Kata ephemeral volume.
pub fn is_kata_ephemeral_volume(ty: &str) -> bool {
ty == KATA_EPHEMERAL_VOLUME_TYPE
}
/// Check whether a mount type is a marker for Kata hostdir volume.
/// Checks whether a mount type is a marker for a Kata hostdir volume.
pub fn is_kata_host_dir_volume(ty: &str) -> bool {
ty == KATA_HOST_DIR_VOLUME_TYPE
}
/// sandbox bindmount format: /path/to/dir, or /path/to/dir:ro[:rw]
/// the real path is without suffix ":ro" or ":rw".
/// Splits a sandbox bindmount string into its real path and mode.
///
/// The `bindmount` format is typically `/path/to/dir` or `/path/to/dir:ro[:rw]`.
/// This function extracts the real path (without the suffix ":ro" or ":rw") and the mode.
pub fn split_bind_mounts(bindmount: &str) -> (&str, &str) {
let (real_path, mode) = if bindmount.ends_with(SANDBOX_BIND_MOUNTS_RO) {
(
@@ -525,12 +528,14 @@ pub fn split_bind_mounts(bindmount: &str) -> (&str, &str) {
(real_path, mode)
}
/// This function, adjust_rootfs_mounts, manages the root filesystem mounts based on guest-pull mechanism.
/// - the function disregards any provided rootfs_mounts.
/// Instead, it forcefully creates a single, default KataVirtualVolume specifically for guest-pull operations.
/// This volume's representation is then base64-encoded and added as the only option to a new, singular Mount entry,
/// which becomes the sole item in the returned Vec<Mount>.
/// This ensures that when guest pull is active, the root filesystem is exclusively configured via this virtual volume.
/// Adjusts the root filesystem mounts based on the guest-pull mechanism.
///
/// This function disregards any provided `rootfs_mounts`. Instead, it forcefully creates
/// a single, default `KataVirtualVolume` specifically for guest-pull operations.
/// This volume's representation is then base64-encoded and added as the only option
/// to a new, singular `Mount` entry, which becomes the sole item in the returned `Vec<Mount>`.
/// This ensures that when guest pull is active, the root filesystem is exclusively
/// configured via this virtual volume.
pub fn adjust_rootfs_mounts() -> Result<Vec<Mount>> {
// We enforce a single, default KataVirtualVolume as the exclusive rootfs mount.
let volume = KataVirtualVolume::new(KATA_VIRTUAL_VOLUME_IMAGE_GUEST_PULL.to_string());

View File

@@ -115,7 +115,7 @@ impl From<oci::PosixRlimit> for grpc::POSIXRlimit {
impl From<oci::Process> for grpc::Process {
fn from(from: oci::Process) -> Self {
grpc::Process {
Terminal: from.terminal().map_or(false, |t| t),
Terminal: from.terminal().is_some_and(|t| t),
ConsoleSize: from_option(from.console_size()),
User: from_option(Some(from.user().clone())),
Args: option_vec_to_vec(from.args()),
@@ -161,7 +161,7 @@ impl From<oci::LinuxMemory> for grpc::LinuxMemory {
Kernel: from.kernel().map_or(0, |t| t),
KernelTCP: from.kernel_tcp().map_or(0, |t| t),
Swappiness: from.swappiness().map_or(0, |t| t),
DisableOOMKiller: from.disable_oom_killer().map_or(false, |t| t),
DisableOOMKiller: from.disable_oom_killer().is_some_and(|t| t),
..Default::default()
}
}

View File

@@ -355,6 +355,7 @@ mod tests {
.read(false)
.write(true)
.create(true)
.truncate(true)
.mode(0o200)
.open(&path)
.unwrap();
@@ -376,6 +377,7 @@ mod tests {
.read(false)
.write(true)
.create(true)
.truncate(true)
.mode(0o200)
.open(&path)
.unwrap();

View File

@@ -90,7 +90,7 @@ pub fn mgmt_socket_addr(sid: &str) -> Result<String> {
));
}
get_uds_with_sid(sid, &sb_storage_path()?)
get_uds_with_sid(sid, sb_storage_path()?)
}
#[cfg(test)]

View File

@@ -147,6 +147,7 @@ DEFMAXMEMSZ := 0
##VAR DEFBRIDGES=<number> Default number of bridges
DEFBRIDGES := 0
DEFENABLEANNOTATIONS := [\"kernel_params\"]
DEFENABLEANNOTATIONS_COCO := [\"kernel_params\",\"cc_init_data\"]
DEFDISABLEGUESTSECCOMP := true
DEFDISABLEGUESTEMPTYDIR := false
##VAR DEFAULTEXPFEATURES=[features] Default experimental features enabled
@@ -482,6 +483,7 @@ USER_VARS += DEFVIRTIOFSCACHE
USER_VARS += DEFVIRTIOFSQUEUESIZE
USER_VARS += DEFVIRTIOFSEXTRAARGS
USER_VARS += DEFENABLEANNOTATIONS
USER_VARS += DEFENABLEANNOTATIONS_COCO
USER_VARS += DEFENABLEIOTHREADS
USER_VARS += DEFSECCOMPSANDBOXPARAM
USER_VARS += DEFGUESTSELINUXLABEL

View File

@@ -195,6 +195,9 @@ block_device_driver = "virtio-blk-pci"
# result in memory pre allocation
#enable_hugepages = true
# Disable the 'seccomp' feature from Cloud Hypervisor or firecracker, default false
# disable_seccomp = true
# This option changes the default hypervisor and kernel parameters
# to enable debug output where available.
#

View File

@@ -45,7 +45,7 @@ confidential_guest = true
# List of valid annotation names for the hypervisor
# Each member of the list is a regular expression, which is the base name
# of the annotation, e.g. "path" for io.katacontainers.config.hypervisor.path"
enable_annotations = @DEFENABLEANNOTATIONS@
enable_annotations = @DEFENABLEANNOTATIONS_COCO@
# List of valid annotations values for the hypervisor
# Each member of the list is a path pattern as described by glob(3).

View File

@@ -145,6 +145,9 @@ block_device_driver = "@DEFBLOCKSTORAGEDRIVER_FC@"
# result in memory pre allocation
#enable_hugepages = true
# Disable the 'seccomp' feature from Cloud Hypervisor or firecracker, default false
# disable_seccomp = true
# Enable vIOMMU, default false
# Enabling this will result in the VM having a vIOMMU device
# This will also add the following options to the kernel's

View File

@@ -103,6 +103,9 @@ impl FcInner {
cmd.args(["--api-sock", &self.asock_path]);
}
}
if self.config.security_info.disable_seccomp {
cmd.arg("--no-seccomp");
}
debug!(sl(), "Exec: {:?}", cmd);
// Make sure we're in the correct Network Namespace

View File

@@ -2182,6 +2182,14 @@ impl<'a> QemuCmdLine<'a> {
qemu_cmd_line.add_virtio_balloon();
}
if let Some(seccomp_sandbox) = &config
.security_info
.seccomp_sandbox
.as_ref()
.filter(|s| !s.is_empty())
{
qemu_cmd_line.add_seccomp_sandbox(seccomp_sandbox);
}
Ok(qemu_cmd_line)
}
@@ -2620,6 +2628,11 @@ impl<'a> QemuCmdLine<'a> {
Ok(())
}
pub fn add_seccomp_sandbox(&mut self, param: &str) {
let seccomp_sandbox = SeccompSandbox::new(param);
self.devices.push(Box::new(seccomp_sandbox));
}
pub async fn build(&self) -> Result<Vec<String>> {
let mut result = Vec::new();
@@ -2706,3 +2719,23 @@ impl ToQemuParams for DeviceVirtioBalloon {
])
}
}
#[derive(Debug)]
struct SeccompSandbox {
param: String,
}
impl SeccompSandbox {
fn new(param: &str) -> Self {
SeccompSandbox {
param: param.to_owned(),
}
}
}
#[async_trait]
impl ToQemuParams for SeccompSandbox {
async fn qemu_params(&self) -> Result<Vec<String>> {
Ok(vec!["-sandbox".to_owned(), self.param.clone()])
}
}

View File

@@ -14,8 +14,8 @@ use kata_types::{
cri_containerd::{SANDBOX_NAMESPACE_LABEL_KEY, SANDBOX_NAME_LABEL_KEY},
KATA_ANNO_CFG_HYPERVISOR_DEFAULT_GPUS, KATA_ANNO_CFG_HYPERVISOR_DEFAULT_GPU_MODEL,
KATA_ANNO_CFG_HYPERVISOR_DEFAULT_MEMORY, KATA_ANNO_CFG_HYPERVISOR_DEFAULT_VCPUS,
KATA_ANNO_CFG_HYPERVISOR_IMAGE_PATH, KATA_ANNO_CFG_HYPERVISOR_MACHINE_TYPE,
KATA_ANNO_CFG_RUNTIME_INIT_DATA,
KATA_ANNO_CFG_HYPERVISOR_IMAGE_PATH, KATA_ANNO_CFG_HYPERVISOR_INIT_DATA,
KATA_ANNO_CFG_HYPERVISOR_MACHINE_TYPE,
},
capabilities::{Capabilities, CapabilityBits},
};
@@ -127,7 +127,7 @@ impl RemoteInner {
config.boot_info.image.to_string(),
);
annotations.insert(
KATA_ANNO_CFG_RUNTIME_INIT_DATA.to_string(),
KATA_ANNO_CFG_HYPERVISOR_INIT_DATA.to_string(),
config.security_info.initdata.to_string(),
);
annotations.insert(

View File

@@ -6,7 +6,7 @@
use std::{collections::HashMap, sync::Arc, thread};
use agent::{types::Device, Agent, OnlineCPUMemRequest, Storage};
use agent::{types::Device, ARPNeighbor, Agent, OnlineCPUMemRequest, Storage};
use anyhow::{anyhow, Context, Ok, Result};
use async_trait::async_trait;
use hypervisor::{
@@ -22,6 +22,7 @@ use kata_types::{
config::{hypervisor::TopologyConfigInfo, TomlConfig},
mount::{adjust_rootfs_mounts, KATA_IMAGE_FORCE_GUEST_PULL},
};
use libc::NUD_PERMANENT;
use oci::{Linux, LinuxCpu, LinuxResources};
use oci_spec::runtime::{self as oci, LinuxDeviceType};
use persist::sandbox_persist::Persist;
@@ -260,7 +261,14 @@ impl ResourceManagerInner {
}
async fn handle_neighbours(&self, network: &dyn Network) -> Result<()> {
let neighbors = network.neighs().await.context("neighs")?;
let all_neighbors = network.neighs().await.context("neighs")?;
// We add only static ARP entries
let neighbors: Vec<ARPNeighbor> = all_neighbors
.iter()
.filter(|n| n.state == NUD_PERMANENT as i32)
.cloned()
.collect();
if !neighbors.is_empty() {
info!(sl!(), "update neighbors {:?}", neighbors);
self.agent

View File

@@ -16,9 +16,11 @@ ifeq ($(ARCH),)
endif
ifeq ($(ARCH),x86_64)
override ARCH = amd64
override EDK2_NAME = ovmf
endif
ifeq ($(ARCH),aarch64)
override ARCH = arm64
override EDK2_NAME = aavmf
endif
ifeq ($(ARCH),riscv64gc)
override ARCH = riscv64
@@ -215,7 +217,7 @@ DEFMAXMEMSZ := 0
#Default number of bridges
DEFBRIDGES := 1
DEFENABLEANNOTATIONS := [\"enable_iommu\", \"virtio_fs_extra_args\", \"kernel_params\"]
DEFENABLEANNOTATIONSTEE := [\"enable_iommu\", \"virtio_fs_extra_args\", \"kernel_params\", \"default_vcpus\", \"default_memory\"]
DEFENABLEANNOTATIONS_COCO := [\"enable_iommu\", \"virtio_fs_extra_args\", \"kernel_params\", \"default_vcpus\", \"default_memory\", \"cc_init_data\"]
DEFDISABLEGUESTSECCOMP := true
DEFDISABLEGUESTEMPTYDIR := false
#Default experimental features enabled
@@ -460,10 +462,10 @@ ifneq (,$(QEMUCMD))
FIRMWAREPATH_NV := $(PREFIXDEPS)/share/ovmf/OVMF.fd
ifneq (,$(QEMUFW))
FIRMWAREPATH := $(PREFIXDEPS)/share/ovmf/$(QEMUFW)
FIRMWAREPATH := $(PREFIXDEPS)/share/$(EDK2_NAME)/$(QEMUFW)
endif
ifneq (,$(QEMUFWVOL))
FIRMWAREVOLUMEPATH := $(PREFIXDEPS)/share/ovmf/$(QEMUFWVOL)
FIRMWAREVOLUMEPATH := $(PREFIXDEPS)/share/$(EDK2_NAME)/$(QEMUFWVOL)
endif
endif
@@ -729,7 +731,7 @@ USER_VARS += DEFVIRTIOFSCACHE
USER_VARS += DEFVIRTIOFSQUEUESIZE
USER_VARS += DEFVIRTIOFSEXTRAARGS
USER_VARS += DEFENABLEANNOTATIONS
USER_VARS += DEFENABLEANNOTATIONSTEE
USER_VARS += DEFENABLEANNOTATIONS_COCO
USER_VARS += DEFENABLEIOTHREADS
USER_VARS += DEFSECCOMPSANDBOXPARAM
USER_VARS += DEFENABLEVHOSTUSERSTORE

View File

@@ -55,7 +55,7 @@ rootfs_type=@DEFROOTFSTYPE@
# List of valid annotation names for the hypervisor
# Each member of the list is a regular expression, which is the base name
# of the annotation, e.g. "path" for io.katacontainers.config.hypervisor.path"
enable_annotations = @DEFENABLEANNOTATIONSTEE@
enable_annotations = @DEFENABLEANNOTATIONS_COCO@
# List of valid annotations values for the hypervisor
# Each member of the list is a path pattern as described by glob(3).

View File

@@ -62,8 +62,9 @@ valid_hypervisor_paths = @QEMUSNPVALIDHYPERVISORPATHS@
# SNP 'ID Block' and 'ID Authentication Information Structure'.
# If one of snp_id_block or snp_id_auth is specified, the other must be specified, too.
# Notice that the default SNP policy of QEMU (0x30000) is used by Kata, and the IDBlock
# must be generated with exactly this policy.
# Notice that the default SNP policy of QEMU (0x30000) is used by Kata, if not explicitly
# set via 'snp_guest_policy' option. The IDBlock contains the guest policy as field, and
# it must match the value from 'snp_guest_policy' or, if unset, the QEMU default policy.
#
# 96-byte, base64-encoded blob to provide the ID Block structure for the
# SNP_LAUNCH_FINISH command defined in the SEV-SNP firmware ABI (QEMU default: all-zero)
@@ -72,6 +73,13 @@ valid_hypervisor_paths = @QEMUSNPVALIDHYPERVISORPATHS@
# for the SNP_LAUNCH_FINISH command defined in the SEV-SNP firmware ABI (QEMU default: all-zero)
#snp_id_auth = ""
# SNP Guest Policy, the POLICY parameter to the SNP_LAUNCH_START command.
# If unset, the QEMU default policy (0x30000) will be used.
# Notice that the guest policy is enforced at VM launch, and your pod VMs
# won't start at all if the policy denys it. This will be indicated by a
# 'SNP_LAUNCH_START' error.
#snp_guest_policy = 196608
# Optional space-separated list of options to pass to the guest kernel.
# For example, use `kernel_params = "vsyscall=emulate"` if you are having
# trouble running pre-2.15 glibc.

View File

@@ -40,7 +40,7 @@ confidential_guest = true
# List of valid annotation names for the hypervisor
# Each member of the list is a regular expression, which is the base name
# of the annotation, e.g. "path" for io.katacontainers.config.hypervisor.path"
enable_annotations = @DEFENABLEANNOTATIONS@
enable_annotations = @DEFENABLEANNOTATIONS_COCO@
# List of valid annotations values for the hypervisor
# Each member of the list is a path pattern as described by glob(3).

View File

@@ -62,8 +62,9 @@ valid_hypervisor_paths = @QEMUVALIDHYPERVISORPATHS@
# SNP 'ID Block' and 'ID Authentication Information Structure'.
# If one of snp_id_block or snp_id_auth is specified, the other must be specified, too.
# Notice that the default SNP policy of QEMU (0x30000) is used by Kata, and the IDBlock
# must be generated with exactly this policy.
# Notice that the default SNP policy of QEMU (0x30000) is used by Kata, if not explicitly
# set via 'snp_guest_policy' option. The IDBlock contains the guest policy as field, and
# it must match the value from 'snp_guest_policy' or, if unset, the QEMU default policy.
#
# 96-byte, base64-encoded blob to provide the ID Block structure for the
# SNP_LAUNCH_FINISH command defined in the SEV-SNP firmware ABI (QEMU default: all-zero)
@@ -72,6 +73,13 @@ valid_hypervisor_paths = @QEMUVALIDHYPERVISORPATHS@
# for the SNP_LAUNCH_FINISH command defined in the SEV-SNP firmware ABI (QEMU default: all-zero)
#snp_id_auth = ""
# SNP Guest Policy, the POLICY parameter to the SNP_LAUNCH_START command.
# If unset, the QEMU default policy (0x30000) will be used.
# Notice that the guest policy is enforced at VM launch, and your pod VMs
# won't start at all if the policy denys it. This will be indicated by a
# 'SNP_LAUNCH_START' error.
#snp_guest_policy = 196608
# Optional space-separated list of options to pass to the guest kernel.
# For example, use `kernel_params = "vsyscall=emulate"` if you are having
# trouble running pre-2.15 glibc.

View File

@@ -49,7 +49,7 @@ confidential_guest = true
# List of valid annotation names for the hypervisor
# Each member of the list is a regular expression, which is the base name
# of the annotation, e.g. "path" for io.katacontainers.config.hypervisor.path"
enable_annotations = @DEFENABLEANNOTATIONSTEE@
enable_annotations = @DEFENABLEANNOTATIONS_COCO@
# List of valid annotations values for the hypervisor
# Each member of the list is a path pattern as described by glob(3).

View File

@@ -1,7 +1,7 @@
module github.com/kata-containers/kata-containers/src/runtime
// Keep in sync with version in versions.yaml
go 1.23.0
go 1.23.12
// WARNING: Do NOT use `replace` directives as those break dependabot:
// https://github.com/kata-containers/kata-containers/issues/11020

View File

@@ -330,6 +330,9 @@ type Object struct {
// for the SNP_LAUNCH_FINISH command defined in the SEV-SNP firmware ABI (default: all-zero)
SnpIdAuth string
// SnpGuestPolicy is the integer representation of the SEV-SNP guest policy.
SnpGuestPolicy *uint64
// Raw byte slice of initdata digest
InitdataDigest []byte
}
@@ -415,6 +418,9 @@ func (object Object) QemuParams(config *Config) []string {
if object.SnpIdAuth != "" {
objectParams = append(objectParams, fmt.Sprintf("id-auth=%s", object.SnpIdAuth))
}
if object.SnpGuestPolicy != nil {
objectParams = append(objectParams, fmt.Sprintf("policy=%d", *object.SnpGuestPolicy))
}
if len(object.InitdataDigest) > 0 {
// due to https://github.com/confidential-containers/qemu/blob/amd-snp-202402240000/qapi/qom.json#L926-L929
// hostdata in SEV-SNP should be exactly 32 bytes

View File

@@ -109,6 +109,7 @@ type hypervisor struct {
RemoteHypervisorSocket string `toml:"remote_hypervisor_socket"`
SnpIdBlock string `toml:"snp_id_block"`
SnpIdAuth string `toml:"snp_id_auth"`
SnpGuestPolicy *uint64 `toml:"snp_guest_policy"`
HypervisorPathList []string `toml:"valid_hypervisor_paths"`
JailerPathList []string `toml:"valid_jailer_paths"`
VirtioFSDaemonList []string `toml:"valid_virtio_fs_daemon_paths"`
@@ -992,6 +993,7 @@ func newQemuHypervisorConfig(h hypervisor) (vc.HypervisorConfig, error) {
ExtraMonitorSocket: extraMonitorSocket,
SnpIdBlock: h.SnpIdBlock,
SnpIdAuth: h.SnpIdAuth,
SnpGuestPolicy: h.SnpGuestPolicy,
}, nil
}

View File

@@ -885,6 +885,9 @@ func TestAddRuntimeAnnotations(t *testing.T) {
runtimeConfig := RuntimeConfig{
HypervisorType: vc.QemuHypervisor,
HypervisorConfig: vc.HypervisorConfig{
EnableAnnotations: []string{"cc_init_data"},
},
}
ocispec.Annotations[vcAnnotations.DisableGuestSeccomp] = "true"

View File

@@ -473,6 +473,9 @@ type HypervisorConfig struct {
// for the SNP_LAUNCH_FINISH command defined in the SEV-SNP firmware ABI (default: all-zero)
SnpIdAuth string
// SnpGuestPolicy is the integer representation of the SEV-SNP guest policy.
SnpGuestPolicy *uint64
// KernelParams are additional guest kernel parameters.
KernelParams []Param

View File

@@ -245,7 +245,7 @@ const (
EnableRootlessHypervisor = kataAnnotHypervisorPrefix + "rootless"
// Initdata is the initdata passed in when CreateVM
Initdata = kataConfAnnotationsPrefix + "runtime.cc_init_data"
Initdata = kataConfAnnotationsPrefix + "hypervisor.cc_init_data"
)
// Runtime related annotations

View File

@@ -397,23 +397,6 @@ func (q *qemu) createQmpSocket() ([]govmmQemu.QMPSocket, error) {
return sockets, nil
}
func (q *qemu) buildInitdataDevice(devices []govmmQemu.Device, InitdataImage string) []govmmQemu.Device {
device := govmmQemu.BlockDevice{
Driver: govmmQemu.VirtioBlock,
Transport: govmmQemu.TransportPCI,
ID: "initdata",
File: InitdataImage,
SCSI: false,
WCE: false,
AIO: govmmQemu.Threads,
Interface: "none",
Format: "raw",
}
devices = append(devices, device)
return devices
}
func (q *qemu) buildDevices(ctx context.Context, kernelPath string) ([]govmmQemu.Device, *govmmQemu.IOThread, *govmmQemu.Kernel, error) {
var devices []govmmQemu.Device
@@ -763,7 +746,7 @@ func (q *qemu) CreateVM(ctx context.Context, id string, network Network, hypervi
}
if len(hypervisorConfig.Initdata) > 0 {
devices = q.buildInitdataDevice(devices, hypervisorConfig.InitdataImage)
devices = q.arch.buildInitdataDevice(ctx, devices, hypervisorConfig.InitdataImage)
}
// some devices configuration may also change kernel params, make sure this is called afterwards

View File

@@ -38,6 +38,8 @@ type qemuAmd64 struct {
snpIdBlock string
snpIdAuth string
snpGuestPolicy *uint64
}
const (
@@ -126,11 +128,12 @@ func newQemuArch(config HypervisorConfig) (qemuArch, error) {
protection: noneProtection,
legacySerial: config.LegacySerial,
},
vmFactory: factory,
snpGuest: config.SevSnpGuest,
qgsPort: config.QgsPort,
snpIdBlock: config.SnpIdBlock,
snpIdAuth: config.SnpIdAuth,
vmFactory: factory,
snpGuest: config.SevSnpGuest,
qgsPort: config.QgsPort,
snpIdBlock: config.SnpIdBlock,
snpIdAuth: config.SnpIdAuth,
snpGuestPolicy: config.SnpGuestPolicy,
}
if config.ConfidentialGuest {
@@ -315,6 +318,7 @@ func (q *qemuAmd64) appendProtectionDevice(devices []govmmQemu.Device, firmware,
CBitPos: cpuid.AMDMemEncrypt.CBitPosition,
ReducedPhysBits: 1,
InitdataDigest: initdataDigest,
SnpGuestPolicy: q.snpGuestPolicy,
}
if q.snpIdBlock != "" && q.snpIdAuth != "" {
obj.SnpIdBlock = q.snpIdBlock

View File

@@ -176,6 +176,9 @@ type qemuArch interface {
// Query QMP to find the PCI slot of a device, given its QOM path or ID
qomGetSlot(qomPath string, qmpCh *qmpChannel) (types.PciSlot, error)
// buildInitdataDevice creates an initdata device for the given architecture.
buildInitdataDevice(ctx context.Context, devices []govmmQemu.Device, initdataImage string) []govmmQemu.Device
}
type qemuArchBase struct {
@@ -949,6 +952,24 @@ func (q *qemuArchBase) qomGetSlot(qomPath string, qmpCh *qmpChannel) (types.PciS
return types.PciSlotFromInt(slotNum)
}
// build initdata device
func (q *qemuArchBase) buildInitdataDevice(ctx context.Context, devices []govmmQemu.Device, initdataImage string) []govmmQemu.Device {
device := govmmQemu.BlockDevice{
Driver: govmmQemu.VirtioBlock,
Transport: govmmQemu.TransportPCI,
ID: "initdata",
File: initdataImage,
SCSI: false,
WCE: false,
AIO: govmmQemu.Threads,
Interface: "none",
Format: "raw",
}
devices = append(devices, device)
return devices
}
// Query QMP to find a device's PCI path given its QOM path or ID
func (q *qemuArchBase) qomGetPciPath(qemuID string, qmpCh *qmpChannel) (types.PciPath, error) {

View File

@@ -154,6 +154,11 @@ func (q *qemuArm64) enableProtection() error {
return nil
}
func (q *qemuArm64) buildInitdataDevice(ctx context.Context, devices []govmmQemu.Device, initdataImage string) []govmmQemu.Device {
hvLogger.Warnf("buildInitdataDevice not implemented for arm64; ignoring initdata image: %s", initdataImage)
return devices
}
func (q *qemuArm64) appendProtectionDevice(devices []govmmQemu.Device, firmware, firmwareVolume string, initdataDigest []byte) ([]govmmQemu.Device, string, error) {
err := q.enableProtection()
if err != nil {

View File

@@ -8,6 +8,7 @@
package virtcontainers
import (
"context"
"fmt"
"time"
@@ -156,6 +157,11 @@ func (q *qemuPPC64le) enableProtection() error {
}
}
func (q *qemuPPC64le) buildInitdataDevice(ctx context.Context, devices []govmmQemu.Device, initdataImage string) []govmmQemu.Device {
hvLogger.Warnf("buildInitdataDevice not implemented for PPC64le; ignoring initdata image: %s", initdataImage)
return devices
}
// append protection device
func (q *qemuPPC64le) appendProtectionDevice(devices []govmmQemu.Device, firmware, firmwareVolume string, initdataDigest []byte) ([]govmmQemu.Device, string, error) {
switch q.protection {

View File

@@ -349,8 +349,9 @@ func (q *qemuS390x) appendProtectionDevice(devices []govmmQemu.Device, firmware,
case seProtection:
return append(devices,
govmmQemu.Object{
Type: govmmQemu.SecExecGuest,
ID: secExecID,
Type: govmmQemu.SecExecGuest,
ID: secExecID,
InitdataDigest: initdataDigest,
}), firmware, nil
case noneProtection:
return devices, firmware, nil
@@ -382,6 +383,42 @@ func (q *qemuS390x) appendVFIODevice(devices []govmmQemu.Device, vfioDev config.
return devices
}
func (q *qemuS390x) buildInitdataDevice(ctx context.Context, devices []govmmQemu.Device, initdataImage string) []govmmQemu.Device {
var transport govmmQemu.VirtioTransport
var devNo string
transport = govmmQemu.TransportCCW
id := "initdata"
addr, bridge, err := q.addDeviceToBridge(ctx, id, types.CCW)
if err != nil {
hvLogger.WithError(err).Error("Failed to allocate CCW address for initdata")
return nil
}
devNo, err = bridge.AddressFormatCCW(addr)
if err != nil {
hvLogger.WithError(err).Error("Failed to format CCW address for initdata")
return nil
}
hvLogger.WithField("devno", devNo).Info("Using dynamic CCW DevNo for initdata")
device := govmmQemu.BlockDevice{
Driver: govmmQemu.VirtioBlock,
Transport: transport,
ID: id,
File: initdataImage,
SCSI: false,
WCE: false,
AIO: govmmQemu.Threads,
Interface: "none",
Format: "raw",
DevNo: devNo,
}
devices = append(devices, device)
return devices
}
// Query QMP to find a device's PCI path given its QOM path or ID
func (q *qemuS390x) qomGetPciPath(qemuID string, qmpCh *qmpChannel) (types.PciPath, error) {
hvLogger.Warnf("qomGetPciPath not implemented for s390x")

View File

@@ -144,14 +144,15 @@ func TestQemuS390xAppendProtectionDevice(t *testing.T) {
// Secure Execution protection
s390x.(*qemuS390x).protection = seProtection
devices, bios, err = s390x.appendProtectionDevice(devices, firmware, "", []byte(nil))
devices, bios, err = s390x.appendProtectionDevice(devices, firmware, "", []byte(""))
assert.NoError(err)
assert.Empty(bios)
expectedOut := []govmmQemu.Device{
govmmQemu.Object{
Type: govmmQemu.SecExecGuest,
ID: secExecID,
Type: govmmQemu.SecExecGuest,
ID: secExecID,
InitdataDigest: []byte(""),
},
}
assert.Equal(expectedOut, devices)

View File

@@ -1,7 +1,7 @@
module kata-containers/csi-kata-directvolume
// Keep in sync with version in versions.yaml
go 1.23.0
go 1.23.12
// WARNING: Do NOT use `replace` directives as those break dependabot:
// https://github.com/kata-containers/kata-containers/issues/11020

View File

@@ -347,6 +347,14 @@
"^127\\.(?:[0-9]{1,3}\\.){2}[0-9]{1,3}$"
]
},
"AddARPNeighborsRequest": {
"forbidden_device_names": [
"lo"
],
"forbidden_cidrs_regex": [
"^127\\.(?:[0-9]{1,3}\\.){2}[0-9]{1,3}$"
]
},
"CloseStdinRequest": false,
"ReadStreamRequest": false,
"UpdateEphemeralMountsRequest": false,

View File

@@ -1400,6 +1400,25 @@ UpdateInterfaceRequest if {
print("UpdateInterfaceRequest: true")
}
AddARPNeighborsRequest if {
p_defaults := policy_data.request_defaults.AddARPNeighborsRequest
print("AddARPNeighborsRequest: policy =", p_defaults)
every i_neigh in input.neighbors.ARPNeighbors {
print("AddARPNeighborsRequest: i_neigh =", i_neigh)
not i_neigh.device in p_defaults.forbidden_device_names
i_neigh.toIPAddress.mask == ""
every p_cidr in p_defaults.forbidden_cidrs_regex {
not regex.match(p_cidr, i_neigh.toIPAddress.address)
}
i_neigh.state == 128
bits.or(i_neigh.flags, 136) == 136
}
print("AddARPNeighborsRequest: true")
}
CloseStdinRequest if {
policy_data.request_defaults.CloseStdinRequest == true
}

View File

@@ -355,6 +355,16 @@ pub struct UpdateInterfaceRequestDefaults {
forbidden_hw_addrs: Vec<String>,
}
/// UpdateInterfaceRequest settings from genpolicy-settings.json.
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct AddARPNeighborsRequestDefaults {
/// Explicitly blocked interface names. Intent is to block changes to loopback interface.
forbidden_device_names: Vec<String>,
/// Explicitly blocked IP address ranges.
/// Should include loopback addresses and other CIDRs that should not be routed outside the VM.
forbidden_cidrs_regex: Vec<String>,
}
/// Settings specific to each kata agent endpoint, loaded from
/// genpolicy-settings.json.
#[derive(Clone, Debug, Serialize, Deserialize)]
@@ -374,6 +384,9 @@ pub struct RequestDefaults {
/// Allow the host to configure only used raw_flags and reject names/mac addresses of the loopback.
pub UpdateInterfaceRequest: UpdateInterfaceRequestDefaults,
/// Allow the host to configure only used raw_flags and reject names/mac addresses of the loopback.
pub AddARPNeighborsRequest: AddARPNeighborsRequestDefaults,
/// Allow the Host to close stdin for a container. Typically used with WriteStreamRequest.
pub CloseStdinRequest: bool,

View File

@@ -13,8 +13,8 @@ mod tests {
use std::str;
use protocols::agent::{
CopyFileRequest, CreateContainerRequest, CreateSandboxRequest, ExecProcessRequest,
RemoveContainerRequest, UpdateInterfaceRequest, UpdateRoutesRequest,
AddARPNeighborsRequest, CopyFileRequest, CreateContainerRequest, CreateSandboxRequest,
ExecProcessRequest, RemoveContainerRequest, UpdateInterfaceRequest, UpdateRoutesRequest,
};
use serde::{Deserialize, Serialize};
@@ -32,6 +32,7 @@ mod tests {
RemoveContainer(RemoveContainerRequest),
UpdateInterface(UpdateInterfaceRequest),
UpdateRoutes(UpdateRoutesRequest),
AddARPNeighbors(AddARPNeighborsRequest),
}
impl Display for TestRequest {
@@ -44,6 +45,7 @@ mod tests {
TestRequest::RemoveContainer(_) => write!(f, "RemoveContainerRequest"),
TestRequest::UpdateInterface(_) => write!(f, "UpdateInterfaceRequest"),
TestRequest::UpdateRoutes(_) => write!(f, "UpdateRoutesRequest"),
TestRequest::AddARPNeighbors(_) => write!(f, "AddARPNeighborsRequest"),
}
}
}
@@ -240,6 +242,11 @@ mod tests {
runtests("updateinterface").await;
}
#[tokio::test]
async fn test_add_arp_neighbors() {
runtests("addarpneighbors").await;
}
#[tokio::test]
async fn test_create_container_network_namespace() {
runtests("createcontainer/network_namespace").await;

View File

@@ -0,0 +1,9 @@
apiVersion: v1
kind: Pod
metadata:
name: dummy
spec:
runtimeClassName: kata-cc-isolation
containers:
- name: dummy
image: registry.k8s.io/pause:3.6@sha256:3d380ca8864549e74af4b29c10f9cb0956236dfb01c40ca076fb6c37253234db

View File

@@ -0,0 +1,156 @@
[
{
"description": "compliant neighbors",
"allowed": true,
"request": {
"type": "AddARPNeighbors",
"neighbors": {
"ARPNeighbors": [
{
"toIPAddress": {
"family": 0,
"address": "10.0.0.1",
"mask": ""
},
"device": "eth0",
"lladdr": "00:00:5e:00:53:01",
"state": 128,
"flags": 0
}
]
}
}
},
{
"description": "allowed flags: NTF_PROXY",
"allowed": true,
"request": {
"type": "AddARPNeighbors",
"neighbors": {
"ARPNeighbors": [
{
"toIPAddress": {
"family": 0,
"address": "10.0.0.1",
"mask": ""
},
"device": "eth0",
"lladdr": "00:00:5e:00:53:01",
"state": 128,
"flags": 8
}
]
}
}
},
{
"description": "allowed flags: NTF_ROUTER",
"allowed": true,
"request": {
"type": "AddARPNeighbors",
"neighbors": {
"ARPNeighbors": [
{
"toIPAddress": {
"family": 0,
"address": "10.0.0.1",
"mask": ""
},
"device": "eth0",
"lladdr": "00:00:5e:00:53:01",
"state": 128,
"flags": 128
}
]
}
}
},
{
"description": "bad interface",
"allowed": false,
"request": {
"type": "AddARPNeighbors",
"neighbors": {
"ARPNeighbors": [
{
"toIPAddress": {
"family": 0,
"address": "10.0.0.1",
"mask": ""
},
"device": "lo",
"lladdr": "00:00:5e:00:53:01",
"state": 128,
"flags": 0
}
]
}
}
},
{
"description": "bad IP",
"allowed": false,
"request": {
"type": "AddARPNeighbors",
"neighbors": {
"ARPNeighbors": [
{
"toIPAddress": {
"family": 0,
"address": "127.1.2.3",
"mask": ""
},
"device": "eth0",
"lladdr": "00:00:5e:00:53:01",
"state": 128,
"flags": 0
}
]
}
}
},
{
"description": "bad state",
"allowed": false,
"request": {
"type": "AddARPNeighbors",
"neighbors": {
"ARPNeighbors": [
{
"toIPAddress": {
"family": 0,
"address": "10.0.0.1",
"mask": ""
},
"device": "eth0",
"lladdr": "00:00:5e:00:53:01",
"state": 0,
"flags": 0
}
]
}
}
},
{
"description": "bad flags",
"allowed": false,
"request": {
"type": "AddARPNeighbors",
"neighbors": {
"ARPNeighbors": [
{
"toIPAddress": {
"family": 0,
"address": "10.0.0.1",
"mask": ""
},
"device": "eth0",
"lladdr": "00:00:5e:00:53:01",
"state": 128,
"flags": 5
}
]
}
}
}
]

View File

@@ -28,7 +28,7 @@ KATA_HYPERVISOR="${KATA_HYPERVISOR:-qemu}"
RUNTIME="${RUNTIME:-containerd-shim-kata-v2}"
export branch="${target_branch:-main}"
export branch="${target_branch:-"$(git remote show origin | sed -n '/HEAD branch/s/.*: //p')"}"
function die() {
local msg="$*"

View File

@@ -174,7 +174,7 @@ function create_coco_pod_yaml() {
# This function creates pod yaml. Parameters
# - $1: image reference
# - $2: annotation `io.katacontainers.config.hypervisor.kernel_params`
# - $3: anootation `io.katacontainers.config.runtime.cc_init_data`
# - $3: annotation `io.katacontainers.config.hypervisor.cc_init_data`
# - $4: node
function create_coco_pod_yaml_with_annotations() {
image=$1
@@ -183,7 +183,7 @@ function create_coco_pod_yaml_with_annotations() {
node=${4:-}
kernel_params_annotation_key="io.katacontainers.config.hypervisor.kernel_params"
cc_initdata_annotation_key="io.katacontainers.config.runtime.cc_init_data"
cc_initdata_annotation_key="io.katacontainers.config.hypervisor.cc_init_data"
# Note: this is not local as we use it in the caller test
kata_pod="$(new_pod_config "$image" "kata-${KATA_HYPERVISOR}")"

View File

@@ -10,7 +10,7 @@
# 3. Pull an image from a banned registry
# 4. Check if the pulling fails with log `image security validation failed`,
# the initdata works.
#
#
# Note that if initdata does not work, the pod still fails to launch (hang at
# CreatingContainer status). The error information is
# `[CDH] [ERROR]: Get Resource failed` which internally means that the KBS URL
@@ -35,7 +35,7 @@ setup() {
setup_common || die "setup_common failed"
FAIL_TEST_IMAGE="quay.io/prometheus/busybox:latest"
SECURITY_POLICY_KBS_URI="kbs:///default/security-policy/test"
}
@@ -45,13 +45,16 @@ function setup_kbs_image_policy_for_initdata() {
fi
export CURRENT_ARCH=$(uname -m)
if [ "${CURRENT_ARCH}" != "x86_64" ]; then
skip "Test skipped as only x86-64 supports, while current platform is ${CURRENT_ARCH}"
fi
case "${CURRENT_ARCH}" in
"x86_64"|"s390x")
;;
*)
skip "Test skipped as only x86-64 & s390x is supported, while current platform is ${CURRENT_ARCH}"
;;
esac
# TODO: Enable for more archs
case "$KATA_HYPERVISOR" in
"qemu-tdx"|"qemu-coco-dev"|"qemu-snp")
"qemu-tdx"|"qemu-coco-dev"|"qemu-snp"|"qemu-se")
;;
*)
skip "Test not supported for ${KATA_HYPERVISOR}."
@@ -88,7 +91,7 @@ EOF
@test "Test that creating a container from an rejected image configured by initdata, fails according to policy reject" {
setup_kbs_image_policy_for_initdata
CC_KBS_ADDRESS=$(kbs_k8s_svc_http_addr)
kernel_parameter="agent.image_policy_file=${SECURITY_POLICY_KBS_URI} agent.enable_signature_verification=true"
@@ -179,7 +182,7 @@ EOF
return 1
fi
assert_logs_contain "${node}" kata "${node_start_time}" "\[CDH\] \[ERROR\]: Get Resource failed"
assert_logs_contain "${node}" kata "${node_start_time}" "\[CDH\] \[ERROR\]: Image Client error: Initialize resource provider failed: Get resource failed"
}
teardown() {

View File

@@ -10,10 +10,13 @@ load "${BATS_TEST_DIRNAME}/../../common.bash"
# shellcheck disable=SC1091
load "${BATS_TEST_DIRNAME}/tests_common.sh"
RUNTIME_CLASS_NAME=${RUNTIME_CLASS_NAME:-kata-qemu-nvidia-gpu}
export RUNTIME_CLASS_NAME
export POD_NAME_INSTRUCT="nvidia-nim-llama-3-1-8b-instruct"
export POD_NAME_EMBEDQA="nvidia-nim-llama-3-2-nv-embedqa-1b-v2"
export POD_SECRET_INSTRUCT="ngc-secret-instruct"
export LOCAL_NIM_CACHE="/opt/nim/.cache"
DOCKER_CONFIG_JSON=$(
echo -n "{\"auths\":{\"nvcr.io\":{\"username\":\"\$oauthtoken\",\"password\":\"${NGC_API_KEY}\",\"auth\":\"$(echo -n "\$oauthtoken:${NGC_API_KEY}" | base64 -w0)\"}}}" |
@@ -21,6 +24,40 @@ DOCKER_CONFIG_JSON=$(
)
export DOCKER_CONFIG_JSON
setup_langchain_flow() {
# shellcheck disable=SC1091 # Sourcing virtual environment activation script
source "${HOME}"/.cicd/venv/bin/activate
pip install --upgrade pip
[[ "$(pip show langchain 2>/dev/null | awk '/^Version:/{print $2}')" = "0.2.5" ]] || pip install langchain==0.2.5
[[ "$(pip show langchain-nvidia-ai-endpoints 2>/dev/null | awk '/^Version:/{print $2}')" = "0.1.2" ]] || pip install langchain-nvidia-ai-endpoints==0.1.2
[[ "$(pip show faiss-gpu 2>/dev/null | awk '/^Version:/{print $2}')" = "1.7.2" ]] || pip install faiss-gpu==1.7.2
[[ "$(pip show langchain-community 2>/dev/null | awk '/^Version:/{print $2}')" = "0.2.5" ]] || pip install langchain-community==0.2.5
[[ "$(pip show beautifulsoup4 2>/dev/null | awk '/^Version:/{print $2}')" = "4.13.4" ]] || pip install beautifulsoup4==4.13.4
}
create_inference_embedqa_pods() {
kubectl apply -f "${POD_INSTRUCT_YAML}"
kubectl apply -f "${POD_EMBEDQA_YAML}"
kubectl wait --for=condition=Ready --timeout=500s pod "${POD_NAME_INSTRUCT}"
kubectl wait --for=condition=Ready --timeout=500s pod "${POD_NAME_EMBEDQA}"
# shellcheck disable=SC2030 # Variable is shared via file between BATS tests
POD_IP_INSTRUCT=$(kubectl get pod "${POD_NAME_INSTRUCT}" -o jsonpath='{.status.podIP}')
[[ -n "${POD_IP_INSTRUCT}" ]]
# shellcheck disable=SC2030 # Variable is shared via file between BATS tests
POD_IP_EMBEDQA=$(kubectl get pod "${POD_NAME_EMBEDQA}" -o jsonpath='{.status.podIP}')
[[ -n "${POD_IP_EMBEDQA}" ]]
echo "POD_IP_INSTRUCT=${POD_IP_INSTRUCT}" >"${BATS_SUITE_TMPDIR}/env"
echo "# POD_IP_INSTRUCT=${POD_IP_INSTRUCT}" >&3
echo "POD_IP_EMBEDQA=${POD_IP_EMBEDQA}" >>"${BATS_SUITE_TMPDIR}/env"
echo "# POD_IP_EMBEDQA=${POD_IP_EMBEDQA}" >&3
}
setup_file() {
dpkg -s jq >/dev/null 2>&1 || sudo apt -y install jq
@@ -28,6 +65,7 @@ setup_file() {
[[ -d ${PYENV_ROOT}/bin ]] && export PATH="${PYENV_ROOT}/bin:${PATH}"
eval "$(pyenv init - bash)"
# shellcheck disable=SC1091 # Virtual environment will be created during test execution
python3 -m venv "${HOME}"/.cicd/venv
get_pod_config_dir
@@ -35,20 +73,17 @@ setup_file() {
pod_instruct_yaml_in="${pod_config_dir}/${POD_NAME_INSTRUCT}.yaml.in"
pod_instruct_yaml="${pod_config_dir}/${POD_NAME_INSTRUCT}.yaml"
pod_embedqa_yaml_in="${pod_config_dir}/${POD_NAME_EMBEDQA}.yaml.in"
pod_embedqa_yaml="${pod_config_dir}/${POD_NAME_EMBEDQA}.yaml"
envsubst <"${pod_instruct_yaml_in}" >"${pod_instruct_yaml}"
envsubst <"${pod_embedqa_yaml_in}" >"${pod_embedqa_yaml}"
export POD_INSTRUCT_YAML="${pod_instruct_yaml}"
}
export POD_EMBEDQA_YAML="${pod_embedqa_yaml}"
@test "NVIDIA NIM Llama 3.1-8b Instruct" {
kubectl apply -f "${POD_INSTRUCT_YAML}"
kubectl wait --for=condition=Ready --timeout=500s pod "${POD_NAME_INSTRUCT}"
# shellcheck disable=SC2030 # Variable is shared via file between BATS tests
POD_IP_INSTRUCT=$(kubectl get pod "${POD_NAME_INSTRUCT}" -o jsonpath='{.status.podIP}')
[[ -n "${POD_IP_INSTRUCT}" ]]
echo "POD_IP_INSTRUCT=${POD_IP_INSTRUCT}" >"${BATS_SUITE_TMPDIR}/env"
echo "# POD_IP_INSTRUCT=${POD_IP_INSTRUCT}" >&3
setup_langchain_flow
create_inference_embedqa_pods
}
@test "List of models available for inference" {
@@ -64,10 +99,11 @@ setup_file() {
# shellcheck disable=SC2030 # Variable is shared via file between BATS tests
MODEL_NAME=$(echo "${output}" | jq '.data[0].id' | tr -d '"')
export MODEL_NAME
[[ -n "${MODEL_NAME}" ]]
echo "MODEL_NAME=${MODEL_NAME}" >>"${BATS_SUITE_TMPDIR}/env"
echo "# MODEL_NAME=${MODEL_NAME}" >&3
}
@test "Simple OpenAI completion request" {
@@ -94,6 +130,198 @@ setup_file() {
echo "# ANSWER: ${ANSWER}" >&3
}
@test "LangChain NVIDIA AI Endpoints" {
# shellcheck disable=SC1091 # File is created by previous test
source "${BATS_SUITE_TMPDIR}/env"
# shellcheck disable=SC2031 # Variables are shared via file between BATS tests
[[ -n "${POD_IP_INSTRUCT}" ]]
# shellcheck disable=SC2031 # Variables are shared via file between BATS tests
[[ -n "${MODEL_NAME}" ]]
QUESTION="What is the capital of France?"
ANSWER="The capital of France is Paris."
# shellcheck disable=SC1091 # Sourcing virtual environment activation script
source "${HOME}"/.cicd/venv/bin/activate
# shellcheck disable=SC2031 # Variables are used in heredoc, not subshell
cat <<EOF >"${HOME}"/.cicd/venv/langchain_nim.py
from langchain_nvidia_ai_endpoints import ChatNVIDIA
llm = ChatNVIDIA(base_url="http://${POD_IP_INSTRUCT}:8000/v1", model="${MODEL_NAME}", temperature=0.1, max_tokens=1000, top_p=1.0)
result = llm.invoke("${QUESTION}")
print(result.content)
EOF
run python3 "${HOME}"/.cicd/venv/langchain_nim.py
[[ "${status}" -eq 0 ]]
[[ "${output}" = "${ANSWER}" ]]
echo "# QUESTION: ${QUESTION}" >&3
echo "# ANSWER: ${ANSWER}" >&3
}
@test "Kata Documentation RAG" {
# shellcheck disable=SC1091 # File is created by previous test
source "${BATS_SUITE_TMPDIR}/env"
# shellcheck disable=SC2031 # Variables are shared via file between BATS tests
[[ -n "${POD_IP_EMBEDQA}" ]]
# shellcheck disable=SC2031 # Variables are shared via file between BATS tests
[[ -n "${POD_IP_INSTRUCT}" ]]
# shellcheck disable=SC1091 # Sourcing virtual environment activation script
source "${HOME}"/.cicd/venv/bin/activate
cat <<EOF >"${HOME}"/.cicd/venv/langchain_nim_kata_rag.py
import os
from langchain.chains import ConversationalRetrievalChain, LLMChain
from langchain.chains.conversational_retrieval.prompts import CONDENSE_QUESTION_PROMPT, QA_PROMPT
from langchain.chains.question_answering import load_qa_chain
from langchain.memory import ConversationBufferMemory
from langchain_community.vectorstores import FAISS
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain_nvidia_ai_endpoints import ChatNVIDIA
from langchain_nvidia_ai_endpoints import NVIDIAEmbeddings
EOF
# shellcheck disable=SC2129 # Multiple heredocs are intentional for building the Python script
cat <<EOF >>"${HOME}"/.cicd/venv/langchain_nim_kata_rag.py
import re
from typing import List, Union
import requests
from bs4 import BeautifulSoup
def html_document_loader(url: Union[str, bytes]) -> str:
try:
response = requests.get(url)
html_content = response.text
except Exception as e:
print(f"Failed to load {url} due to exception {e}")
return ""
try:
# Create a Beautiful Soup object to parse html
soup = BeautifulSoup(html_content, "html.parser")
# Remove script and style tags
for script in soup(["script", "style"]):
script.extract()
# Get the plain text from the HTML document
text = soup.get_text()
# Remove excess whitespace and newlines
text = re.sub("\s+", " ", text).strip()
return text
except Exception as e:
print(f"Exception {e} while loading document")
return ""
EOF
cat <<EOF >>"${HOME}"/.cicd/venv/langchain_nim_kata_rag.py
def create_embeddings(embedding_path: str = "./data/nv_embedding"):
embedding_path = "./data/nv_embedding"
print(f"Storing embeddings to {embedding_path}")
# List of web pages containing Kata technical documentation
urls = [
"https://github.com/kata-containers/kata-containers/releases",
]
documents = []
for url in urls:
document = html_document_loader(url)
documents.append(document)
text_splitter = RecursiveCharacterTextSplitter(
chunk_size=1000,
chunk_overlap=0,
length_function=len,
)
texts = text_splitter.create_documents(documents)
index_docs(url, text_splitter, texts, embedding_path)
print("Generated embedding successfully")
EOF
# shellcheck disable=SC2031 # POD_IP_EMBEDQA is shared via file between BATS tests
cat <<EOF >>"${HOME}"/.cicd/venv/langchain_nim_kata_rag.py
def index_docs(url: Union[str, bytes], splitter, documents: List[str], dest_embed_dir) -> None:
embeddings = NVIDIAEmbeddings(base_url="http://${POD_IP_EMBEDQA}:8000/v1", model="nvidia/llama-3.2-nv-embedqa-1b-v2")
for document in documents:
texts = splitter.split_text(document.page_content)
# metadata to attach to document
metadatas = [document.metadata]
# create embeddings and add to vector store
if os.path.exists(dest_embed_dir):
update = FAISS.load_local(folder_path=dest_embed_dir, embeddings=embeddings, allow_dangerous_deserialization=True)
update.add_texts(texts, metadatas=metadatas)
update.save_local(folder_path=dest_embed_dir)
else:
docsearch = FAISS.from_texts(texts, embedding=embeddings, metadatas=metadatas)
docsearch.save_local(folder_path=dest_embed_dir)
EOF
# shellcheck disable=SC2031 # POD_IP_EMBEDQA is shared via file between BATS tests
cat <<EOF >>"${HOME}"/.cicd/venv/langchain_nim_kata_rag.py
create_embeddings()
embedding_model = NVIDIAEmbeddings(base_url="http://${POD_IP_EMBEDQA}:8000/v1", model="nvidia/llama-3.2-nv-embedqa-1b-v2")
EOF
cat <<EOF >>"${HOME}"/.cicd/venv/langchain_nim_kata_rag.py
# Embed documents
embedding_path = "./data/nv_embedding"
docsearch = FAISS.load_local(folder_path=embedding_path, embeddings=embedding_model, allow_dangerous_deserialization=True)
EOF
# shellcheck disable=SC2031 # Variables are used in heredoc, not subshell
cat <<EOF >>"${HOME}"/.cicd/venv/langchain_nim_kata_rag.py
llm = ChatNVIDIA(base_url="http://${POD_IP_INSTRUCT}:8000/v1", model="meta/llama3-8b-instruct", temperature=0.1, max_tokens=1000, top_p=1.0)
memory = ConversationBufferMemory(memory_key="chat_history", return_messages=True)
qa_prompt=QA_PROMPT
doc_chain = load_qa_chain(llm, chain_type="stuff", prompt=QA_PROMPT)
qa = ConversationalRetrievalChain.from_llm(
llm=llm,
retriever=docsearch.as_retriever(),
chain_type="stuff",
memory=memory,
combine_docs_chain_kwargs={'prompt': qa_prompt},
)
EOF
QUESTION="What is the latest Kata Containers release?"
cat <<EOF >>"${HOME}"/.cicd/venv/langchain_nim_kata_rag.py
query = "${QUESTION}"
result = qa.invoke({"question": query})
print("#"+ result.get("answer"))
EOF
run python3 "${HOME}"/.cicd/venv/langchain_nim_kata_rag.py
[[ "${status}" -eq 0 ]]
ANSWER=$(echo "${output}" | cut -d '#' -f2)
[[ -n "${ANSWER}" ]]
echo "# QUESTION: ${QUESTION}" >&3
echo "# ANSWER: ${ANSWER}" >&3
}
teardown_file() {
kubectl delete -f "${POD_INSTRUCT_YAML}"
}

View File

@@ -1,4 +1,3 @@
# Copyright (c) 2025 NVIDIA Corporation
#
# SPDX-License-Identifier: Apache-2.0
@@ -20,7 +19,7 @@ metadata:
app: ${POD_NAME_INSTRUCT}
spec:
restartPolicy: Never
runtimeClassName: kata-qemu-nvidia-gpu
runtimeClassName: "${RUNTIME_CLASS_NAME}"
imagePullSecrets:
- name: ngc-secret-instruct
securityContext:
@@ -84,6 +83,6 @@ spec:
volumes:
- name: nim-cache
hostPath:
path: "/opr/nim/.cache"
path: "${LOCAL_NIM_CACHE}"
type: DirectoryOrCreate

View File

@@ -7,7 +7,6 @@ apiVersion: v1
kind: Secret
metadata:
name: ngc-secret-embedqa
namespace: nim-embedqa
type: kubernetes.io/dockerconfigjson
data:
.dockerconfigjson: ${DOCKER_CONFIG_JSON}
@@ -16,7 +15,6 @@ apiVersion: v1
kind: Pod
metadata:
name: nvidia-nim-llama-3-2-nv-embedqa-1b-v2
namespace: nim-embedqa
labels:
app: nvidia-nim-llama-3-2-nv-embedqa-1b-v2
spec:
@@ -91,5 +89,5 @@ spec:
volumes:
- name: nim-cache
hostPath:
path: "/opr/nim/.cache"
path: "${LOCAL_NIM_CACHE}"
type: DirectoryOrCreate

View File

@@ -15,10 +15,10 @@ type: application
# This is the chart version. This version number should be incremented each time you make changes
# to the chart and its templates, including the app version.
# Versions are expected to follow Semantic Versioning (https://semver.org/)
version: "3.19.1"
version: "3.20.0"
# This is the version number of the application being deployed. This version number should be
# incremented each time you make changes to the application. Versions are not expected to
# follow Semantic Versioning. They should reflect the version the application is using.
# It is recommended to use it with quotes.
appVersion: "3.19.1"
appVersion: "3.20.0"

View File

@@ -343,6 +343,20 @@ get_latest_kernel_confidential_artefact_and_builder_image_version() {
echo "${latest_kernel_artefact}-${latest_kernel_builder_image}"
}
get_latest_kernel_artefact_and_builder_image_version() {
local kernel_version
local kernel_kata_config_version
local latest_kernel_artefact
local latest_kernel_builder_image
kernel_version=$(get_from_kata_deps ".assets.kernel.version")
kernel_kata_config_version="$(cat "${repo_root_dir}"/tools/packaging/kernel/kata_config_version)"
latest_kernel_artefact="${kernel_version}-${kernel_kata_config_version}-$(get_last_modification "$(dirname "${kernel_builder}")")"
latest_kernel_builder_image="$(get_kernel_image_name)"
echo "${latest_kernel_artefact}-${latest_kernel_builder_image}"
}
#Install guest image
install_image() {
local variant="${1:-}"
@@ -370,7 +384,7 @@ install_image() {
latest_artefact="$(get_kata_version)-${os_name}-${os_version}-${osbuilder_last_commit}-${guest_image_last_commit}-${agent_last_commit}-${libs_last_commit}-${gperf_version}-${libseccomp_version}-${rust_version}-${image_type}"
if [ "${variant}" == "confidential" ]; then
if [[ "${variant}" == *confidential ]]; then
# For the confidential image we depend on the kernel built in order to ensure that
# measured boot is used
latest_artefact+="-$(get_latest_kernel_confidential_artefact_and_builder_image_version)"
@@ -378,6 +392,11 @@ install_image() {
latest_artefact+="-$(get_latest_pause_image_artefact_and_builder_image_version)"
fi
if [[ "${variant}" == "nvidia-gpu" ]]; then
# If we bump the kernel we need to rebuild the image
latest_artefact+="-$(get_latest_kernel_artefact_and_builder_image_version "${variant}")"
fi
latest_builder_image=""
install_cached_tarball_component \
@@ -465,7 +484,7 @@ install_initrd() {
"$(get_last_modification "${repo_root_dir}/tools/packaging/static-build/agent")")
latest_artefact="$(get_kata_version)-${os_name}-${os_version}-${osbuilder_last_commit}-${guest_image_last_commit}-${agent_last_commit}-${libs_last_commit}-${gperf_version}-${libseccomp_version}-${rust_version}-${initrd_type}"
if [ "${variant}" == "confidential" ]; then
if [[ "${variant}" == *confidential ]]; then
# For the confidential initrd we depend on the kernel built in order to ensure that
# measured boot is used
latest_artefact+="-$(get_latest_kernel_confidential_artefact_and_builder_image_version)"
@@ -473,6 +492,11 @@ install_initrd() {
latest_artefact+="-$(get_latest_pause_image_artefact_and_builder_image_version)"
fi
if [[ "${variant}" == "nvidia-gpu" ]]; then
# If we bump the kernel we need to rebuild the initrd as well
latest_artefact+="-$(get_latest_kernel_artefact_and_builder_image_version "${variant}")"
fi
latest_builder_image=""
[[ "${ARCH}" == "aarch64" && "${CROSS_BUILD}" == "true" ]] && echo "warning: Don't cross build initrd for aarch64 as it's too slow" && exit 0

View File

@@ -12,7 +12,6 @@ CONFIG_CRYPTO_MANAGER=y
CONFIG_CRYPTO_MANAGER2=y
CONFIG_CRYPTO_USER=y
CONFIG_CRYPTO_NULL=y
CONFIG_CRYPTO_NULL2=y
CONFIG_CRYPTO_CRYPTD=y
CONFIG_CRYPTO_AUTHENC=y
CONFIG_CRYPTO_CBC=y

View File

@@ -9,3 +9,6 @@ CONFIG_PCIEPORTBUS=y
# Define hotplugs to be online immediately. Speeds things up, and makes things
# work smoother on some arch's.
CONFIG_MEMORY_HOTPLUG_DEFAULT_ONLINE=y
# Linux v6.14+ dropped MEMORY_HOTPLUG_DEFAULT_ONLINE. The equivalent is:
CONFIG_MHP_DEFAULT_ONLINE_TYPE_ONLINE_AUTO=y

View File

@@ -0,0 +1,7 @@
# To keep CRYPTO_FIPS enabled, the following dependencies
# are needed. This is done for confidential guest build
# target only since it's needed by v6.16+ kernels. Move
# to a common fragment once non-confidential guest kernels
# follow.
CONFIG_CRYPTO_SELFTESTS=y
CONFIG_EXPERT=y

View File

@@ -39,3 +39,6 @@ CONFIG_MITIGATION_PAGE_TABLE_ISOLATION
CONFIG_VFIO_AP
CONFIG_VFIO_MDEV
CONFIG_BLK_DEV_WRITE_MOUNTED
CONFIG_MEMORY_HOTPLUG_DEFAULT_ONLINE
CONFIG_MHP_DEFAULT_ONLINE_TYPE_ONLINE_AUTO
CONFIG_CRYPTO_CRC32_S390

View File

@@ -0,0 +1,7 @@
# To keep CRYPTO_FIPS enabled, the following dependencies
# are needed. This is done for confidential guest build
# target only since it's needed by v6.16+ kernels. Move
# to a common fragment once non-confidential guest kernels
# follow.
CONFIG_CRYPTO_SELFTESTS=y
CONFIG_EXPERT=y

View File

@@ -1,3 +1,2 @@
# x86 cryptographic instructions to improve AES encryption and SHA256 hashing.
CONFIG_CRYPTO_SHA256_SSSE3=y
CONFIG_CRYPTO_AES_NI_INTEL=y

View File

@@ -7,6 +7,5 @@ CONFIG_INTEL_TDX_GUEST=y
CONFIG_OF=y
CONFIG_TDX_GUEST_DRIVER=y
CONFIG_VIRT_DRIVERS=y
CONFIG_X86_5LEVEL=y
CONFIG_X86_INTEL_MEMORY_PROTECTION_KEYS=y
CONFIG_X86_PLATFORM_DEVICES=y

View File

@@ -1 +1 @@
160
162

View File

@@ -20,11 +20,13 @@ RUN apt-get update && \
git \
iptables \
kmod \
libdw-dev \
libelf-dev \
libssl-dev \
gettext \
rsync \
cpio \
patch && \
patch \
python3 && \
if [ "${ARCH}" != "$(uname -m)" ]; then apt-get install --no-install-recommends -y gcc-"${ARCH}"-linux-gnu binutils-"${ARCH}"-linux-gnu; fi && \
apt-get clean && apt-get autoclean && rm -rf /var/lib/apt/lists/*

View File

@@ -84,7 +84,11 @@ fi
popd
info "Install fd to destdir"
install_dir="${DESTDIR}/${PREFIX}/share/ovmf"
if [ "${ovmf_build}" == "arm64" ]; then
install_dir="${DESTDIR}/${PREFIX}/share/aavmf"
else
install_dir="${DESTDIR}/${PREFIX}/share/ovmf"
fi
mkdir -p "${install_dir}"
if [ "${ovmf_build}" == "sev" ]; then

View File

@@ -101,6 +101,7 @@ mapping:
- Kata Containers CI / kata-containers-ci-on-push / run-kata-deploy-tests / run-kata-deploy-tests (qemu, microk8s)
- Kata Containers CI / kata-containers-ci-on-push / run-kata-deploy-tests / run-kata-deploy-tests (qemu, rke2)
- Kata Containers CI / kata-containers-ci-on-push / run-kata-monitor-tests / run-monitor (qemu, crio)
- Kata Containers CI / kata-containers-ci-on-push / run-k8s-tests-on-nvidia-gpu / run-nvidia-gpu-tests-on-amd64 (qemu-nvidia-gpu, kubeadm)
required-labels:
- ok-to-test
build:
@@ -135,6 +136,7 @@ mapping:
- Static checks / build-checks / check (make check, dragonball, src/dragonball, rust)
- Static checks / build-checks / check (make check, genpolicy, src/tools/genpolicy, rust, protobuf-compiler)
- Static checks / build-checks / check (make check, kata-ctl, src/tools/kata-ctl, rust)
- Static checks / build-checks / check (make check, libs, src/libs, rust)
- Static checks / build-checks / check (make check, runtime-rs, src/runtime-rs, rust)
- Static checks / build-checks / check (make check, runtime, src/runtime, golang, XDG_RUNTIME_DIR)
- Static checks / build-checks / check (make check, trace-forwarder, src/tools/trace-forwarder, rust)
@@ -143,6 +145,7 @@ mapping:
- Static checks / build-checks / check (make test, dragonball, src/dragonball, rust)
- Static checks / build-checks / check (make test, genpolicy, src/tools/genpolicy, rust, protobuf-compiler)
- Static checks / build-checks / check (make test, kata-ctl, src/tools/kata-ctl, rust)
- Static checks / build-checks / check (make test, libs, src/libs, rust)
- Static checks / build-checks / check (make test, runtime-rs, src/runtime-rs, rust)
- Static checks / build-checks / check (make test, runtime, src/runtime, golang, XDG_RUNTIME_DIR)
- Static checks / build-checks / check (make test, trace-forwarder, src/tools/trace-forwarder, rust)
@@ -159,6 +162,7 @@ mapping:
- Static checks / build-checks / check (sudo -E PATH="$PATH" make test, dragonball, src/dragonball, rust)
- Static checks / build-checks / check (sudo -E PATH="$PATH" make test, genpolicy, src/tools/genpolicy, rust, protobuf-compiler)
- Static checks / build-checks / check (sudo -E PATH="$PATH" make test, kata-ctl, src/tools/kata-ctl, rust)
- Static checks / build-checks / check (sudo -E PATH="$PATH" make test, libs, src/libs, rust)
- Static checks / build-checks / check (sudo -E PATH="$PATH" make test, runtime-rs, src/runtime-rs, rust)
- Static checks / build-checks / check (sudo -E PATH="$PATH" make test, runtime, src/runtime, golang, XDG_RUNTIME_DIR)
- Static checks / build-checks / check (sudo -E PATH="$PATH" make test, trace-forwarder, src/tools/trace-forwarder, rust)

View File

@@ -1,7 +1,7 @@
module module-path
// Keep in sync with version in versions.yaml
go 1.23.0
go 1.23.12
require (
github.com/sirupsen/logrus v1.9.3

View File

@@ -196,11 +196,11 @@ assets:
kernel:
description: "Linux kernel optimised for virtual machines"
url: "https://cdn.kernel.org/pub/linux/kernel/v6.x/"
version: "v6.12.36"
version: "v6.12.42"
confidential:
description: "Linux kernel with x86_64 TEEs (SNP and TDX) support"
url: "https://cdn.kernel.org/pub/linux/kernel/v6.x/"
version: "v6.12.36"
version: "v6.16.1"
kernel-arm-experimental:
description: "Linux kernel with cpu/mem hotplug support on arm64"
@@ -210,7 +210,7 @@ assets:
kernel-dragonball-experimental:
description: "Linux kernel with Dragonball VMM optimizations like upcall"
url: "https://cdn.kernel.org/pub/linux/kernel/v6.x/"
version: "v6.12.36"
version: "v6.12.42"
externals:
description: "Third-party projects used by the system"
@@ -415,12 +415,13 @@ languages:
golang:
description: "Google's 'go' language"
notes: "'version' is the default minimum version used by this project."
version: "1.23.10"
# When updating this, also update in go.mod files.
version: "1.23.12"
meta:
description: |
'newest-version' is the latest version known to work when
building Kata
newest-version: "1.23.10"
newest-version: "1.23.12"
rust:
description: "Rust language"