Bug 2040610
| Summary: | the libnbd OCaml bindings map C's "uint32_t" type to OCaml's "int32" type | ||
|---|---|---|---|
| Product: | Red Hat Enterprise Linux 9 | Reporter: | Laszlo Ersek <lersek> |
| Component: | libnbd | Assignee: | Laszlo Ersek <lersek> |
| Status: | CLOSED ERRATA | QA Contact: | Vera <vwu> |
| Severity: | unspecified | Docs Contact: | |
| Priority: | unspecified | ||
| Version: | 9.0 | CC: | eblake, lersek, mxie, rjones, tyan, tzheng, virt-maint, vwu, xiaodwan |
| Target Milestone: | rc | Keywords: | Triaged |
| Target Release: | --- | Flags: | pm-rhel:
mirror+
|
| Hardware: | Unspecified | ||
| OS: | Unspecified | ||
| Whiteboard: | |||
| Fixed In Version: | libnbd-1.10.3-1.el9 | Doc Type: | If docs needed, set a value |
| Doc Text: | Story Points: | --- | |
| Clone Of: | Environment: | ||
| Last Closed: | 2022-05-17 12:51:02 UTC | Type: | Bug |
| Regression: | --- | Mount Type: | --- |
| Documentation: | --- | CRM: | |
| Verified Versions: | Category: | --- | |
| oVirt Team: | --- | RHEL 7.3 requirements from Atomic Host: | |
| Cloudforms Team: | --- | Target Upstream Version: | |
| Embargoed: | |||
| Bug Depends On: | |||
| Bug Blocks: | 2027598 | ||
|
Description
Laszlo Ersek
2022-01-14 08:46:57 UTC
*** Bug 2040609 has been marked as a duplicate of this bug. *** (Adding Eric as heads up because I think he has a patch series which will conflict with changes in this area) > (2) The same issue exists for C's uint64_t <-> OCaml's int64 -- this is in fact a bug (or limitation) in OCaml's type system. We can't do anything about that, at the moment, as there is no OCaml type we could widen uint64_t to. (At least we can widen C's uint32_t to OCaml's int64.)
NBD offsets are always [0..0x7fff_ffff_ffff_ffff] so we're probably OK in most
practical cases.
I've got a patch for fixing the problem with the conversion between OCaml's "int32" type and C's "uint32_t".
Additionally, I've mostly reviewed the existing mappings, between OCaml's (signed-only) int* types, and the various unsigned types of C (represented by SizeT, UInt, UIntPtr, UInt64; and in the reverse direction, RSizeT, RUInt, RSizeT, ...) in "generator/OCaml.ml". I can see many-many problems; catching all out-of-range errors is a Herculean task.
In trying to come up with some range checks, I wanted to see what the *actual* range of the OCaml "int" type was. Turns out that on a 64-bit platform, it has *62* value bits, where
- the LSB determines whether the thing is an OCaml "block", or an "unboxed integer",
- then we have 62 value bits,
- and the MSB is the sign bit.
Now here's my problem:
$ ocaml
OCaml version 4.12.0
# let x = 4611686018427387903;;
val x : int = 4611686018427387903
# let x = 4611686018427387904;;
val x : int = -4611686018427387904
The first definition creates "x" with value 0x3FFF_FFFF_FFFF_FFFF; that is, with the 62 value bits set, and the sign bit clear. The type that OCaml infers from the constant is "int". All good.
The second definition redefines "x" (in a narrower scope) with value 0x4000_0000_0000_0000, with the 62 value bits clear, and *attempting* to set "value bit #62" (that is, attempting to set the "63rd value bit") -- which does not exist. Unfortunately, instead of producing an exception *or* inferring a type other than "int", OCaml silently sets the sign bit, permitting "x" (of type "int") to wrap to negative. :/
Given this (i.e., that the "int" type can be overflowed in *purely OCaml* code, before it reaches the libnbd bindings, and is converted to a particular C-language type), I don't think I can do anything at all in the libnbd bindings to catch overflows and underflows.
We shouldn't be using OCaml "int" type for storing any 64 bit numbers, that's a mistake if it happens. On 32 bit platforms it's 31 bits (signed). However with a quick look at the bindings it seems we map signed and unsigned Int64 / UInt64 to OCaml "int64". This is boxed and has a full range of 64 bits (signed). It's technically wrong to store a uint64_t in this type, but we can probably get away with it if it's an NBD offset since those are limited to [0..7fff_ffff_ffff_ffff] There is, sadly, no overflow checking ... About unsigned integers see also: https://discuss.ocaml.org/t/unsigned-integers/9145 https://github.com/ocaml/ocaml/pull/1201 (In reply to Richard W.M. Jones from comment #5) > However with a quick look at the bindings it seems we map signed and > unsigned Int64 / UInt64 to OCaml "int64". So I realised what I should have been looking at are the UInt32 mapping. That is mapped to OCaml int32, which is definitely wrong. Luckily it doesn't affect very many APIs, just these ones (and here I'm only talking about the OCaml bindings, the underlying APIs are fine): - connect_vsock - aio_connect_vsock - block_status # this bug - aio_block_status # [Libguestfs] [libnbd PATCH] ocaml: map C's uint32_t to OCaml's int64 https://listman.redhat.com/archives/libguestfs/2022-January/msg00093.html Message-Id: <20220114133833.24835-1-lersek> (In reply to Laszlo Ersek from comment #8) > [Libguestfs] [libnbd PATCH] ocaml: map C's uint32_t to OCaml's int64 > https://listman.redhat.com/archives/libguestfs/2022-January/msg00093.html > Message-Id: <20220114133833.24835-1-lersek> Upstream commit 0e714a6e06e6. Temporarily adding Verified:Tested to move this to a compose so I can build virt-v2v against it. Verified with the versions: libnbd-1.10.3-1.el9.x86_64 virt-v2v-1.45.97-2.el9.x86_64 qemu-img-6.2.0-4.el9.x86_64 libvirt-libs-8.0.0-1.el9.x86_64 guestfs-tools-1.46.1-6.el9.x86_64 nbdkit-1.28.4-2.el9.x86_64 rhv 4.4.10.2-0.1.el8ev Steps: 1.Convert a guest from VMware to rhv4.4 via -o rhv by v2v # virt-v2v -ic vpx://root.73.141/data/10.73.75.219/?no_verify=1 -it vddk -io vddk-libdir=/root/vddk_libdir/latest -io vddk-thumbprint=1F:97:34:5F:B6:C2:BA:66:46:CB:1A:71:76:7D:6B:50:1E:03:00:EA -ip /v2v-ops/esxpw -o rhv -os 10.73.195.48:/home/nfs_export -b ovirtmgmt esx6.7-rhel8.4-x86_64 [ 0.0] Setting up the source: -i libvirt -ic vpx://root.73.141/data/10.73.75.219/?no_verify=1 -it vddk esx6.7-rhel8.4-x86_64 [ 1.9] Opening the source [ 9.5] Inspecting the source [ 18.4] Checking for sufficient free disk space in the guest [ 18.4] Converting Red Hat Enterprise Linux 8.4 (Ootpa) to run on KVM virt-v2v: This guest has virtio drivers installed. [ 67.2] Mapping filesystem data to avoid copying unused and blank areas [ 68.6] Closing the overlay [ 68.9] Assigning disks to buses [ 68.9] Checking if the guest needs BIOS or UEFI to boot [ 68.9] Setting up the destination: -o rhv [ 71.1] Copying disk 1/1 █ 100% [****************************************] [ 364.5] Creating output metadata [ 373.8] Finishing off 2. Check if the guest is in "Storage--> Storage Domains--->nfs_export --> VM Import" on rhv4.4 after conversion 3. Import the guest and check the stauts on rhv4.4 Moving to Verified. Since the problem described in this bug report should be resolved in a recent advisory, it has been closed with a resolution of ERRATA. For information on the advisory (new packages: libnbd), and where to find the updated files, follow the link below. If the solution does not work for you, open a new bug report. https://access.redhat.com/errata/RHEA-2022:2409 |