-
-
Notifications
You must be signed in to change notification settings - Fork 31.9k
POSIX module incompatible with ZFS on FreeBSD #113078
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
Comments
Following the implementions from both FreeBSD and GNU glibc, `PyLong_FromDev should actually be unsigned. This can break on FreeBSD systems using ZFS, since they wouldn't generate device IDs with 56 upper bits randomly, therefore the MSB too. Also, following the documentation from FreeBSD and Linux, `makedev` should accept unsigned 32 bit integers. The reason to that is because on FreeBSD `major` and `minor` can return anything on the 32 bit int range and on Linux it really specifies that it returns a unsigned integer.
Following the implementions from both FreeBSD and GNU glibc, `PyLong_FromDev should actually be unsigned. This can break on FreeBSD systems using ZFS, since they wouldn't generate device IDs with 56 upper bits randomly, therefore the MSB too. Also, following the documentation from FreeBSD and Linux, `makedev` should accept unsigned 32 bit integers. The reason to that is because on FreeBSD `major` and `minor` can return anything on the 32 bit int range and on Linux it really specifies that it returns a unsigned integer.
Following the implementions from both FreeBSD and GNU glibc, `PyLong_FromDev should actually be unsigned. This can break on FreeBSD systems using ZFS, since they wouldn't generate device IDs with 56 upper bits randomly, therefore the MSB too. Also, following the documentation from FreeBSD and Linux, `makedev` should accept unsigned 32 bit integers. The reason to that is because on FreeBSD `major` and `minor` can return anything on the 32 bit int range and on Linux it really specifies that it returns a unsigned integer.
Sure, there's one thing tho. On you're implementation, Also, |
This issue is a duplicate of #89928. |
Bug report
Bug description:
When running tests on FreeBSD 14, I've found a problem with the current wrapper implementations of POSIX's
stat
andmakedev
. The first problem resides in the fact that the code in https://github.com/python/cpython/blob/main/Modules/posixmodule.c#L937 assumesdev_t
is always signed and positive, and inmakedev
not following the same interfaces frommajor
andminor
, which usesint
andunsigned int
for the later two.On stat
In https://github.com/python/cpython/blob/main/Lib/test/test_posix.py#L694-698, it's checked if
st.st_dev
is positive, but it can fail for reasons that I'll explain below. For now we should know that_PyLong_FromDev
in https://github.com/python/cpython/blob/main/Modules/posixmodule.c#L2521, usesPyLong_FromLongLong
which may interpret unsigned 64 bit integers incorrectly.Leads to this test error:
In fact when looking into FreeBSDs C headers, that is known that
dev_t
isuint64
and notint64
, and even glibc uses__UQUAD_TYPE
.Although
st_dev
shouldn't be negative, it doesn't cause any harm at first glance. It could probably crash other libraries and routines that expect it to be positive or unsigned tho.On makedev
By assuming that dev_t is always positive the implementations of
makedev
doesn't expect themajor
andminor
parameters to be unsigned. Therefore, beingint
, they may overflow once they use the results fromstat
+major
/minor
giving the following test error:Therefore, the whole round trip could cause errors in applications following this same pattern. The FreeBSD man pages for
makedev
,major
andminor
also mentions that the return values formajor
andminor
could span the complete range of an int:RETURN VALUES
On Linux, the return values are always
unsigned int
:ZFS and FreeBSD
After asking on the FreeBSD forums trying to understand why that
st_dev
was so large, after all it could be a bug on FreeBSD iself. Some users reported that in fact, ZFS uses such high device IDs. The reason, is that it doesn't refer to real devices, but virtual ones so OpenZFS generates the upper 56 bits of the device ID randomly, and therefore there's actually a 50% probability of that happening since the MSB is randomly generated.More details from
ralphbsz
:And from the OpenZFS code:
I couldn't dig deeper into Linux's implementation of ZFS, but testing it on a virtual machine the same bug doesn't happen.
CPython versions tested on:
CPython main branch
Operating systems tested on:
Other
Linked PRs
The text was updated successfully, but these errors were encountered: