Statistics
| Branch: | Revision:

root / hw / virtio-9p-local.c @ fc22118d

History | View | Annotate | Download (14 kB)

1
/*
2
 * Virtio 9p Posix callback
3
 *
4
 * Copyright IBM, Corp. 2010
5
 *
6
 * Authors:
7
 *  Anthony Liguori   <aliguori@us.ibm.com>
8
 *
9
 * This work is licensed under the terms of the GNU GPL, version 2.  See
10
 * the COPYING file in the top-level directory.
11
 *
12
 */
13
#include "virtio.h"
14
#include "virtio-9p.h"
15
#include "virtio-9p-xattr.h"
16
#include <arpa/inet.h>
17
#include <pwd.h>
18
#include <grp.h>
19
#include <sys/socket.h>
20
#include <sys/un.h>
21
#include <attr/xattr.h>
22

    
23

    
24
static int local_lstat(FsContext *fs_ctx, const char *path, struct stat *stbuf)
25
{
26
    int err;
27
    err =  lstat(rpath(fs_ctx, path), stbuf);
28
    if (err) {
29
        return err;
30
    }
31
    if (fs_ctx->fs_sm == SM_MAPPED) {
32
        /* Actual credentials are part of extended attrs */
33
        uid_t tmp_uid;
34
        gid_t tmp_gid;
35
        mode_t tmp_mode;
36
        dev_t tmp_dev;
37
        if (getxattr(rpath(fs_ctx, path), "user.virtfs.uid", &tmp_uid,
38
                    sizeof(uid_t)) > 0) {
39
            stbuf->st_uid = tmp_uid;
40
        }
41
        if (getxattr(rpath(fs_ctx, path), "user.virtfs.gid", &tmp_gid,
42
                    sizeof(gid_t)) > 0) {
43
            stbuf->st_gid = tmp_gid;
44
        }
45
        if (getxattr(rpath(fs_ctx, path), "user.virtfs.mode", &tmp_mode,
46
                    sizeof(mode_t)) > 0) {
47
            stbuf->st_mode = tmp_mode;
48
        }
49
        if (getxattr(rpath(fs_ctx, path), "user.virtfs.rdev", &tmp_dev,
50
                        sizeof(dev_t)) > 0) {
51
                stbuf->st_rdev = tmp_dev;
52
        }
53
    }
54
    return err;
55
}
56

    
57
static int local_set_xattr(const char *path, FsCred *credp)
58
{
59
    int err;
60
    if (credp->fc_uid != -1) {
61
        err = setxattr(path, "user.virtfs.uid", &credp->fc_uid, sizeof(uid_t),
62
                0);
63
        if (err) {
64
            return err;
65
        }
66
    }
67
    if (credp->fc_gid != -1) {
68
        err = setxattr(path, "user.virtfs.gid", &credp->fc_gid, sizeof(gid_t),
69
                0);
70
        if (err) {
71
            return err;
72
        }
73
    }
74
    if (credp->fc_mode != -1) {
75
        err = setxattr(path, "user.virtfs.mode", &credp->fc_mode,
76
                sizeof(mode_t), 0);
77
        if (err) {
78
            return err;
79
        }
80
    }
81
    if (credp->fc_rdev != -1) {
82
        err = setxattr(path, "user.virtfs.rdev", &credp->fc_rdev,
83
                sizeof(dev_t), 0);
84
        if (err) {
85
            return err;
86
        }
87
    }
88
    return 0;
89
}
90

    
91
static int local_post_create_passthrough(FsContext *fs_ctx, const char *path,
92
        FsCred *credp)
93
{
94
    if (chmod(rpath(fs_ctx, path), credp->fc_mode & 07777) < 0) {
95
        return -1;
96
    }
97
    if (lchown(rpath(fs_ctx, path), credp->fc_uid, credp->fc_gid) < 0) {
98
        /*
99
         * If we fail to change ownership and if we are
100
         * using security model none. Ignore the error
101
         */
102
        if (fs_ctx->fs_sm != SM_NONE) {
103
            return -1;
104
        }
105
    }
106
    return 0;
107
}
108

    
109
static ssize_t local_readlink(FsContext *fs_ctx, const char *path,
110
        char *buf, size_t bufsz)
111
{
112
    ssize_t tsize = -1;
113
    if (fs_ctx->fs_sm == SM_MAPPED) {
114
        int fd;
115
        fd = open(rpath(fs_ctx, path), O_RDONLY);
116
        if (fd == -1) {
117
            return -1;
118
        }
119
        do {
120
            tsize = read(fd, (void *)buf, bufsz);
121
        } while (tsize == -1 && errno == EINTR);
122
        close(fd);
123
        return tsize;
124
    } else if ((fs_ctx->fs_sm == SM_PASSTHROUGH) ||
125
               (fs_ctx->fs_sm == SM_NONE)) {
126
        tsize = readlink(rpath(fs_ctx, path), buf, bufsz);
127
    }
128
    return tsize;
129
}
130

    
131
static int local_close(FsContext *ctx, int fd)
132
{
133
    return close(fd);
134
}
135

    
136
static int local_closedir(FsContext *ctx, DIR *dir)
137
{
138
    return closedir(dir);
139
}
140

    
141
static int local_open(FsContext *ctx, const char *path, int flags)
142
{
143
    return open(rpath(ctx, path), flags);
144
}
145

    
146
static DIR *local_opendir(FsContext *ctx, const char *path)
147
{
148
    return opendir(rpath(ctx, path));
149
}
150

    
151
static void local_rewinddir(FsContext *ctx, DIR *dir)
152
{
153
    return rewinddir(dir);
154
}
155

    
156
static off_t local_telldir(FsContext *ctx, DIR *dir)
157
{
158
    return telldir(dir);
159
}
160

    
161
static struct dirent *local_readdir(FsContext *ctx, DIR *dir)
162
{
163
    return readdir(dir);
164
}
165

    
166
static void local_seekdir(FsContext *ctx, DIR *dir, off_t off)
167
{
168
    return seekdir(dir, off);
169
}
170

    
171
static ssize_t local_readv(FsContext *ctx, int fd, const struct iovec *iov,
172
                            int iovcnt)
173
{
174
    return readv(fd, iov, iovcnt);
175
}
176

    
177
static off_t local_lseek(FsContext *ctx, int fd, off_t offset, int whence)
178
{
179
    return lseek(fd, offset, whence);
180
}
181

    
182
static ssize_t local_writev(FsContext *ctx, int fd, const struct iovec *iov,
183
                            int iovcnt)
