On Tue, Mar 31, 2009 at 12:04:00PM +0200, Daniel Veillard wrote:
> > +++ b/src/security_selinux.c Mon Mar 30 14:37:45 2009
+0100
> > @@ -303,11 +303,13 @@ SELinuxRestoreSecurityImageLabel(virConn
> > return -1;
> >
> > if (S_ISLNK(buf.st_mode)) {
> > + int n;
> > if (VIR_ALLOC_N(newpath, buf.st_size + 1) < 0)
> > return -1;
> >
> > - if (readlink(path, newpath, buf.st_size) < 0)
> > + if ((n =readlink(path, newpath, buf.st_size)) < 0)
> > goto err;
> > + buf.st_size[n] = '\0';
> newpath[n] = '\0';
>
> correct?
Yup, I doubt it would compile otherwise :-)
I'm still doubtful about this piece of code though.
Suppose you have path an absolute path to /tmp/bar, and
bar is a relative symlink to foo, you will get buf.st_size
which is 3 i.e. the length of "foo" which is insufficient
to hold the expected path /tmp/foo.
Also /tmp/bar may point to /tmp/foo, which itself points to
/tmp/very_long_filename and again readlink will fail to provide
the full path.
Seems to me that if you're to use readlink there is no other
way than to allocate a PATH_MAX (+1) buffer and use that for
the link resolution.
Actually, the buffer is the exact right size, because that
'buf.st_size' was filled by a lstat() call, and the POSIX
semantics for lstat() are that 'st_size' will contain the
number of bytes in the destination filename. At least that's
what this post claims....
http://lists.debian.org/debian-hurd/2001/07/msg00301.html
Here's an updated patch which makes a helper function for
all this
Daniel
diff -r b6f96d7d7b11 src/libvirt_private.syms
--- a/src/libvirt_private.syms Tue Mar 31 13:48:24 2009 +0100
+++ b/src/libvirt_private.syms Tue Mar 31 14:26:15 2009 +0100
@@ -306,6 +306,7 @@ virStrToLong_ll;
virStrToLong_ull;
virStrToLong_ui;
virFileLinkPointsTo;
+virFileResolveLink;
saferead;
safewrite;
safezero;
diff -r b6f96d7d7b11 src/security_selinux.c
--- a/src/security_selinux.c Tue Mar 31 13:48:24 2009 +0100
+++ b/src/security_selinux.c Tue Mar 31 14:26:15 2009 +0100
@@ -293,28 +293,24 @@ SELinuxRestoreSecurityImageLabel(virConn
struct stat buf;
security_context_t fcon = NULL;
int rc = -1;
+ int err;
char *newpath = NULL;
const char *path = disk->src;
if (disk->readonly || disk->shared)
return 0;
- if (lstat(path, &buf) != 0)
- return -1;
-
- if (S_ISLNK(buf.st_mode)) {
- if (VIR_ALLOC_N(newpath, buf.st_size + 1) < 0)
- return -1;
-
- if (readlink(path, newpath, buf.st_size) < 0)
- goto err;
- path = newpath;
- if (stat(path, &buf) != 0)
- goto err;
+ if ((err = virFileResolveLink(path, &newpath)) < 0) {
+ virReportSystemError(conn, err,
+ _("cannot resolve symlink %s"), path);
+ goto err;
}
- if (matchpathcon(path, buf.st_mode, &fcon) == 0) {
- rc = SELinuxSetFilecon(conn, path, fcon);
+ if (stat(newpath, &buf) != 0)
+ goto err;
+
+ if (matchpathcon(newpath, buf.st_mode, &fcon) == 0) {
+ rc = SELinuxSetFilecon(conn, newpath, fcon);
}
err:
VIR_FREE(fcon);
diff -r b6f96d7d7b11 src/storage_backend_disk.c
--- a/src/storage_backend_disk.c Tue Mar 31 13:48:24 2009 +0100
+++ b/src/storage_backend_disk.c Tue Mar 31 14:26:15 2009 +0100
@@ -362,20 +362,16 @@ virStorageBackendDiskDeleteVol(virConnec
unsigned int flags ATTRIBUTE_UNUSED)
{
char *part_num = NULL;
- int n;
- char devpath[PATH_MAX];
+ int err;
+ char *devpath = NULL;
char *devname, *srcname;
+ int rc = -1;
- if ((n = readlink(vol->target.path, devpath, sizeof(devpath))) < 0 &&
- errno != EINVAL) {
- virReportSystemError(conn, errno,
+ if ((err = virFileResolveLink(vol->target.path, &devpath)) < 0) {
+ virReportSystemError(conn, err,
_("Couldn't read volume target path
'%s'"),
vol->target.path);
- return -1;
- } else if (n <= 0) {
- strncpy(devpath, vol->target.path, PATH_MAX);
- } else {
- devpath[n] = '\0';
+ goto cleanup;
}
devname = basename(devpath);
@@ -386,7 +382,7 @@ virStorageBackendDiskDeleteVol(virConnec
virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
_("Volume path '%s' did not start with parent
"
"pool source device name."), devname);
- return -1;
+ goto cleanup;
}
part_num = devname + strlen(srcname);
@@ -395,7 +391,7 @@ virStorageBackendDiskDeleteVol(virConnec
virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
_("cannot parse partition number from target "
"'%s'"), devname);
- return -1;
+ goto cleanup;
}
/* eg parted /dev/sda rm 2 */
@@ -409,9 +405,12 @@ virStorageBackendDiskDeleteVol(virConnec
};
if (virRun(conn, prog, NULL) < 0)
- return -1;
+ goto cleanup;
- return 0;
+ rc = 0;
+cleanup:
+ VIR_FREE(devpath);
+ return rc;
}
diff -r b6f96d7d7b11 src/util.c
--- a/src/util.c Tue Mar 31 13:48:24 2009 +0100
+++ b/src/util.c Tue Mar 31 14:26:15 2009 +0100
@@ -934,6 +934,53 @@ int virFileLinkPointsTo(const char *chec
&& SAME_INODE (src_sb, dest_sb));
}
+
+
+/*
+ * Attempt to resolve a symbolic link, returning the
+ * real path
+ *
+ * Return 0 if path was not a symbolic, or the link was
+ * resolved. Return -1 upon error
+ */
+int virFileResolveLink(const char *linkpath,
+ char **resultpath)
+{
+ struct stat st;
+ char *buf;
+ int n;
+
+ *resultpath = NULL;
+
+ if (lstat(linkpath, &st) < 0)
+ return errno;
+
+ if (!S_ISLNK(st.st_mode)) {
+ if (!(*resultpath = strdup(linkpath)))
+ return -ENOMEM;
+ return 0;
+ }
+
+ /* Posix says that 'st_size' field from
+ * result of an lstat() call is filled with
+ * number of bytes in the destination
+ * filename.
+ */
+ if (VIR_ALLOC_N(buf, st.st_size + 1) < 0)
+ return -ENOMEM;
+
+ if ((n = readlink(linkpath, buf, st.st_size)) < 0) {
+ VIR_FREE(buf);
+ return -errno;
+ }
+
+ buf[n] = '\0';
+
+ *resultpath = buf;
+ return 0;
+}
+
+
int virFileExists(const char *path)
{
struct stat st;
diff -r b6f96d7d7b11 src/util.h
--- a/src/util.h Tue Mar 31 13:48:24 2009 +0100
+++ b/src/util.h Tue Mar 31 14:26:15 2009 +0100
@@ -87,6 +87,9 @@ int virFileStripSuffix(char *str,
int virFileLinkPointsTo(const char *checkLink,
const char *checkDest);
+int virFileResolveLink(const char *linkpath,
+ char **resultpath);
+
int virFileExists(const char *path);
int virFileMakePath(const char *path);
--
|: Red Hat, Engineering, London -o-
http://people.redhat.com/berrange/ :|
|:
http://libvirt.org -o-
http://virt-manager.org -o-
http://ovirt.org :|
|:
http://autobuild.org -o-
http://search.cpan.org/~danberr/ :|
|: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|