From f9a726abefe1c25d952b36cd554e026e4c782967 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Thu, 31 Mar 2022 03:29:23 +0900 Subject: [PATCH] sd-device: introduce sd_device_open() We usually open() device node obtained by sd_device_get_devname(). However, the device node corresponds to the sd-device object may be already removed, and another device node with the same path may be created, hence an unexpected device may be opened. The sd_device_open() opens device node, and checks the devnum and diskseq of opened devnum, to avoid the above possibility. Prompted by https://github.com/systemd/systemd/issues/22906#issuecomment-1082736443. --- src/libsystemd/libsystemd.sym | 1 + src/libsystemd/sd-device/sd-device.c | 65 ++++++++++++++++++++++++++++ src/systemd/sd-device.h | 1 + 3 files changed, 67 insertions(+) diff --git a/src/libsystemd/libsystemd.sym b/src/libsystemd/libsystemd.sym index 0066894d54..bdf76b467b 100644 --- a/src/libsystemd/libsystemd.sym +++ b/src/libsystemd/libsystemd.sym @@ -775,4 +775,5 @@ global: sd_id128_to_uuid_string; sd_device_new_from_devname; sd_device_new_from_path; + sd_device_open; } LIBSYSTEMD_250; diff --git a/src/libsystemd/sd-device/sd-device.c b/src/libsystemd/sd-device/sd-device.c index c7389c8a3b..4f413880eb 100644 --- a/src/libsystemd/sd-device/sd-device.c +++ b/src/libsystemd/sd-device/sd-device.c @@ -2237,3 +2237,68 @@ _public_ int sd_device_trigger_with_uuid( *ret_uuid = u; return 0; } + +_public_ int sd_device_open(sd_device *device, int flags) { + _cleanup_close_ int fd = -1, fd2 = -1; + const char *devname, *subsystem = NULL; + uint64_t q, diskseq = 0; + struct stat st; + dev_t devnum; + int r; + + assert_return(device, -EINVAL); + assert_return(FLAGS_SET(flags, O_PATH) || !FLAGS_SET(flags, O_NOFOLLOW), -EINVAL); + + r = sd_device_get_devname(device, &devname); + if (r == -ENOENT) + return -ENOEXEC; + if (r < 0) + return r; + + r = sd_device_get_devnum(device, &devnum); + if (r == -ENOENT) + return -ENOEXEC; + if (r < 0) + return r; + + r = sd_device_get_subsystem(device, &subsystem); + if (r < 0 && r != -ENOENT) + return r; + + r = sd_device_get_diskseq(device, &diskseq); + if (r < 0 && r != -ENOENT) + return r; + + fd = open(devname, FLAGS_SET(flags, O_PATH) ? flags : O_CLOEXEC|O_NOFOLLOW|O_PATH); + if (fd < 0) + return -errno; + + if (fstat(fd, &st) < 0) + return -errno; + + if (st.st_rdev != devnum) + return -ENXIO; + + if (streq_ptr(subsystem, "block") ? !S_ISBLK(st.st_mode) : !S_ISCHR(st.st_mode)) + return -ENXIO; + + /* If flags has O_PATH, then we cannot check diskseq. Let's return earlier. */ + if (FLAGS_SET(flags, O_PATH)) + return TAKE_FD(fd); + + fd2 = open(FORMAT_PROC_FD_PATH(fd), flags); + if (fd2 < 0) + return -errno; + + if (diskseq == 0) + return TAKE_FD(fd2); + + r = fd_get_diskseq(fd2, &q); + if (r < 0) + return r; + + if (q != diskseq) + return -ENXIO; + + return TAKE_FD(fd2); +} diff --git a/src/systemd/sd-device.h b/src/systemd/sd-device.h index 2ac670b08c..f0c3c115e4 100644 --- a/src/systemd/sd-device.h +++ b/src/systemd/sd-device.h @@ -109,6 +109,7 @@ int sd_device_set_sysattr_value(sd_device *device, const char *sysattr, const ch int sd_device_set_sysattr_valuef(sd_device *device, const char *sysattr, const char *format, ...) _sd_printf_(3, 4); int sd_device_trigger(sd_device *device, sd_device_action_t action); int sd_device_trigger_with_uuid(sd_device *device, sd_device_action_t action, sd_id128_t *ret_uuid); +int sd_device_open(sd_device *device, int flags); /* device enumerator */