184
{
185
    return writev(fd, iov, iovcnt);
186
}
187

    
188
static int local_chmod(FsContext *fs_ctx, const char *path, FsCred *credp)
189
{
190
    if (fs_ctx->fs_sm == SM_MAPPED) {
191
        return local_set_xattr(rpath(fs_ctx, path), credp);
192
    } else if ((fs_ctx->fs_sm == SM_PASSTHROUGH) ||
193
               (fs_ctx->fs_sm == SM_NONE)) {
194
        return chmod(rpath(fs_ctx, path), credp->fc_mode);
195
    }
196
    return -1;
197
}
198

    
199
static int local_mknod(FsContext *fs_ctx, const char *path, FsCred *credp)
200
{
201
    int err = -1;
202
    int serrno = 0;
203

    
204
    /* Determine the security model */
205
    if (fs_ctx->fs_sm == SM_MAPPED) {
206
        err = mknod(rpath(fs_ctx, path), SM_LOCAL_MODE_BITS|S_IFREG, 0);
207
        if (err == -1) {
208
            return err;
209
        }
210
        local_set_xattr(rpath(fs_ctx, path), credp);
211
        if (err == -1) {
212
            serrno = errno;
213
            goto err_end;
214
        }
215
    } else if ((fs_ctx->fs_sm == SM_PASSTHROUGH) ||
216
               (fs_ctx->fs_sm == SM_NONE)) {
217
        err = mknod(rpath(fs_ctx, path), credp->fc_mode, credp->fc_rdev);
218
        if (err == -1) {
219
            return err;
220
        }
221
        err = local_post_create_passthrough(fs_ctx, path, credp);
222
        if (err == -1) {
223
            serrno = errno;
224
            goto err_end;
225
        }
226
    }
227
    return err;
228

    
229
err_end:
230
    remove(rpath(fs_ctx, path));
231
    errno = serrno;
232
    return err;
233
}
234

    
235
static int local_mkdir(FsContext *fs_ctx, const char *path, FsCred *credp)
236
{
237
    int err = -1;
238
    int serrno = 0;
239

    
240
    /* Determine the security model */
241
    if (fs_ctx->fs_sm == SM_MAPPED) {
242
        err = mkdir(rpath(fs_ctx, path), SM_LOCAL_DIR_MODE_BITS);
243
        if (err == -1) {
244
            return err;
245
        }
246
        credp->fc_mode = credp->fc_mode|S_IFDIR;
247
        err = local_set_xattr(rpath(fs_ctx, path), credp);
248
        if (err == -1) {
249
            serrno = errno;
250
            goto err_end;
251
        }
252
    } else if ((fs_ctx->fs_sm == SM_PASSTHROUGH) ||
253
               (fs_ctx->fs_sm == SM_NONE)) {
254
        err = mkdir(rpath(fs_ctx, path), credp->fc_mode);
255
        if (err == -1) {
256
            return err;
257
        }
258
        err = local_post_create_passthrough(fs_ctx, path, credp);
259
        if (err == -1) {
260
            serrno = errno;
261
            goto err_end;
262
        }
263
    }
264
    return err;
265

    
266
err_end:
267
    remove(rpath(fs_ctx, path));
268
    errno = serrno;
269
    return err;
270
}
271

    
272
static int local_fstat(FsContext *fs_ctx, int fd, struct stat *stbuf)
273
{
274
    int err;
275
    err = fstat(fd, stbuf);
276
    if (err) {
277
        return err;
278
    }
279
    if (fs_ctx->fs_sm == SM_MAPPED) {
280
        /* Actual credentials are part of extended attrs */
281
        uid_t tmp_uid;
282
        gid_t tmp_gid;
283
        mode_t tmp_mode;
284
        dev_t tmp_dev;
285

    
286
        if (fgetxattr(fd, "user.virtfs.uid", &tmp_uid, sizeof(uid_t)) > 0) {
287
            stbuf->st_uid = tmp_uid;
288
        }
289
        if (fgetxattr(fd, "user.virtfs.gid", &tmp_gid, sizeof(gid_t)) > 0) {
290
            stbuf->st_gid = tmp_gid;
291
        }
292
        if (fgetxattr(fd, "user.virtfs.mode", &tmp_mode, sizeof(mode_t)) > 0) {
293
            stbuf->st_mode = tmp_mode;
294
        }
295
        if (fgetxattr(fd, "user.virtfs.rdev", &tmp_dev, sizeof(dev_t)) > 0) {
296
                stbuf->st_rdev = tmp_dev;
297
        }
298
    }
299
    return err;
300
}
301

    
302
static int local_open2(FsContext *fs_ctx, const char *path, int flags,
303
        FsCred *credp)
304
{
305
    int fd = -1;
306
    int err = -1;
307
    int serrno = 0;
308

    
309
    /* Determine the security model */
310
    if (fs_ctx->fs_sm == SM_MAPPED) {
311
        fd = open(rpath(fs_ctx, path), flags, SM_LOCAL_MODE_BITS);
312
        if (fd == -1) {
313
            return fd;
314
        }
315
        credp->fc_mode = credp->fc_mode|S_IFREG;
316
        /* Set cleint credentials in xattr */
317
        err = local_set_xattr(rpath(fs_ctx, path), credp);
318
        if (err == -1) {
319
            serrno = errno;
320
            goto err_end;
321
        }
322
    } else if ((fs_ctx->fs_sm == SM_PASSTHROUGH) ||
323
               (fs_ctx->fs_sm == SM_NONE)) {
324
        fd = open(rpath(fs_ctx, path), flags, credp->fc_mode);
325
        if (fd == -1) {
326
            return fd;
327
        }
328
        err = local_post_create_passthrough(fs_ctx, path, credp);
329
        if (err == -1) {
330
            serrno = errno;
331
            goto err_end;
332
        }
333
    }
334
    return fd;
335

    
336
err_end:
337
    close(fd);
338
    remove(rpath(fs_ctx, path));
339
    errno = serrno;
340
    return err;
341
}
342

    
343

    
344
static int local_symlink(FsContext *fs_ctx, const char *oldpath,
345
        const char *newpath, FsCred *credp)
346
{
347
    int err = -1;
348
    int serrno = 0;
349

    
350
    /* Determine the security model */
351
    if (fs_ctx->fs_sm == SM_MAPPED) {
352
        int fd;
353
        ssize_t oldpath_size, write_size;
354
        fd = open(rpath(fs_ctx, newpath), O_CREAT|O_EXCL|O_RDWR,
355
                SM_LOCAL_MODE_BITS);
356
        if (fd == -1) {
357
            return fd;
358
        }
359
        /* Write the oldpath (target) to the file. */
360
        oldpath_size = strlen(oldpath) + 1;
361
        do {
362
            write_size = write(fd, (void *)oldpath, oldpath_size);
363
        } while (write_size == -1 && errno == EINTR);
364

    
365
        if (write_size != oldpath_size) {
366
            serrno = errno;
367
            close(fd);
368
            err = -1;
369
            goto err_end;
370
        }
371
        close(fd);
372
        /* Set cleint credentials in symlink's xattr */
373
        credp->fc_mode = credp->fc_mode|S_IFLNK;
374
        err = local_set_xattr(rpath(fs_ctx, newpath), credp);
375
        if (err == -1) {
376
            serrno = errno;
377
            goto err_end;
378
        }
379
    } else if ((fs_ctx->fs_sm == SM_PASSTHROUGH) ||
380
               (fs_ctx->fs_sm == SM_NONE)) {
381
        err = symlink(oldpath, rpath(fs_ctx, newpath));
382
        if (err) {
383
            return err;
384
        }
385
        err = lchown(rpath(fs_ctx, newpath), credp->fc_uid, credp->fc_gid);
386
        if (err == -1) {
387
            /*
388
             * If we fail to change ownership and if we are
389
             * using security model none. Ignore the error
390
             */
391
            if (fs_ctx->fs_sm != SM_NONE) {
392
                serrno = errno;
393
                goto err_end;
394
            } else
395
                err = 0;
396
        }
397
    }
398
    return err;
399

    
400
err_end:
401
    remove(rpath(fs_ctx, newpath));
402
    errno = serrno;
403
    return err;
404
}
405

    
406
static int local_link(FsContext *ctx, const char *oldpath, const char *newpath)
407
{
408
    char *tmp = qemu_strdup(rpath(ctx, oldpath));
409
    int err, serrno = 0;
410

    
411
    if (tmp == NULL) {
412
        return -ENOMEM;
413
    }
414

    
415
    err = link(tmp, rpath(ctx, newpath));
416
    if (err == -1) {
417
        serrno = errno;
418
    }
419

    
420
    qemu_free(tmp);
421

    
422
    if (err == -1) {
423
        errno = serrno;
424
    }
425

    
426
    return err;
427
}
428

    
429
static int local_truncate(FsContext *ctx, const char *path, off_t size)
430
{
431
    return truncate(rpath(ctx, path), size);
432
}
433

    
434
static int local_rename(FsContext *ctx, const char *oldpath,
435
                        const char *newpath)
