cachepc-qemu

Fork of AMDESE/qemu with changes for cachepc side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-qemu
Log | Files | Refs | Submodules | LICENSE | sfeed.txt

9p-synth.c (17304B)


      1/*
      2 * 9p synthetic file system support
      3 *
      4 * Copyright IBM, Corp. 2011
      5 *
      6 * Authors:
      7 *  Malahal Naineni <malahal@us.ibm.com>
      8 *  Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
      9 *
     10 * This work is licensed under the terms of the GNU GPL, version 2.  See
     11 * the COPYING file in the top-level directory.
     12 *
     13 */
     14
     15/*
     16 * Not so fast! You might want to read the 9p developer docs first:
     17 * https://wiki.qemu.org/Documentation/9p
     18 */
     19
     20#include "qemu/osdep.h"
     21#include "9p.h"
     22#include "fsdev/qemu-fsdev.h"
     23#include "9p-synth.h"
     24#include "qemu/rcu.h"
     25#include "qemu/rcu_queue.h"
     26#include "qemu/cutils.h"
     27#include "sysemu/qtest.h"
     28
     29/* Root node for synth file system */
     30static V9fsSynthNode synth_root = {
     31    .name = "/",
     32    .actual_attr = {
     33        .mode = 0555 | S_IFDIR,
     34        .nlink = 1,
     35    },
     36    .attr = &synth_root.actual_attr,
     37};
     38
     39static QemuMutex  synth_mutex;
     40static int synth_node_count;
     41/* set to 1 when the synth fs is ready */
     42static int synth_fs;
     43
     44static V9fsSynthNode *v9fs_add_dir_node(V9fsSynthNode *parent, int mode,
     45                                        const char *name,
     46                                        V9fsSynthNodeAttr *attr, int inode)
     47{
     48    V9fsSynthNode *node;
     49
     50    /* Add directory type and remove write bits */
     51    mode = ((mode & 0777) | S_IFDIR) & ~(S_IWUSR | S_IWGRP | S_IWOTH);
     52    node = g_malloc0(sizeof(V9fsSynthNode));
     53    if (attr) {
     54        /* We are adding .. or . entries */
     55        node->attr = attr;
     56        node->attr->nlink++;
     57    } else {
     58        node->attr = &node->actual_attr;
     59        node->attr->inode = inode;
     60        node->attr->nlink = 1;
     61        /* We don't allow write to directories */
     62        node->attr->mode   = mode;
     63        node->attr->write = NULL;
     64        node->attr->read  = NULL;
     65    }
     66    node->private = node;
     67    pstrcpy(node->name, sizeof(node->name), name);
     68    QLIST_INSERT_HEAD_RCU(&parent->child, node, sibling);
     69    return node;
     70}
     71
     72int qemu_v9fs_synth_mkdir(V9fsSynthNode *parent, int mode,
     73                          const char *name, V9fsSynthNode **result)
     74{
     75    int ret;
     76    V9fsSynthNode *node, *tmp;
     77
     78    if (!synth_fs) {
     79        return EAGAIN;
     80    }
     81    if (!name || (strlen(name) >= NAME_MAX)) {
     82        return EINVAL;
     83    }
     84    if (!parent) {
     85        parent = &synth_root;
     86    }
     87    QEMU_LOCK_GUARD(&synth_mutex);
     88    QLIST_FOREACH(tmp, &parent->child, sibling) {
     89        if (!strcmp(tmp->name, name)) {
     90            ret = EEXIST;
     91            return ret;
     92        }
     93    }
     94    /* Add the name */
     95    node = v9fs_add_dir_node(parent, mode, name, NULL, synth_node_count++);
     96    v9fs_add_dir_node(node, parent->attr->mode, "..",
     97                      parent->attr, parent->attr->inode);
     98    v9fs_add_dir_node(node, node->attr->mode, ".",
     99                      node->attr, node->attr->inode);
    100    *result = node;
    101    ret = 0;
    102    return ret;
    103}
    104
    105int qemu_v9fs_synth_add_file(V9fsSynthNode *parent, int mode,
    106                             const char *name, v9fs_synth_read read,
    107                             v9fs_synth_write write, void *arg)
    108{
    109    int ret;
    110    V9fsSynthNode *node, *tmp;
    111
    112    if (!synth_fs) {
    113        return EAGAIN;
    114    }
    115    if (!name || (strlen(name) >= NAME_MAX)) {
    116        return EINVAL;
    117    }
    118    if (!parent) {
    119        parent = &synth_root;
    120    }
    121
    122    QEMU_LOCK_GUARD(&synth_mutex);
    123    QLIST_FOREACH(tmp, &parent->child, sibling) {
    124        if (!strcmp(tmp->name, name)) {
    125            ret = EEXIST;
    126            return ret;
    127        }
    128    }
    129    /* Add file type and remove write bits */
    130    mode = ((mode & 0777) | S_IFREG);
    131    node = g_malloc0(sizeof(V9fsSynthNode));
    132    node->attr         = &node->actual_attr;
    133    node->attr->inode  = synth_node_count++;
    134    node->attr->nlink  = 1;
    135    node->attr->read   = read;
    136    node->attr->write  = write;
    137    node->attr->mode   = mode;
    138    node->private      = arg;
    139    pstrcpy(node->name, sizeof(node->name), name);
    140    QLIST_INSERT_HEAD_RCU(&parent->child, node, sibling);
    141    ret = 0;
    142    return ret;
    143}
    144
    145static void synth_fill_statbuf(V9fsSynthNode *node, struct stat *stbuf)
    146{
    147    stbuf->st_dev = 0;
    148    stbuf->st_ino = node->attr->inode;
    149    stbuf->st_mode = node->attr->mode;
    150    stbuf->st_nlink = node->attr->nlink;
    151    stbuf->st_uid = 0;
    152    stbuf->st_gid = 0;
    153    stbuf->st_rdev = 0;
    154    stbuf->st_size = 0;
    155    stbuf->st_blksize = 0;
    156    stbuf->st_blocks = 0;
    157    stbuf->st_atime = 0;
    158    stbuf->st_mtime = 0;
    159    stbuf->st_ctime = 0;
    160}
    161
    162static int synth_lstat(FsContext *fs_ctx,
    163                            V9fsPath *fs_path, struct stat *stbuf)
    164{
    165    V9fsSynthNode *node = *(V9fsSynthNode **)fs_path->data;
    166
    167    synth_fill_statbuf(node, stbuf);
    168    return 0;
    169}
    170
    171static int synth_fstat(FsContext *fs_ctx, int fid_type,
    172                            V9fsFidOpenState *fs, struct stat *stbuf)
    173{
    174    V9fsSynthOpenState *synth_open = fs->private;
    175    synth_fill_statbuf(synth_open->node, stbuf);
    176    return 0;
    177}
    178
    179static int synth_opendir(FsContext *ctx,
    180                             V9fsPath *fs_path, V9fsFidOpenState *fs)
    181{
    182    V9fsSynthOpenState *synth_open;
    183    V9fsSynthNode *node = *(V9fsSynthNode **)fs_path->data;
    184
    185    synth_open = g_malloc(sizeof(*synth_open));
    186    synth_open->node = node;
    187    node->open_count++;
    188    fs->private = synth_open;
    189    return 0;
    190}
    191
    192static int synth_closedir(FsContext *ctx, V9fsFidOpenState *fs)
    193{
    194    V9fsSynthOpenState *synth_open = fs->private;
    195    V9fsSynthNode *node = synth_open->node;
    196
    197    node->open_count--;
    198    g_free(synth_open);
    199    fs->private = NULL;
    200    return 0;
    201}
    202
    203static off_t synth_telldir(FsContext *ctx, V9fsFidOpenState *fs)
    204{
    205    V9fsSynthOpenState *synth_open = fs->private;
    206    return synth_open->offset;
    207}
    208
    209static void synth_seekdir(FsContext *ctx, V9fsFidOpenState *fs, off_t off)
    210{
    211    V9fsSynthOpenState *synth_open = fs->private;
    212    synth_open->offset = off;
    213}
    214
    215static void synth_rewinddir(FsContext *ctx, V9fsFidOpenState *fs)
    216{
    217    synth_seekdir(ctx, fs, 0);
    218}
    219
    220static void synth_direntry(V9fsSynthNode *node,
    221                                struct dirent *entry, off_t off)
    222{
    223    strcpy(entry->d_name, node->name);
    224    entry->d_ino = node->attr->inode;
    225    entry->d_off = off + 1;
    226}
    227
    228static struct dirent *synth_get_dentry(V9fsSynthNode *dir,
    229                                            struct dirent *entry, off_t off)
    230{
    231    int i = 0;
    232    V9fsSynthNode *node;
    233
    234    rcu_read_lock();
    235    QLIST_FOREACH(node, &dir->child, sibling) {
    236        /* This is the off child of the directory */
    237        if (i == off) {
    238            break;
    239        }
    240        i++;
    241    }
    242    rcu_read_unlock();
    243    if (!node) {
    244        /* end of directory */
    245        return NULL;
    246    }
    247    synth_direntry(node, entry, off);
    248    return entry;
    249}
    250
    251static struct dirent *synth_readdir(FsContext *ctx, V9fsFidOpenState *fs)
    252{
    253    struct dirent *entry;
    254    V9fsSynthOpenState *synth_open = fs->private;
    255    V9fsSynthNode *node = synth_open->node;
    256    entry = synth_get_dentry(node, &synth_open->dent, synth_open->offset);
    257    if (entry) {
    258        synth_open->offset++;
    259    }
    260    return entry;
    261}
    262
    263static int synth_open(FsContext *ctx, V9fsPath *fs_path,
    264                           int flags, V9fsFidOpenState *fs)
    265{
    266    V9fsSynthOpenState *synth_open;
    267    V9fsSynthNode *node = *(V9fsSynthNode **)fs_path->data;
    268
    269    synth_open = g_malloc(sizeof(*synth_open));
    270    synth_open->node = node;
    271    node->open_count++;
    272    fs->private = synth_open;
    273    return 0;
    274}
    275
    276static int synth_open2(FsContext *fs_ctx, V9fsPath *dir_path,
    277                            const char *name, int flags,
    278                            FsCred *credp, V9fsFidOpenState *fs)
    279{
    280    errno = ENOSYS;
    281    return -1;
    282}
    283
    284static int synth_close(FsContext *ctx, V9fsFidOpenState *fs)
    285{
    286    V9fsSynthOpenState *synth_open = fs->private;
    287    V9fsSynthNode *node = synth_open->node;
    288
    289    node->open_count--;
    290    g_free(synth_open);
    291    fs->private = NULL;
    292    return 0;
    293}
    294
    295static ssize_t synth_pwritev(FsContext *ctx, V9fsFidOpenState *fs,
    296                                  const struct iovec *iov,
    297                                  int iovcnt, off_t offset)
    298{
    299    int i, count = 0, wcount;
    300    V9fsSynthOpenState *synth_open = fs->private;
    301    V9fsSynthNode *node = synth_open->node;
    302    if (!node->attr->write) {
    303        errno = EPERM;
    304        return -1;
    305    }
    306    for (i = 0; i < iovcnt; i++) {
    307        wcount = node->attr->write(iov[i].iov_base, iov[i].iov_len,
    308                                   offset, node->private);
    309        offset += wcount;
    310        count  += wcount;
    311        /* If we wrote less than requested. we are done */
    312        if (wcount < iov[i].iov_len) {
    313            break;
    314        }
    315    }
    316    return count;
    317}
    318
    319static ssize_t synth_preadv(FsContext *ctx, V9fsFidOpenState *fs,
    320                                 const struct iovec *iov,
    321                                 int iovcnt, off_t offset)
    322{
    323    int i, count = 0, rcount;
    324    V9fsSynthOpenState *synth_open = fs->private;
    325    V9fsSynthNode *node = synth_open->node;
    326    if (!node->attr->read) {
    327        errno = EPERM;
    328        return -1;
    329    }
    330    for (i = 0; i < iovcnt; i++) {
    331        rcount = node->attr->read(iov[i].iov_base, iov[i].iov_len,
    332                                  offset, node->private);
    333        offset += rcount;
    334        count  += rcount;
    335        /* If we read less than requested. we are done */
    336        if (rcount < iov[i].iov_len) {
    337            break;
    338        }
    339    }
    340    return count;
    341}
    342
    343static int synth_truncate(FsContext *ctx, V9fsPath *path, off_t offset)
    344{
    345    errno = ENOSYS;
    346    return -1;
    347}
    348
    349static int synth_chmod(FsContext *fs_ctx, V9fsPath *path, FsCred *credp)
    350{
    351    errno = EPERM;
    352    return -1;
    353}
    354
    355static int synth_mknod(FsContext *fs_ctx, V9fsPath *path,
    356                       const char *buf, FsCred *credp)
    357{
    358    errno = EPERM;
    359    return -1;
    360}
    361
    362static int synth_mkdir(FsContext *fs_ctx, V9fsPath *path,
    363                       const char *buf, FsCred *credp)
    364{
    365    errno = EPERM;
    366    return -1;
    367}
    368
    369static ssize_t synth_readlink(FsContext *fs_ctx, V9fsPath *path,
    370                                   char *buf, size_t bufsz)
    371{
    372    errno = ENOSYS;
    373    return -1;
    374}
    375
    376static int synth_symlink(FsContext *fs_ctx, const char *oldpath,
    377                              V9fsPath *newpath, const char *buf, FsCred *credp)
    378{
    379    errno = EPERM;
    380    return -1;
    381}
    382
    383static int synth_link(FsContext *fs_ctx, V9fsPath *oldpath,
    384                           V9fsPath *newpath, const char *buf)
    385{
    386    errno = EPERM;
    387    return -1;
    388}
    389
    390static int synth_rename(FsContext *ctx, const char *oldpath,
    391                             const char *newpath)
    392{
    393    errno = EPERM;
    394    return -1;
    395}
    396
    397static int synth_chown(FsContext *fs_ctx, V9fsPath *path, FsCred *credp)
    398{
    399    errno = EPERM;
    400    return -1;
    401}
    402
    403static int synth_utimensat(FsContext *fs_ctx, V9fsPath *path,
    404                                const struct timespec *buf)
    405{
    406    errno = EPERM;
    407    return 0;
    408}
    409
    410static int synth_remove(FsContext *ctx, const char *path)
    411{
    412    errno = EPERM;
    413    return -1;
    414}
    415
    416static int synth_fsync(FsContext *ctx, int fid_type,
    417                            V9fsFidOpenState *fs, int datasync)
    418{
    419    errno = ENOSYS;
    420    return 0;
    421}
    422
    423static int synth_statfs(FsContext *s, V9fsPath *fs_path,
    424                             struct statfs *stbuf)
    425{
    426    stbuf->f_type = 0xABCD;
    427    stbuf->f_bsize = 512;
    428    stbuf->f_blocks = 0;
    429    stbuf->f_files = synth_node_count;
    430    stbuf->f_namelen = NAME_MAX;
    431    return 0;
    432}
    433
    434static ssize_t synth_lgetxattr(FsContext *ctx, V9fsPath *path,
    435                                    const char *name, void *value, size_t size)
    436{
    437    errno = ENOTSUP;
    438    return -1;
    439}
    440
    441static ssize_t synth_llistxattr(FsContext *ctx, V9fsPath *path,
    442                                     void *value, size_t size)
    443{
    444    errno = ENOTSUP;
    445    return -1;
    446}
    447
    448static int synth_lsetxattr(FsContext *ctx, V9fsPath *path,
    449                                const char *name, void *value,
    450                                size_t size, int flags)
    451{
    452    errno = ENOTSUP;
    453    return -1;
    454}
    455
    456static int synth_lremovexattr(FsContext *ctx,
    457                                   V9fsPath *path, const char *name)
    458{
    459    errno = ENOTSUP;
    460    return -1;
    461}
    462
    463static int synth_name_to_path(FsContext *ctx, V9fsPath *dir_path,
    464                                   const char *name, V9fsPath *target)
    465{
    466    V9fsSynthNode *node;
    467    V9fsSynthNode *dir_node;
    468
    469    /* "." and ".." are not allowed */
    470    if (!strcmp(name, ".") || !strcmp(name, "..")) {
    471        errno = EINVAL;
    472        return -1;
    473
    474    }
    475    if (!dir_path) {
    476        dir_node = &synth_root;
    477    } else {
    478        dir_node = *(V9fsSynthNode **)dir_path->data;
    479    }
    480    if (!strcmp(name, "/")) {
    481        node = dir_node;
    482        goto out;
    483    }
    484    /* search for the name in the childern */
    485    rcu_read_lock();
    486    QLIST_FOREACH(node, &dir_node->child, sibling) {
    487        if (!strcmp(node->name, name)) {
    488            break;
    489        }
    490    }
    491    rcu_read_unlock();
    492
    493    if (!node) {
    494        errno = ENOENT;
    495        return -1;
    496    }
    497out:
    498    /* Copy the node pointer to fid */
    499    g_free(target->data);
    500    target->data = g_memdup(&node, sizeof(void *));
    501    target->size = sizeof(void *);
    502    return 0;
    503}
    504
    505static int synth_renameat(FsContext *ctx, V9fsPath *olddir,
    506                               const char *old_name, V9fsPath *newdir,
    507                               const char *new_name)
    508{
    509    errno = EPERM;
    510    return -1;
    511}
    512
    513static int synth_unlinkat(FsContext *ctx, V9fsPath *dir,
    514                               const char *name, int flags)
    515{
    516    errno = EPERM;
    517    return -1;
    518}
    519
    520static ssize_t v9fs_synth_qtest_write(void *buf, int len, off_t offset,
    521                                      void *arg)
    522{
    523    return 1;
    524}
    525
    526static ssize_t v9fs_synth_qtest_flush_write(void *buf, int len, off_t offset,
    527                                            void *arg)
    528{
    529    bool should_block = !!*(uint8_t *)buf;
    530
    531    if (should_block) {
    532        /* This will cause the server to call us again until we're cancelled */
    533        errno = EINTR;
    534        return -1;
    535    }
    536
    537    return 1;
    538}
    539
    540static int synth_init(FsContext *ctx, Error **errp)
    541{
    542    QLIST_INIT(&synth_root.child);
    543    qemu_mutex_init(&synth_mutex);
    544
    545    /* Add "." and ".." entries for root */
    546    v9fs_add_dir_node(&synth_root, synth_root.attr->mode,
    547                      "..", synth_root.attr, synth_root.attr->inode);
    548    v9fs_add_dir_node(&synth_root, synth_root.attr->mode,
    549                      ".", synth_root.attr, synth_root.attr->inode);
    550
    551    /* Mark the subsystem is ready for use */
    552    synth_fs = 1;
    553
    554    if (qtest_enabled()) {
    555        V9fsSynthNode *node = NULL;
    556        int i, ret;
    557
    558        /* Directory hierarchy for WALK test */
    559        for (i = 0; i < P9_MAXWELEM; i++) {
    560            char *name = g_strdup_printf(QTEST_V9FS_SYNTH_WALK_FILE, i);
    561
    562            ret = qemu_v9fs_synth_mkdir(node, 0700, name, &node);
    563            assert(!ret);
    564            g_free(name);
    565        }
    566
    567        /* File for LOPEN test */
    568        ret = qemu_v9fs_synth_add_file(NULL, 0, QTEST_V9FS_SYNTH_LOPEN_FILE,
    569                                       NULL, NULL, ctx);
    570        assert(!ret);
    571
    572        /* File for WRITE test */
    573        ret = qemu_v9fs_synth_add_file(NULL, 0, QTEST_V9FS_SYNTH_WRITE_FILE,
    574                                       NULL, v9fs_synth_qtest_write, ctx);
    575        assert(!ret);
    576
    577        /* File for FLUSH test */
    578        ret = qemu_v9fs_synth_add_file(NULL, 0, QTEST_V9FS_SYNTH_FLUSH_FILE,
    579                                       NULL, v9fs_synth_qtest_flush_write,
    580                                       ctx);
    581        assert(!ret);
    582
    583        /* Directory for READDIR test */
    584        {
    585            V9fsSynthNode *dir = NULL;
    586            ret = qemu_v9fs_synth_mkdir(
    587                NULL, 0700, QTEST_V9FS_SYNTH_READDIR_DIR, &dir
    588            );
    589            assert(!ret);
    590            for (i = 0; i < QTEST_V9FS_SYNTH_READDIR_NFILES; ++i) {
    591                char *name = g_strdup_printf(
    592                    QTEST_V9FS_SYNTH_READDIR_FILE, i
    593                );
    594                ret = qemu_v9fs_synth_add_file(
    595                    dir, 0, name, NULL, NULL, ctx
    596                );
    597                assert(!ret);
    598                g_free(name);
    599            }
    600        }
    601    }
    602
    603    return 0;
    604}
    605
    606FileOperations synth_ops = {
    607    .init         = synth_init,
    608    .lstat        = synth_lstat,
    609    .readlink     = synth_readlink,
    610    .close        = synth_close,
    611    .closedir     = synth_closedir,
    612    .open         = synth_open,
    613    .opendir      = synth_opendir,
    614    .rewinddir    = synth_rewinddir,
    615    .telldir      = synth_telldir,
    616    .readdir      = synth_readdir,
    617    .seekdir      = synth_seekdir,
    618    .preadv       = synth_preadv,
    619    .pwritev      = synth_pwritev,
    620    .chmod        = synth_chmod,
    621    .mknod        = synth_mknod,
    622    .mkdir        = synth_mkdir,
    623    .fstat        = synth_fstat,
    624    .open2        = synth_open2,
    625    .symlink      = synth_symlink,
    626    .link         = synth_link,
    627    .truncate     = synth_truncate,
    628    .rename       = synth_rename,
    629    .chown        = synth_chown,
    630    .utimensat    = synth_utimensat,
    631    .remove       = synth_remove,
    632    .fsync        = synth_fsync,
    633    .statfs       = synth_statfs,
    634    .lgetxattr    = synth_lgetxattr,
    635    .llistxattr   = synth_llistxattr,
    636    .lsetxattr    = synth_lsetxattr,
    637    .lremovexattr = synth_lremovexattr,
    638    .name_to_path = synth_name_to_path,
    639    .renameat     = synth_renameat,
    640    .unlinkat     = synth_unlinkat,
    641};