diff mbox

[V9fs-developer,PATCH-V5,08/10] virtio-9p: Security model for symlink and readlink

Message ID 1275700132-22823-9-git-send-email-jvrao@linux.vnet.ibm.com (mailing list archive)
State Not Applicable
Headers show

Commit Message

jvrao June 5, 2010, 1:08 a.m. UTC
None
diff mbox

Patch

diff --git a/hw/file-op-9p.h b/hw/file-op-9p.h
index 12223de..0808630 100644
--- a/hw/file-op-9p.h
+++ b/hw/file-op-9p.h
@@ -55,7 +55,7 @@  typedef struct FileOperations
     int (*mksock)(FsContext *, const char *);
     int (*utime)(FsContext *, const char *, const struct utimbuf *);
     int (*remove)(FsContext *, const char *);
-    int (*symlink)(FsContext *, const char *, const char *);
+    int (*symlink)(FsContext *, const char *, const char *, FsCred *);
     int (*link)(FsContext *, const char *, const char *);
     int (*setuid)(FsContext *, uid_t);
     int (*close)(FsContext *, int);
diff --git a/hw/virtio-9p-local.c b/hw/virtio-9p-local.c
index e0a5f58..fcc2250 100644
--- a/hw/virtio-9p-local.c
+++ b/hw/virtio-9p-local.c
@@ -107,10 +107,25 @@  static int local_post_create_passthrough(FsContext *fs_ctx, const char *path,
     return 0;
 }
 
-static ssize_t local_readlink(FsContext *ctx, const char *path,
-                                char *buf, size_t bufsz)
+static ssize_t local_readlink(FsContext *fs_ctx, const char *path,
+        char *buf, size_t bufsz)
 {
-    return readlink(rpath(ctx, path), buf, bufsz);
+    ssize_t tsize = -1;
+    if (fs_ctx->fs_sm == SM_MAPPED) {
+        int fd;
+        fd = open(rpath(fs_ctx, path), O_RDONLY);
+        if (fd == -1) {
+            return -1;
+        }
+        do {
+            tsize = read(fd, (void *)buf, bufsz);
+        } while (tsize == -1 && errno == EINTR);
+        close(fd);
+        return tsize;
+    } else if (fs_ctx->fs_sm == SM_PASSTHROUGH) {
+        tsize = readlink(rpath(fs_ctx, path), buf, bufsz);
+    }
+    return tsize;
 }
 
 static int local_close(FsContext *ctx, int fd)
@@ -314,10 +329,58 @@  err_end:
 }
 
 
-static int local_symlink(FsContext *ctx, const char *oldpath,
-                            const char *newpath)
+static int local_symlink(FsContext *fs_ctx, const char *oldpath,
+        const char *newpath, FsCred *credp)
 {
-    return symlink(oldpath, rpath(ctx, newpath));
+    int err = -1;
+    int serrno = 0;
+
+    /* Determine the security model */
+    if (fs_ctx->fs_sm == SM_MAPPED) {
+        int fd;
+        ssize_t oldpath_size, write_size;
+        fd = open(rpath(fs_ctx, newpath), O_CREAT|O_EXCL|O_RDWR,
+                SM_LOCAL_MODE_BITS);
+        if (fd == -1) {
+            return fd;
+        }
+        /* Write the oldpath (target) to the file. */
+        oldpath_size = strlen(oldpath) + 1;
+        do {
+            write_size = write(fd, (void *)oldpath, oldpath_size);
+        } while (write_size == -1 && errno == EINTR);
+
+        if (write_size != oldpath_size) {
+            serrno = errno;
+            close(fd);
+            err = -1;
+            goto err_end;
+        }
+        close(fd);
+        /* Set cleint credentials in symlink's xattr */
+        credp->fc_mode = credp->fc_mode|S_IFLNK;
+        err = local_set_xattr(rpath(fs_ctx, newpath), credp);
+        if (err == -1) {
+            serrno = errno;
+            goto err_end;
+        }
+    } else if (fs_ctx->fs_sm == SM_PASSTHROUGH) {
+        err = symlink(oldpath, rpath(fs_ctx, newpath));
+        if (err) {
+            return err;
+        }
+        err = local_post_create_passthrough(fs_ctx, newpath, credp);
+        if (err == -1) {
+            serrno = errno;
+            goto err_end;
+        }
+    }
+    return err;
+
+err_end:
+    remove(rpath(fs_ctx, newpath));
+    errno = serrno;
+    return err;
 }
 
 static int local_link(FsContext *ctx, const char *oldpath, const char *newpath)
diff --git a/hw/virtio-9p.c b/hw/virtio-9p.c
index 005f725..1a25e96 100644
--- a/hw/virtio-9p.c
+++ b/hw/virtio-9p.c
@@ -199,10 +199,15 @@  static int v9fs_do_open2(V9fsState *s, V9fsCreateState *vs)
     return s->ops->open2(&s->ctx, vs->fullname.data, flags, &cred);
 }
 
-static int v9fs_do_symlink(V9fsState *s, V9fsString *oldpath,
-                            V9fsString *newpath)
+static int v9fs_do_symlink(V9fsState *s, V9fsCreateState *vs)
 {
-    return s->ops->symlink(&s->ctx, oldpath->data, newpath->data);
+    FsCred cred;
+    cred_init(&cred);
+    cred.fc_uid = vs->fidp->uid;
+    cred.fc_mode = vs->perm | 0777;
+
+    return s->ops->symlink(&s->ctx, vs->extension.data, vs->fullname.data,
+            &cred);
 }
 
 static int v9fs_do_link(V9fsState *s, V9fsString *oldpath, V9fsString *newpath)
@@ -1785,7 +1790,7 @@  static void v9fs_create_post_lstat(V9fsState *s, V9fsCreateState *vs, int err)
         err = v9fs_do_mkdir(s, vs);
         v9fs_create_post_mkdir(s, vs, err);
     } else if (vs->perm & P9_STAT_MODE_SYMLINK) {
-        err = v9fs_do_symlink(s, &vs->extension, &vs->fullname);
+        err = v9fs_do_symlink(s, vs);
         v9fs_create_post_perms(s, vs, err);
     } else if (vs->perm & P9_STAT_MODE_LINK) {
         int32_t nfid = atoi(vs->extension.data);