Skip to content

Add kani in ci + kani proof for conformance to 2.7.7.2 section #338

New issue

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

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

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: main
Choose a base branch
from

Conversation

priyasiddharth
Copy link

@priyasiddharth priyasiddharth commented Jun 3, 2025

Enable Kani in the CI and add the verify_spec_2_7_7_2() proof to verify that the implementation of queue satisfies 2.7.7.2 requirement. The proof relies on whether the EVENT_IDX feature has been negotiated. Conversely with test_needs_notification() test, this proof tests for all possible values of the queue structure.

Summary of the PR

This is review-ready version of #324 and #339.
First, we add Kani to the CI pipeline with a timeout of 20 minutes. The timeout is essential because Kani converts a rust program to a SAT problem which is NP-complete and may not return in a reasonable time.

Second, we add a kani proof to meet the requirements outlined in 2.7.7.2 of the virtio specification regarding the notification suppression mechanism. We have sketched this proof from the same proof defined for the queue implemented in firecraker. This commit adds the verify_spec_2_7_7_2() proof to verify that the implementation of queue meets 2.7.7.2 requirement. The proof relies on whether the EVENT_IDX feature has been negotiated. Conversely with test_needs_notification() test, this proof tests for all possible values of queue. To run the proof, you can run:

cargo kani

The proof currently passes with kani v0.62.0:

SUMMARY:
 ** 0 of 4880 failed (379 unreachable)

 ** 1 of 1 cover properties satisfied


VERIFICATION:- SUCCESSFUL
Verification Time: 82.47572s

Manual Harness Summary:
Complete - 1 successfully verified harnesses, 0 failures, 1 total.

Requirements

Before submitting your PR, please make sure you addressed the following
requirements:

  • All commits in this PR have Signed-Off-By trailers (with
    git commit -s), and the commit message has max 60 characters for the
    summary and max 75 characters for each description line.
  • All added/changed functionality has a corresponding unit/integration
    test.
  • All added/changed public-facing functionality has entries in the "Upcoming
    Release" section of CHANGELOG.md (if no such section exists, please create one).
  • Any newly added unsafe code is properly documented.

@stefano-garzarella
Copy link
Member

@priyasiddharth thanks for this PR. IIUC you are re-working a patch initially developed from @MatiasVara, so I think you should add also your S-o-b in the patch.

@priyasiddharth
Copy link
Author

Thank you @stefano-garzarella for the taking on the review. I have added a sign-off tag.

@priyasiddharth priyasiddharth force-pushed the main branch 2 times, most recently from f915258 to 6ac82d5 Compare June 10, 2025 14:33
@priyasiddharth
Copy link
Author

@stefano-garzarella PTAL

@stefano-garzarella
Copy link
Member

@priyasiddharth please mention big changes (e.g. you included patch from #339) and the reason after a push. I think that should also be mentioned in the PR description/title.

Also we usually squash new changes in commit, so all the "fix(comment)..." commit, should be squashed in the first commit (you can remove my Co-authored-by, it was just a suggestion while reviewing. As a general rule, a commit in a PR should not change/fix code added in the same PR.

Maybe we can also change the order of the patches, first enable the CI, then add the first test.

Run kani as a part of the CI pipeline. In particular, run the proofs for
virtio-queue. In some cases, kani may not finish so set a twenty minutes
timeout.

Signed-off-by: Matias Ezequiel Vara Larsen <mvaralar@redhat.com>
Signed-off-by: Siddharth Priya <s2priya@uwaterloo.ca>
@priyasiddharth
Copy link
Author

priyasiddharth commented Jun 13, 2025

@priyasiddharth please mention big changes (e.g. you included patch from #339) and the reason after a push. I think that should also be mentioned in the PR description/title.

Also we usually squash new changes in commit, so all the "fix(comment)..." commit, should be squashed in the first commit (you can remove my Co-authored-by, it was just a suggestion while reviewing. As a general rule, a commit in a PR should not change/fix code added in the same PR.

  • squashed changes
  • Followed rule

Maybe we can also change the order of the patches, first enable the CI, then add the first test.

@priyasiddharth priyasiddharth changed the title Add proof for conformance to 2.7.7.2 section Add kani in ci + kani proof for conformance to 2.7.7.2 section Jun 13, 2025
Copy link
Member

@stefano-garzarella stefano-garzarella left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, just very minimal comments! Thanks!

Copy link
Member

@stefano-garzarella stefano-garzarella left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM for the project POV, but I have no experience with kani, so I cced @roypat that may have comments on the direction!

"test_name": "prove-virtio-queue",
"command": "cargo kani --package virtio-queue",
"platform": ["x86_64", "aarch64"],
"timeout_in_minutes": 20
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: currently it finishes in just 2 minutes, so maybe we can leave the default timeout for now?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would prefer to let this be in this PR and change once this goes in.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It makes more sense to only have override the timeout if it's needed, I agree with @roypat

@priyasiddharth
Copy link
Author

@roypat PTAL

@stefano-garzarella
Copy link
Member

@alexandruag @andreeaflorescu @jiangliu @slp @stsquad @epilys any thought on this?

Comment on lines 505 to 507
#[kani::unwind(0)] // There are no loops anywhere, but kani really enjoys getting stuck in std::ptr::drop_in_place.
// This is a compiler intrinsic that has a "dummy" implementation in stdlib that just
// recursively calls itself. Kani will generally unwind this recursion infinitely
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
#[kani::unwind(0)] // There are no loops anywhere, but kani really enjoys getting stuck in std::ptr::drop_in_place.
// This is a compiler intrinsic that has a "dummy" implementation in stdlib that just
// recursively calls itself. Kani will generally unwind this recursion infinitely
// There are no loops anywhere, but kani really enjoys getting stuck in std::ptr::drop_in_place.
// This is a compiler intrinsic that has a "dummy" implementation in stdlib that just
// recursively calls itself. Kani will generally unwind this recursion infinitely
#[kani::unwind(0)]

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

@@ -269,6 +269,284 @@ impl Queue {
}
}

#[cfg(kani)]
#[allow(dead_code)]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we need this allow(dead_code)?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

removed

@@ -269,6 +269,284 @@ impl Queue {
}
}

#[cfg(kani)]
#[allow(dead_code)]
mod verification {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So far we've been keeping the tests related modules at the end of files. We shouldn't interleave this code with the functionality of the queue.

Is there anything stopping us from having a separate file for the kani related tests and functionality? It looks like it's adding quite a lot of code to a file that's already pretty large.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Currently the unit proofs rely on internal queue state like queue.num_added and internal predicates likeneeds_notification.
IIUC either these need to made public piecewise or the whole module needs to be made public.

/// speeds up all queue proofs, because it eliminates the only loop contained herein,
/// meaning we can use `kani::unwind(0)` instead of `kani::unwind(2)`. Functionally,
/// it works identically to `GuestMemoryMmap` with only a single contained region.
pub struct ProofGuestMemory {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: might be better to name this for what it does instead of what it is used for as we might end up needing different kinds of "GuestMemory" for other proofs.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

}
}

pub struct ProofContext(pub Queue, pub ProofGuestMemory);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you make these named fields instead? We've been using tuples like these when it's obvious what the tuple items represent (i.e. a Point(x, y)).

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

}
}

// can't implement kani::Arbitrary for the relevant types due to orphan rules
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the "orhphan" here the kani vector that provides the baking memory for GuestMemory? If yes, could we have the baking memory part of the ProofGuestMemory and implement any on that?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

Add the verify_spec_2_7_7_2() proof to verify that the implementation of
queue satisfies 2.7.7.2 requirement. The proof relies on whether the
EVENT_IDX feature has been negotiated. Conversely with
`test_needs_notification()` test, this proof `tests` for all possible
values of the queue structure.

Signed-off-by: Matias Ezequiel Vara Larsen <mvaralar@redhat.com>
Signed-off-by: Siddharth Priya <s2priya@uwaterloo.ca>
@priyasiddharth
Copy link
Author

@andreeaflorescu @epilys PTAL

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants