1
1
mirror of https://github.com/systemd/systemd-stable.git synced 2024-12-24 21:34:08 +03:00

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.
This commit is contained in:
Yu Watanabe 2022-03-31 03:29:23 +09:00
parent 7e93a65868
commit f9a726abef
3 changed files with 67 additions and 0 deletions

View File

@ -775,4 +775,5 @@ global:
sd_id128_to_uuid_string; sd_id128_to_uuid_string;
sd_device_new_from_devname; sd_device_new_from_devname;
sd_device_new_from_path; sd_device_new_from_path;
sd_device_open;
} LIBSYSTEMD_250; } LIBSYSTEMD_250;

View File

@ -2237,3 +2237,68 @@ _public_ int sd_device_trigger_with_uuid(
*ret_uuid = u; *ret_uuid = u;
return 0; 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);
}

View File

@ -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_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(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_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 */ /* device enumerator */