[libvirt] [PATCH] storage: don't read storage volumes in nonblock mode
Michal Privoznik
mprivozn at redhat.com
Tue Nov 26 17:19:27 UTC 2013
On 25.11.2013 22:49, Eric Blake wrote:
> Commit 348b4e2 introduced a potential problem (thankfully not
> in any release): we are attempting to use virFileReadHeaderFD()
> on a file that was opened with O_NONBLOCK. While this
> shouldn't be a problem in practice (because O_NONBLOCK
> typically doesn't affect regular or block files, and fifos and
> sockets cannot be storage volumes), it's better to play it safe
> to avoid races from opening an unexpected file type while also
> avoiding problems with having to handle EAGAIN while read()ing.
>
> Based on a report by Dan Berrange.
>
> * src/storage/storage_backend.c
> (virStorageBackendVolOpenCheckMode): Fix up fd after avoiding race.
>
> Signed-off-by: Eric Blake <eblake at redhat.com>
> ---
> src/storage/storage_backend.c | 25 +++++++++++++++++++++----
> 1 file changed, 21 insertions(+), 4 deletions(-)
>
> diff --git a/src/storage/storage_backend.c b/src/storage/storage_backend.c
> index 57c1728..bde39d6 100644
> --- a/src/storage/storage_backend.c
> +++ b/src/storage/storage_backend.c
> @@ -1179,6 +1179,12 @@ virStorageBackendVolOpenCheckMode(const char *path, struct stat *sb,
> return -2;
> }
>
> + /* O_NONBLOCK should only matter during open() for fifos and
> + * sockets, which we already filtered; but using it prevents a
> + * TOCTTOU race. However, later on we will want to read() the
> + * header from this fd, and virFileRead* routines require a
> + * blocking fd, so fix it up after verifying we avoided a
> + * race. */
> if ((fd = open(path, O_RDONLY|O_NONBLOCK|O_NOCTTY)) < 0) {
> if ((errno == ENOENT || errno == ELOOP) &&
> S_ISLNK(sb->st_mode)) {
> @@ -1200,13 +1206,13 @@ virStorageBackendVolOpenCheckMode(const char *path, struct stat *sb,
> return -1;
> }
>
> - if (S_ISREG(sb->st_mode))
> + if (S_ISREG(sb->st_mode)) {
> mode = VIR_STORAGE_VOL_OPEN_REG;
> - else if (S_ISCHR(sb->st_mode))
> + } else if (S_ISCHR(sb->st_mode)) {
> mode = VIR_STORAGE_VOL_OPEN_CHAR;
> - else if (S_ISBLK(sb->st_mode))
> + } else if (S_ISBLK(sb->st_mode)) {
> mode = VIR_STORAGE_VOL_OPEN_BLOCK;
> - else if (S_ISDIR(sb->st_mode)) {
> + } else if (S_ISDIR(sb->st_mode)) {
> mode = VIR_STORAGE_VOL_OPEN_DIR;
>
> if (STREQ(base, ".") ||
> @@ -1215,6 +1221,17 @@ virStorageBackendVolOpenCheckMode(const char *path, struct stat *sb,
> VIR_INFO("Skipping special dir '%s'", base);
> return -2;
> }
> + } else {
> + VIR_WARN("ignoring unexpected type for file '%s'", path);
> + VIR_FORCE_CLOSE(fd);
> + return -2;
> + }
> +
> + if (virSetBlocking(fd, true) < 0) {
> + virReportSystemError(errno, _("unable to set blocking mode for '%s'"),
> + path);
> + VIR_FORCE_CLOSE(fd);
> + return -2;
> }
>
> if (!(mode & flags)) {
>
ACK
Michal
More information about the libvir-list
mailing list