提交 4a1abb3f 编写于 作者: C Cole Robinson

storage: Check for invalid storage mode before opening

If a directory pool contains pipes or sockets, a pool start can fail or hang:

https://bugzilla.redhat.com/show_bug.cgi?id=589577

We already try to avoid these special files, but only attempt after
opening the path, which is where the problems lie. Unify volume opening
into helper functions, which use the proper open() flags to avoid error,
followed by fstat to validate storage mode.

Previously, virStorageBackendUpdateVolTargetInfoFD attempted to enforce the
storage mode check, but allowed callers to detect this case and silently
continue. In practice, only the FS backend was using this feature, the rest
were treating unknown mode as an error condition. Unfortunately the InfoFD
function wasn't raising an error message here, so error reporting was
busted.

This patch adds 2 functions: virStorageBackendVolOpen, and
virStorageBackendVolOpenModeSkip. The latter retains the original opt out
semantics, the former now throws an explicit error.

This patch maintains the previous volume mode checks: allowing specific
modes for specific pool types requires a bit of surgery, since VolOpen
is called through several different helper functions.

v2: Use ATTRIBUTE_NONNULL. Drop stat check, just open with
    O_NONBLOCK|O_NOCTTY.

v3: Move mode check logic back to VolOpen. Use 2 VolOpen functions with
    different error semantics.

v4: Make second VolOpen function more extensible. Didn't opt to change
    FS backend defaults, this can just be to fix the original bug.

