9pfs: local: rename: use renameat
The local_rename() callback is vulnerable to symlink attacks because it
uses rename() which follows symbolic links in all path elements but the
rightmost one.
This patch simply transforms local_rename() into a wrapper around
local_renameat() which is symlink-attack safe.
This partly fixes CVE-2016-9602.
Signed-off-by: Greg Kurz <groug@kaod.org>
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
(cherry picked from commit d2767edec5
)
Signed-off-by: Greg Kurz <gkurz@linux.vnet.ibm.com>
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
This commit is contained in:
parent
0f3490faa8
commit
d93d06a2fc
|
@ -965,36 +965,6 @@ static int local_truncate(FsContext *ctx, V9fsPath *fs_path, off_t size)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int local_rename(FsContext *ctx, const char *oldpath,
|
|
||||||
const char *newpath)
|
|
||||||
{
|
|
||||||
int err;
|
|
||||||
char *buffer, *buffer1;
|
|
||||||
|
|
||||||
if (ctx->export_flags & V9FS_SM_MAPPED_FILE) {
|
|
||||||
err = local_create_mapped_attr_dir(ctx, newpath);
|
|
||||||
if (err < 0) {
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
/* rename the .virtfs_metadata files */
|
|
||||||
buffer = local_mapped_attr_path(ctx, oldpath);
|
|
||||||
buffer1 = local_mapped_attr_path(ctx, newpath);
|
|
||||||
err = rename(buffer, buffer1);
|
|
||||||
g_free(buffer);
|
|
||||||
g_free(buffer1);
|
|
||||||
if (err < 0 && errno != ENOENT) {
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
buffer = rpath(ctx, oldpath);
|
|
||||||
buffer1 = rpath(ctx, newpath);
|
|
||||||
err = rename(buffer, buffer1);
|
|
||||||
g_free(buffer);
|
|
||||||
g_free(buffer1);
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int local_chown(FsContext *fs_ctx, V9fsPath *fs_path, FsCred *credp)
|
static int local_chown(FsContext *fs_ctx, V9fsPath *fs_path, FsCred *credp)
|
||||||
{
|
{
|
||||||
char *buffer;
|
char *buffer;
|
||||||
|
@ -1255,6 +1225,33 @@ out:
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void v9fs_path_init_dirname(V9fsPath *path, const char *str)
|
||||||
|
{
|
||||||
|
path->data = g_path_get_dirname(str);
|
||||||
|
path->size = strlen(path->data) + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int local_rename(FsContext *ctx, const char *oldpath,
|
||||||
|
const char *newpath)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
char *oname = g_path_get_basename(oldpath);
|
||||||
|
char *nname = g_path_get_basename(newpath);
|
||||||
|
V9fsPath olddir, newdir;
|
||||||
|
|
||||||
|
v9fs_path_init_dirname(&olddir, oldpath);
|
||||||
|
v9fs_path_init_dirname(&newdir, newpath);
|
||||||
|
|
||||||
|
err = local_renameat(ctx, &olddir, oname, &newdir, nname);
|
||||||
|
|
||||||
|
v9fs_path_free(&newdir);
|
||||||
|
v9fs_path_free(&olddir);
|
||||||
|
g_free(nname);
|
||||||
|
g_free(oname);
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
static int local_unlinkat(FsContext *ctx, V9fsPath *dir,
|
static int local_unlinkat(FsContext *ctx, V9fsPath *dir,
|
||||||
const char *name, int flags)
|
const char *name, int flags)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue