Posix: Unify minimum kernel version checks
Introduce SysInfo::KernelVersionNumber to hold kernel version numbers
for POSIX platforms. Also provide a static method
SysInfo::KernelVersionNumber::Current() to query the kernel version
using uname. This deduplicates code across the codebase and makes
minimum kernel version checks more readable.
Bug: 384902323
Change-Id: Ib92ad9aeafa13045a52d109c46a8e9a5436cff2b
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6304829
Reviewed-by: Kyle Charbonneau <kylechar@chromium.org>
Reviewed-by: Tom Sepez <tsepez@chromium.org>
Commit-Queue: Anand Ravi <anandrv@google.com>
Cr-Commit-Position: refs/heads/main@{#1430493}
diff --git a/base/rand_util_posix.cc b/base/rand_util_posix.cc
index dc030af9..bced708 100644
--- a/base/rand_util_posix.cc
+++ b/base/rand_util_posix.cc
@@ -25,6 +25,7 @@
#include "base/metrics/histogram_macros.h"
#include "base/no_destructor.h"
#include "base/posix/eintr_wrapper.h"
+#include "base/system/sys_info.h"
#include "base/time/time.h"
#include "build/build_config.h"
@@ -72,38 +73,10 @@
#if (BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || \
BUILDFLAG(IS_ANDROID)) && \
!BUILDFLAG(IS_NACL)
-// TODO(pasko): Unify reading kernel version numbers in:
-// mojo/core/channel_linux.cc
-// chrome/browser/android/seccomp_support_detector.cc
-void KernelVersionNumbers(int32_t* major_version,
- int32_t* minor_version,
- int32_t* bugfix_version) {
- struct utsname info;
- if (uname(&info) < 0) {
- NOTREACHED();
- }
- int num_read = sscanf(info.release, "%d.%d.%d", major_version, minor_version,
- bugfix_version);
- if (num_read < 1) {
- *major_version = 0;
- }
- if (num_read < 2) {
- *minor_version = 0;
- }
- if (num_read < 3) {
- *bugfix_version = 0;
- }
-}
bool KernelSupportsGetRandom() {
- int32_t major = 0;
- int32_t minor = 0;
- int32_t bugfix = 0;
- KernelVersionNumbers(&major, &minor, &bugfix);
- if (major > 3 || (major == 3 && minor >= 17)) {
- return true;
- }
- return false;
+ return base::SysInfo::KernelVersionNumber::Current() >=
+ base::SysInfo::KernelVersionNumber(3, 17);
}
bool GetRandomSyscall(void* output, size_t output_length) {
diff --git a/base/system/sys_info.h b/base/system/sys_info.h
index f57ebd3..f7b9aaa4 100644
--- a/base/system/sys_info.h
+++ b/base/system/sys_info.h
@@ -8,6 +8,8 @@
#include <stddef.h>
#include <stdint.h>
+#include <compare>
+#include <iosfwd>
#include <map>
#include <optional>
#include <string>
@@ -194,6 +196,27 @@
int32_t* minor_version,
int32_t* bugfix_version);
+#if BUILDFLAG(IS_POSIX)
+ // Struct containing the the kernel version number of the host operating
+ // system.
+ struct BASE_EXPORT KernelVersionNumber {
+ // Queries the current kernel version number using uname and parses the
+ // release string to construct the KernelVersionNumber struct. This does not
+ // cache the result.
+ static KernelVersionNumber Current();
+
+ friend bool operator==(const KernelVersionNumber& v1,
+ const KernelVersionNumber& v2) = default;
+
+ friend auto operator<=>(const KernelVersionNumber& v1,
+ const KernelVersionNumber& v2) = default;
+
+ int32_t major = 0;
+ int32_t minor = 0;
+ int32_t bugfix = 0;
+ };
+#endif // BUILDFLAG(IS_POSIX)
+
// Returns the architecture of the running operating system.
// Exact return value may differ across platforms.
// e.g. a 32-bit x86 kernel on a 64-bit capable CPU will return "x86",
@@ -356,6 +379,13 @@
static void ClearAmountOfPhysicalMemoryMbForTesting();
};
+#if BUILDFLAG(IS_POSIX)
+// Stream operator so that SysInfo::KernelVersionNumber can be logged with a
+// consistent format.
+BASE_EXPORT std::ostream& operator<<(std::ostream& out,
+ const SysInfo::KernelVersionNumber& v);
+#endif // BUILDFLAG(IS_POSIX)
+
} // namespace base
#endif // BASE_SYSTEM_SYS_INFO_H_
diff --git a/base/system/sys_info_posix.cc b/base/system/sys_info_posix.cc
index 1f43721..19f50f0b 100644
--- a/base/system/sys_info_posix.cc
+++ b/base/system/sys_info_posix.cc
@@ -20,6 +20,7 @@
#include <unistd.h>
#include <algorithm>
+#include <iostream>
#include "base/check.h"
#include "base/files/file_util.h"
@@ -120,6 +121,24 @@
return true;
}
+void GetKernelVersionNumbers(int32_t* major_version,
+ int32_t* minor_version,
+ int32_t* bugfix_version) {
+ struct utsname info;
+ CHECK_EQ(uname(&info), 0);
+ int num_read = sscanf(info.release, "%d.%d.%d", major_version, minor_version,
+ bugfix_version);
+ if (num_read < 1) {
+ *major_version = 0;
+ }
+ if (num_read < 2) {
+ *minor_version = 0;
+ }
+ if (num_read < 3) {
+ *bugfix_version = 0;
+ }
+}
+
} // namespace
namespace base {
@@ -238,24 +257,22 @@
void SysInfo::OperatingSystemVersionNumbers(int32_t* major_version,
int32_t* minor_version,
int32_t* bugfix_version) {
- struct utsname info;
- if (uname(&info) < 0) {
- NOTREACHED();
- }
- int num_read = sscanf(info.release, "%d.%d.%d", major_version, minor_version,
- bugfix_version);
- if (num_read < 1) {
- *major_version = 0;
- }
- if (num_read < 2) {
- *minor_version = 0;
- }
- if (num_read < 3) {
- *bugfix_version = 0;
- }
+ GetKernelVersionNumbers(major_version, minor_version, bugfix_version);
}
#endif
+// static
+SysInfo::KernelVersionNumber SysInfo::KernelVersionNumber::Current() {
+ KernelVersionNumber v;
+ GetKernelVersionNumbers(&v.major, &v.minor, &v.bugfix);
+ return v;
+}
+
+std::ostream& operator<<(std::ostream& out,
+ const SysInfo::KernelVersionNumber& v) {
+ return out << v.major << "." << v.minor << "." << v.bugfix;
+}
+
#if !BUILDFLAG(IS_MAC) && !BUILDFLAG(IS_IOS)
// static
std::string SysInfo::OperatingSystemArchitecture() {
diff --git a/base/system/sys_info_unittest.cc b/base/system/sys_info_unittest.cc
index 1983447..614472a 100644
--- a/base/system/sys_info_unittest.cc
+++ b/base/system/sys_info_unittest.cc
@@ -462,4 +462,26 @@
#endif // BUILDFLAG(IS_CHROMEOS)
+#if BUILDFLAG(IS_POSIX)
+TEST_F(SysInfoTest, KernelVersionNumber) {
+ auto current_kernel_version = SysInfo::KernelVersionNumber::Current();
+
+ EXPECT_GT(current_kernel_version, SysInfo::KernelVersionNumber());
+ // Chromium will realistically never run on a kernel as old as 2.1.11
+ EXPECT_GT(current_kernel_version, SysInfo::KernelVersionNumber(2, 1, 11));
+
+ SysInfo::KernelVersionNumber next_major_kernel_version(
+ current_kernel_version.major + 1);
+ EXPECT_LT(current_kernel_version, next_major_kernel_version);
+
+ SysInfo::KernelVersionNumber next_minor_kernel_version(
+ current_kernel_version.major, current_kernel_version.minor + 1);
+ EXPECT_LT(current_kernel_version, next_minor_kernel_version);
+
+ SysInfo::KernelVersionNumber next_bugfix_kernel_version(
+ current_kernel_version.major, current_kernel_version.minor,
+ current_kernel_version.bugfix + 1);
+ EXPECT_LT(current_kernel_version, next_bugfix_kernel_version);
+}
+#endif // BUILDFLAG(IS_POSIX)
} // namespace base
diff --git a/mojo/core/channel_linux.cc b/mojo/core/channel_linux.cc
index dd5edfc..84c52a5 100644
--- a/mojo/core/channel_linux.cc
+++ b/mojo/core/channel_linux.cc
@@ -58,29 +58,6 @@
namespace mojo {
namespace core {
-namespace {
-
-// On Android base::SysInfo::OperatingSystemVersionNumbers actually returns the
-// build numbers and not the kernel version as the other posix OSes would.
-void KernelVersionNumbers(int32_t* major_version,
- int32_t* minor_version,
- int32_t* bugfix_version) {
- struct utsname info;
- if (uname(&info) < 0) {
- NOTREACHED();
- }
- int num_read = sscanf(info.release, "%d.%d.%d", major_version, minor_version,
- bugfix_version);
- if (num_read < 1)
- *major_version = 0;
- if (num_read < 2)
- *minor_version = 0;
- if (num_read < 3)
- *bugfix_version = 0;
-}
-
-} // namespace
-
// DataAvailableNotifier is a simple interface which allows us to
// substitute how we notify the reader that we've made data available,
// implementations might be EventFDNotifier or FutexNotifier.
@@ -918,12 +895,8 @@
//
// Additionally, the behavior of eventfd prior to the 4.0 kernel could be
// racy.
- int os_major_version = 0;
- int os_minor_version = 0;
- int os_bugfix_version = 0;
- KernelVersionNumbers(&os_major_version, &os_minor_version,
- &os_bugfix_version);
- if (os_major_version < 4) {
+ if (base::SysInfo::KernelVersionNumber::Current() <
+ base::SysInfo::KernelVersionNumber(4, 0)) {
// Due to the potentially races in 3.17/3.18 kernels with eventfd,
// explicitly require a 4.x+ kernel.
return false;
diff --git a/ui/ozone/platform/wayland/host/wayland_buffer_manager_host.cc b/ui/ozone/platform/wayland/host/wayland_buffer_manager_host.cc
index c036c515..3cc7d24 100644
--- a/ui/ozone/platform/wayland/host/wayland_buffer_manager_host.cc
+++ b/ui/ozone/platform/wayland/host/wayland_buffer_manager_host.cc
@@ -22,6 +22,7 @@
#include "base/posix/eintr_wrapper.h"
#include "base/strings/strcat.h"
#include "base/strings/utf_string_conversions.h"
+#include "base/system/sys_info.h"
#include "base/task/current_thread.h"
#include "base/trace_event/trace_event.h"
#include "ui/gfx/geometry/size.h"
@@ -47,37 +48,10 @@
return base::UTF16ToUTF8(base::FormatNumber(number));
}
-struct KernelVersion {
- int32_t major;
- int32_t minor;
- int32_t bugfix;
-};
-
-KernelVersion KernelVersionNumbers() {
- KernelVersion ver;
- struct utsname info;
- if (uname(&info) < 0) {
- NOTREACHED();
- }
- int num_read =
- sscanf(info.release, "%d.%d.%d", &ver.major, &ver.minor, &ver.bugfix);
- if (num_read < 1) {
- ver.major = 0;
- }
- if (num_read < 2) {
- ver.minor = 0;
- }
- if (num_read < 3) {
- ver.bugfix = 0;
- }
- return ver;
-}
-
bool CheckImportExportFence() {
- KernelVersion ver = KernelVersionNumbers();
-
// DMA_BUF_IOCTL_{IMPORT,EXPORT}_SYNC_FILE was added in 6.0
- return ver.major >= 6;
+ return base::SysInfo::KernelVersionNumber::Current() >=
+ base::SysInfo::KernelVersionNumber(6, 0);
}
} // namespace