v5: Prefix default flags with VIR_, use ATTRIBUTE_RETURN_CHECK
上级 ca1b7cc8
...@@ -873,20 +873,71 @@ virStorageBackendForType(int type) { ...@@ -873,20 +873,71 @@ virStorageBackendForType(int type) {
} }
/*
* Allows caller to silently ignore files with improper mode
*
* Returns -1 on error, -2 if file mode is unexpected.
*/
int int
virStorageBackendUpdateVolTargetInfo(virStorageVolTargetPtr target, virStorageBackendVolOpenCheckMode(const char *path, unsigned int flags)
unsigned long long *allocation,
unsigned long long *capacity)
{ {
int ret, fd; int fd, mode = 0;
struct stat sb;
if ((fd = open(target->path, O_RDONLY)) < 0) { if ((fd = open(path, O_RDONLY|O_NONBLOCK|O_NOCTTY)) < 0) {
virReportSystemError(errno, virReportSystemError(errno,
_("cannot open volume '%s'"), _("cannot open volume '%s'"),
target->path); path);
return -1; return -1;
} }
if (fstat(fd, &sb) < 0) {
virReportSystemError(errno,
_("cannot stat file '%s'"),
path);
close(fd);
return -1;
}
if (S_ISREG(sb.st_mode))
mode = VIR_STORAGE_VOL_OPEN_REG;
else if (S_ISCHR(sb.st_mode))
mode = VIR_STORAGE_VOL_OPEN_CHAR;
else if (S_ISBLK(sb.st_mode))
mode = VIR_STORAGE_VOL_OPEN_BLOCK;
if (!(mode & flags)) {
close(fd);
if (mode & VIR_STORAGE_VOL_OPEN_ERROR) {
virStorageReportError(VIR_ERR_INTERNAL_ERROR,
_("unexpected storage mode for '%s'"), path);
return -1;
}
return -2;
}
return fd;
}
int virStorageBackendVolOpen(const char *path)
{
return virStorageBackendVolOpenCheckMode(path,
VIR_STORAGE_VOL_OPEN_DEFAULT);
}
int
virStorageBackendUpdateVolTargetInfo(virStorageVolTargetPtr target,
unsigned long long *allocation,
unsigned long long *capacity)
{
int ret, fd;
if ((ret = virStorageBackendVolOpen(target->path)) < 0)
return ret;
fd = ret;
ret = virStorageBackendUpdateVolTargetInfoFD(target, ret = virStorageBackendUpdateVolTargetInfoFD(target,
fd, fd,
allocation, allocation,
...@@ -920,12 +971,11 @@ virStorageBackendUpdateVolInfo(virStorageVolDefPtr vol, ...@@ -920,12 +971,11 @@ virStorageBackendUpdateVolInfo(virStorageVolDefPtr vol,
* virStorageBackendUpdateVolTargetInfoFD: * virStorageBackendUpdateVolTargetInfoFD:
* @conn: connection to report errors on * @conn: connection to report errors on
* @target: target definition ptr of volume to update * @target: target definition ptr of volume to update
* @fd: fd of storage volume to update * @fd: fd of storage volume to update, via virStorageBackendOpenVol*
* @allocation: If not NULL, updated allocation information will be stored * @allocation: If not NULL, updated allocation information will be stored
* @capacity: If not NULL, updated capacity info will be stored * @capacity: If not NULL, updated capacity info will be stored
* *
* Returns 0 for success-1 on a legitimate error condition, * Returns 0 for success, -1 on a legitimate error condition.
* -2 if passed FD isn't a regular, char, or block file.
*/ */
int int
virStorageBackendUpdateVolTargetInfoFD(virStorageVolTargetPtr target, virStorageBackendUpdateVolTargetInfoFD(virStorageVolTargetPtr target,
...@@ -945,11 +995,6 @@ virStorageBackendUpdateVolTargetInfoFD(virStorageVolTargetPtr target, ...@@ -945,11 +995,6 @@ virStorageBackendUpdateVolTargetInfoFD(virStorageVolTargetPtr target,
return -1; return -1;
} }
if (!S_ISREG(sb.st_mode) &&
!S_ISCHR(sb.st_mode) &&
!S_ISBLK(sb.st_mode))
return -2;
if (allocation) { if (allocation) {
if (S_ISREG(sb.st_mode)) { if (S_ISREG(sb.st_mode)) {
#ifndef WIN32 #ifndef WIN32
......
...@@ -80,6 +80,27 @@ struct _virStorageBackend { ...@@ -80,6 +80,27 @@ struct _virStorageBackend {
virStorageBackendPtr virStorageBackendForType(int type); virStorageBackendPtr virStorageBackendForType(int type);
int virStorageBackendVolOpen(const char *path)
ATTRIBUTE_RETURN_CHECK
ATTRIBUTE_NONNULL(1);
/* VolOpenCheckMode flags */
enum {
VIR_STORAGE_VOL_OPEN_ERROR = 1 << 0, /* warn if unexpected type
* encountered */
VIR_STORAGE_VOL_OPEN_REG = 1 << 1, /* regular files okay */
VIR_STORAGE_VOL_OPEN_BLOCK = 1 << 2, /* block files okay */
VIR_STORAGE_VOL_OPEN_CHAR = 1 << 3, /* char files okay */
};
#define VIR_STORAGE_VOL_OPEN_DEFAULT (VIR_STORAGE_VOL_OPEN_ERROR |\
VIR_STORAGE_VOL_OPEN_REG |\
VIR_STORAGE_VOL_OPEN_CHAR |\
VIR_STORAGE_VOL_OPEN_BLOCK)
int virStorageBackendVolOpenCheckMode(const char *path, unsigned int flags)
ATTRIBUTE_RETURN_CHECK
ATTRIBUTE_NONNULL(1);
int virStorageBackendUpdateVolInfo(virStorageVolDefPtr vol, int virStorageBackendUpdateVolInfo(virStorageVolDefPtr vol,
int withCapacity); int withCapacity);
......
...@@ -61,18 +61,16 @@ virStorageBackendProbeTarget(virStorageVolTargetPtr target, ...@@ -61,18 +61,16 @@ virStorageBackendProbeTarget(virStorageVolTargetPtr target,
if (encryption) if (encryption)
*encryption = NULL; *encryption = NULL;
if ((fd = open(target->path, O_RDONLY)) < 0) { if ((ret = virStorageBackendVolOpenCheckMode(target->path,
virReportSystemError(errno, (VIR_STORAGE_VOL_OPEN_DEFAULT & ~VIR_STORAGE_VOL_OPEN_ERROR))) < 0)
_("cannot open volume '%s'"), return ret; /* Take care to propagate ret, it is not always -1 */
target->path); fd = ret;
return -1;
}
if ((ret = virStorageBackendUpdateVolTargetInfoFD(target, fd, if ((ret = virStorageBackendUpdateVolTargetInfoFD(target, fd,
allocation, allocation,
capacity)) < 0) { capacity)) < 0) {
close(fd); close(fd);
return ret; /* Take care to propagate ret, it is not always -1 */ return -1;
} }
memset(&meta, 0, sizeof(meta)); memset(&meta, 0, sizeof(meta));
......
...@@ -559,7 +559,7 @@ virStorageBackendLogicalCreateVol(virConnectPtr conn, ...@@ -559,7 +559,7 @@ virStorageBackendLogicalCreateVol(virConnectPtr conn,
virStoragePoolObjPtr pool, virStoragePoolObjPtr pool,
virStorageVolDefPtr vol) virStorageVolDefPtr vol)
{ {
int fd = -1; int fdret, fd = -1;
char size[100]; char size[100];
const char *cmdargvnew[] = { const char *cmdargvnew[] = {
LVCREATE, "--name", vol->name, "-L", size, LVCREATE, "--name", vol->name, "-L", size,
...@@ -602,12 +602,9 @@ virStorageBackendLogicalCreateVol(virConnectPtr conn, ...@@ -602,12 +602,9 @@ virStorageBackendLogicalCreateVol(virConnectPtr conn,
if (virRun(cmdargv, NULL) < 0) if (virRun(cmdargv, NULL) < 0)
return -1; return -1;
if ((fd = open(vol->target.path, O_RDONLY)) < 0) { if ((fdret = virStorageBackendVolOpen(vol->target.path)) < 0)
virReportSystemError(errno,
_("cannot read path '%s'"),
vol->target.path);
goto cleanup; goto cleanup;
} fd = fdret;
/* We can only chown/grp if root */ /* We can only chown/grp if root */
if (getuid() == 0) { if (getuid() == 0) {
......
...@@ -44,14 +44,11 @@ virStorageBackendMpathUpdateVolTargetInfo(virStorageVolTargetPtr target, ...@@ -44,14 +44,11 @@ virStorageBackendMpathUpdateVolTargetInfo(virStorageVolTargetPtr target,
unsigned long long *capacity) unsigned long long *capacity)
{ {
int ret = -1; int ret = -1;
int fd = -1; int fdret, fd = -1;
if ((fd = open(target->path, O_RDONLY)) < 0) { if ((fdret = virStorageBackendVolOpen(target->path)) < 0)
virReportSystemError(errno,
_("cannot open volume '%s'"),
target->path);
goto out; goto out;
} fd = fdret;
if (virStorageBackendUpdateVolTargetInfoFD(target, if (virStorageBackendUpdateVolTargetInfoFD(target,
fd, fd,
......
...@@ -135,14 +135,12 @@ virStorageBackendSCSIUpdateVolTargetInfo(virStorageVolTargetPtr target, ...@@ -135,14 +135,12 @@ virStorageBackendSCSIUpdateVolTargetInfo(virStorageVolTargetPtr target,
unsigned long long *allocation, unsigned long long *allocation,
unsigned long long *capacity) unsigned long long *capacity)
{ {
int fd, ret = -1; int fdret, fd = -1;
int ret = -1;
if ((fd = open(target->path, O_RDONLY)) < 0) { if ((fdret = virStorageBackendVolOpen(target->path)) < 0)
virReportSystemError(errno, goto cleanup;
_("cannot open volume '%s'"), fd = fdret;
target->path);
return -1;
}
if (virStorageBackendUpdateVolTargetInfoFD(target, if (virStorageBackendUpdateVolTargetInfoFD(target,
fd, fd,
...@@ -155,8 +153,9 @@ virStorageBackendSCSIUpdateVolTargetInfo(virStorageVolTargetPtr target, ...@@ -155,8 +153,9 @@ virStorageBackendSCSIUpdateVolTargetInfo(virStorageVolTargetPtr target,
ret = 0; ret = 0;
cleanup: cleanup:
close(fd); if (fd >= 0)
close(fd);
return ret; return ret;
} }
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册