stat-util: add macros for checking whether major and minor values are in range

As it turns out glibc and the Linux kernel have different ideas about
the size of dev_t and how many bits exist for the major and the minor.
When validating major/minor numbers we should check against the kernel's
actual sizes, hence add macros for this.
This commit is contained in:
Lennart Poettering 2018-06-28 20:57:15 +02:00
parent 192b89368e
commit fb2430c6e5
2 changed files with 55 additions and 0 deletions

View File

@ -62,3 +62,22 @@ int fd_verify_regular(int fd);
int stat_verify_directory(const struct stat *st);
int fd_verify_directory(int fd);
/* glibc and the Linux kernel have different ideas about the major/minor size. These calls will check whether the
* specified major is valid by the Linux kernel's standards, not by glibc's. Linux has 20bits of minor, and 12 bits of
* major space. See MINORBITS in linux/kdev_t.h in the kernel sources. (If you wonder why we define _y here, instead of
* comparing directly >= 0: it's to trick out -Wtype-limits, which would otherwise complain if the type is unsigned, as
* such a test would be pointless in such a case.) */
#define DEVICE_MAJOR_VALID(x) \
({ \
typeof(x) _x = (x), _y = 0; \
_x >= _y && _x < (UINT32_C(1) << 12); \
\
})
#define DEVICE_MINOR_VALID(x) \
({ \
typeof(x) _x = (x), _y = 0; \
_x >= _y && _x < (UINT32_C(1) << 20); \
})

View File

@ -81,12 +81,48 @@ static void test_fd_is_network_ns(void) {
assert_se(IN_SET(fd_is_network_ns(fd), 1, -EUCLEAN));
}
static void test_device_major_minor_valid(void) {
/* on glibc dev_t is 64bit, even though in the kernel it is only 32bit */
assert_cc(sizeof(dev_t) == sizeof(uint64_t));
assert_se(DEVICE_MAJOR_VALID(0U));
assert_se(DEVICE_MINOR_VALID(0U));
assert_se(DEVICE_MAJOR_VALID(1U));
assert_se(DEVICE_MINOR_VALID(1U));
assert_se(!DEVICE_MAJOR_VALID(-1U));
assert_se(!DEVICE_MINOR_VALID(-1U));
assert_se(DEVICE_MAJOR_VALID(1U << 10));
assert_se(DEVICE_MINOR_VALID(1U << 10));
assert_se(DEVICE_MAJOR_VALID((1U << 12) - 1));
assert_se(DEVICE_MINOR_VALID((1U << 20) - 1));
assert_se(!DEVICE_MAJOR_VALID((1U << 12)));
assert_se(!DEVICE_MINOR_VALID((1U << 20)));
assert_se(!DEVICE_MAJOR_VALID(1U << 25));
assert_se(!DEVICE_MINOR_VALID(1U << 25));
assert_se(!DEVICE_MAJOR_VALID(UINT32_MAX));
assert_se(!DEVICE_MINOR_VALID(UINT32_MAX));
assert_se(!DEVICE_MAJOR_VALID(UINT64_MAX));
assert_se(!DEVICE_MINOR_VALID(UINT64_MAX));
assert_se(DEVICE_MAJOR_VALID(major(0)));
assert_se(DEVICE_MINOR_VALID(minor(0)));
}
int main(int argc, char *argv[]) {
test_files_same();
test_is_symlink();
test_path_is_fs_type();
test_path_is_temporary_fs();
test_fd_is_network_ns();
test_device_major_minor_valid();
return 0;
}