436
{
437
    char *tmp;
438
    int err;
439

    
440
    tmp = qemu_strdup(rpath(ctx, oldpath));
441

    
442
    err = rename(tmp, rpath(ctx, newpath));
443
    if (err == -1) {
444
        int serrno = errno;
445
        qemu_free(tmp);
446
        errno = serrno;
447
    } else {
448
        qemu_free(tmp);
449
    }
450

    
451
    return err;
452

    
453
}
454

    
455
static int local_chown(FsContext *fs_ctx, const char *path, FsCred *credp)
456
{
457
    if ((credp->fc_uid == -1 && credp->fc_gid == -1) ||
458
            (fs_ctx->fs_sm == SM_PASSTHROUGH)) {
459
        return lchown(rpath(fs_ctx, path), credp->fc_uid, credp->fc_gid);
460
    } else if (fs_ctx->fs_sm == SM_MAPPED) {
461
        return local_set_xattr(rpath(fs_ctx, path), credp);
462
    } else if ((fs_ctx->fs_sm == SM_PASSTHROUGH) ||
463
               (fs_ctx->fs_sm == SM_NONE)) {
464
        return lchown(rpath(fs_ctx, path), credp->fc_uid, credp->fc_gid);
465
    }
466
    return -1;
467
}
468

    
469
static int local_utimensat(FsContext *s, const char *path,
470
                       const struct timespec *buf)
471
{
472
    return utimensat(AT_FDCWD, rpath(s, path), buf, AT_SYMLINK_NOFOLLOW);
473
}
474

    
475
static int local_remove(FsContext *ctx, const char *path)
476
{
477
    return remove(rpath(ctx, path));
478
}
479

    
480
static int local_fsync(FsContext *ctx, int fd)
481
{
482
    return fsync(fd);
483
}
484

    
485
static int local_statfs(FsContext *s, const char *path, struct statfs *stbuf)
486
{
487
   return statfs(rpath(s, path), stbuf);
488
}
489

    
490
static ssize_t local_lgetxattr(FsContext *ctx, const char *path,
491
                               const char *name, void *value, size_t size)
492
{
493
    return v9fs_get_xattr(ctx, path, name, value, size);
494
}
495

    
496
static ssize_t local_llistxattr(FsContext *ctx, const char *path,
497
                                void *value, size_t size)
498
{
499
    return v9fs_list_xattr(ctx, path, value, size);
500
}
501

    
502
static int local_lsetxattr(FsContext *ctx, const char *path, const char *name,
503
                           void *value, size_t size, int flags)
504
{
505
    return v9fs_set_xattr(ctx, path, name, value, size, flags);
506
}
507

    
508
static int local_lremovexattr(FsContext *ctx,
509
                              const char *path, const char *name)
510
{
511
    return v9fs_remove_xattr(ctx, path, name);
512
}
513

    
514

    
515
FileOperations local_ops = {
516
    .lstat = local_lstat,
517
    .readlink = local_readlink,
518
    .close = local_close,
519
    .closedir = local_closedir,
520
    .open = local_open,
521
    .opendir = local_opendir,
522
    .rewinddir = local_rewinddir,
523
    .telldir = local_telldir,
524
    .readdir = local_readdir,
525
    .seekdir = local_seekdir,
526
    .readv = local_readv,
527
    .lseek = local_lseek,
528
    .writev = local_writev,
529
    .chmod = local_chmod,
530
    .mknod = local_mknod,
531
    .mkdir = local_mkdir,
532
    .fstat = local_fstat,
533
    .open2 = local_open2,
534
    .symlink = local_symlink,
535
    .link = local_link,
536
    .truncate = local_truncate,
537
    .rename = local_rename,
538
    .chown = local_chown,
539
    .utimensat = local_utimensat,
540
    .remove = local_remove,
541
    .fsync = local_fsync,
542
    .statfs = local_statfs,
543
    .lgetxattr = local_lgetxattr,
544
    .llistxattr = local_llistxattr,
545
    .lsetxattr = local_lsetxattr,
546
    .lremovexattr = local_lremovexattr,
547
};