Skip to content

Commit 584bca5

Browse files
committed
Remove top directory bind mounts to prevent EXDEV errors
Fixes: #9
1 parent c6dc820 commit 584bca5

File tree

3 files changed

+61
-45
lines changed

3 files changed

+61
-45
lines changed

src/nvc_mount.c

Lines changed: 50 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
#include <sys/types.h>
88

99
#include <errno.h>
10+
#include <libgen.h>
11+
#undef basename /* Use the GNU version of basename. */
1012
#include <limits.h>
1113
#include <stdio.h>
1214
#include <string.h>
@@ -20,7 +22,7 @@
2022
#include "utils.h"
2123
#include "xfuncs.h"
2224

23-
static char *mount_files(struct error *, const struct nvc_container *, const char *, char *[], size_t);
25+
static char **mount_files(struct error *, const struct nvc_container *, const char *, char *[], size_t);
2426
static char *mount_device(struct error *, const struct nvc_container *, const char *);
2527
static char *mount_ipc(struct error *, const struct nvc_container *, const char *);
2628
static char *mount_procfs(struct error *, const struct nvc_container *);
@@ -29,32 +31,32 @@ static char *mount_app_profile(struct error *, const struct nvc_container *);
2931
static int update_app_profile(struct error *, const struct nvc_container *, dev_t);
3032
static void unmount(const char *);
3133
static int setup_cgroup(struct error *, const char *, dev_t);
32-
static int symlink_library(struct error *, const char *, const char *, const char *, const char *, uid_t, gid_t);
33-
static int symlink_libraries(struct error *, const struct nvc_container *, const char *, char *[], size_t, const char *);
34+
static int symlink_library(struct error *, const char *, const char *, const char *, uid_t, gid_t);
35+
static int symlink_libraries(struct error *, const struct nvc_container *, const char * const [], size_t);
3436

35-
static char *
37+
static char **
3638
mount_files(struct error *err, const struct nvc_container *cnt, const char *dir, char *paths[], size_t size)
3739
{
3840
char path[PATH_MAX];
3941
mode_t mode;
40-
char *ptr, *mnt, *p;
42+
char *end, *file;
43+
char **mnt, **ptr;
4144

42-
/* Create the top directory under the rootfs. */
4345
if (path_resolve(err, path, cnt->cfg.rootfs, dir) < 0)
4446
return (NULL);
4547
if (file_create(err, path, NULL, cnt->uid, cnt->gid, MODE_DIR(0755)) < 0)
4648
return (NULL);
4749

48-
ptr = path + strlen(path);
49-
50-
/* Bind mount the top directory and every files under it with read-only permissions. */
51-
if (xmount(err, path, path, NULL, MS_BIND, NULL) < 0)
50+
end = path + strlen(path);
51+
mnt = ptr = array_new(err, size + 1); /* NULL terminated. */
52+
if (mnt == NULL)
5253
goto fail;
54+
5355
for (size_t i = 0; i < size; ++i) {
54-
p = basename(paths[i]);
55-
if (!match_binary_flags(p, cnt->flags) && !match_library_flags(p, cnt->flags))
56+
file = basename(paths[i]);
57+
if (!match_binary_flags(file, cnt->flags) && !match_library_flags(file, cnt->flags))
5658
continue;
57-
if (path_append(err, path, p) < 0)
59+
if (path_append(err, path, file) < 0)
5860
goto fail;
5961
if (file_mode(err, paths[i], &mode) < 0)
6062
goto fail;
@@ -66,15 +68,16 @@ mount_files(struct error *err, const struct nvc_container *cnt, const char *dir,
6668
goto fail;
6769
if (xmount(err, NULL, path, NULL, MS_BIND|MS_REMOUNT | MS_RDONLY|MS_NODEV|MS_NOSUID, NULL) < 0)
6870
goto fail;
69-
*ptr = '\0';
71+
if ((*ptr++ = xstrdup(err, path)) == NULL)
72+
goto fail;
73+
*end = '\0';
7074
}
71-
if ((mnt = xstrdup(err, path)) == NULL)
72-
goto fail;
7375
return (mnt);
7476

7577
fail:
76-
*ptr = '\0';
77-
unmount(path);
78+
for (size_t i = 0; i < size; ++i)
79+
unmount(mnt[i]);
80+
array_free(mnt, size);
7881
return (NULL);
7982
}
8083

@@ -326,41 +329,41 @@ setup_cgroup(struct error *err, const char *cgroup, dev_t id)
326329
}
327330

328331
static int
329-
symlink_library(struct error *err, const char *dir, const char *lib, const char *version, const char *linkname, uid_t uid, gid_t gid)
332+
symlink_library(struct error *err, const char *src, const char *target, const char *linkname, uid_t uid, gid_t gid)
330333
{
331334
char path[PATH_MAX];
332-
char *target;
335+
char *tmp;
333336
int rv = -1;
334337

335-
if (path_join(err, path, dir, linkname) < 0)
336-
return (-1);
337-
if (xasprintf(err, &target, "%s.%s", lib, version) < 0)
338+
if ((tmp = xstrdup(err, src)) == NULL)
338339
return (-1);
340+
if (path_join(err, path, dirname(tmp), linkname) < 0)
341+
goto fail;
339342

340343
log_infof("creating symlink %s -> %s", path, target);
341344
if (file_create(err, path, target, uid, gid, MODE_LNK(0777)) < 0)
342345
goto fail;
343346
rv = 0;
344347

345348
fail:
346-
free(target);
349+
free(tmp);
347350
return (rv);
348351
}
349352

350353
static int
351-
symlink_libraries(struct error *err, const struct nvc_container *cnt, const char *dir, char *paths[], size_t size, const char *version)
354+
symlink_libraries(struct error *err, const struct nvc_container *cnt, const char * const paths[], size_t size)
352355
{
353-
char *p;
356+
char *lib;
354357

355358
for (size_t i = 0; i < size; ++i) {
356-
p = basename(paths[i]);
357-
if ((cnt->flags & OPT_COMPUTE_LIBS) && !strpcmp(p, "libcuda.so")) {
359+
lib = basename(paths[i]);
360+
if (!strpcmp(lib, "libcuda.so")) {
358361
/* XXX Many applications wrongly assume that libcuda.so exists (e.g. with dlopen). */
359-
if (symlink_library(err, dir, "libcuda.so", version, "libcuda.so", cnt->uid, cnt->gid) < 0)
362+
if (symlink_library(err, paths[i], lib, "libcuda.so", cnt->uid, cnt->gid) < 0)
360363
return (-1);
361-
} else if ((cnt->flags & OPT_GRAPHICS_LIBS) && !strpcmp(p, "libGLX_nvidia.so")) {
364+
} else if (!strpcmp(lib, "libGLX_nvidia.so")) {
362365
/* XXX GLVND requires this symlink for indirect GLX support. */
363-
if (symlink_library(err, dir, "libGLX_nvidia.so", version, "libGLX_indirect.so.0", cnt->uid, cnt->gid) < 0)
366+
if (symlink_library(err, paths[i], lib, "libGLX_indirect.so.0", cnt->uid, cnt->gid) < 0)
364367
return (-1);
365368
}
366369
}
@@ -370,7 +373,7 @@ symlink_libraries(struct error *err, const struct nvc_container *cnt, const char
370373
int
371374
nvc_driver_mount(struct nvc_context *ctx, const struct nvc_container *cnt, const struct nvc_driver_info *info)
372375
{
373-
char **mnt, **ptr;
376+
const char **mnt, **ptr, **tmp;
374377
size_t nmnt;
375378
int rv = -1;
376379

@@ -382,8 +385,8 @@ nvc_driver_mount(struct nvc_context *ctx, const struct nvc_container *cnt, const
382385
if (nsenter(&ctx->err, cnt->mnt_ns, CLONE_NEWNS) < 0)
383386
return (-1);
384387

385-
nmnt = 5 + info->nipcs + info->ndevs;
386-
mnt = ptr = array_new(&ctx->err, nmnt);
388+
nmnt = 2 + info->nbins + info->nlibs + info->nlibs32 + info->nipcs + info->ndevs;
389+
mnt = ptr = (const char **)array_new(&ctx->err, nmnt);
387390
if (mnt == NULL)
388391
goto fail;
389392

@@ -395,25 +398,27 @@ nvc_driver_mount(struct nvc_context *ctx, const struct nvc_container *cnt, const
395398
if ((*ptr++ = mount_app_profile(&ctx->err, cnt)) == NULL)
396399
goto fail;
397400
}
398-
/* Binary and library file mounts */
401+
/* Binary and library mounts */
399402
if (info->bins != NULL && info->nbins > 0) {
400-
if ((*ptr++ = mount_files(&ctx->err, cnt, cnt->cfg.bins_dir, info->bins, info->nbins)) == NULL)
403+
if ((tmp = (const char **)mount_files(&ctx->err, cnt, cnt->cfg.bins_dir, info->bins, info->nbins)) == NULL)
401404
goto fail;
405+
ptr = array_append(ptr, tmp, array_size(tmp));
406+
free(tmp);
402407
}
403408
if (info->libs != NULL && info->nlibs > 0) {
404-
if ((*ptr = mount_files(&ctx->err, cnt, cnt->cfg.libs_dir, info->libs, info->nlibs)) == NULL)
405-
goto fail;
406-
if (symlink_libraries(&ctx->err, cnt, *ptr, info->libs, info->nlibs, info->nvrm_version) < 0)
409+
if ((tmp = (const char **)mount_files(&ctx->err, cnt, cnt->cfg.libs_dir, info->libs, info->nlibs)) == NULL)
407410
goto fail;
408-
++ptr;
411+
ptr = array_append(ptr, tmp, array_size(tmp));
412+
free(tmp);
409413
}
410414
if ((cnt->flags & OPT_COMPAT32) && info->libs32 != NULL && info->nlibs32 > 0) {
411-
if ((*ptr = mount_files(&ctx->err, cnt, cnt->cfg.libs32_dir, info->libs32, info->nlibs32)) == NULL)
415+
if ((tmp = (const char **)mount_files(&ctx->err, cnt, cnt->cfg.libs32_dir, info->libs32, info->nlibs32)) == NULL)
412416
goto fail;
413-
if (symlink_libraries(&ctx->err, cnt, *ptr, info->libs32, info->nlibs32, info->nvrm_version) < 0)
414-
goto fail;
415-
++ptr;
417+
ptr = array_append(ptr, tmp, array_size(tmp));
418+
free(tmp);
416419
}
420+
if (symlink_libraries(&ctx->err, cnt, mnt, (size_t)(ptr - mnt)) < 0)
421+
goto fail;
417422
/* IPC mounts */
418423
for (size_t i = 0; i < info->nipcs; ++i) {
419424
/* XXX Only utility libraries require persistenced IPC, everything else is compute only. */
@@ -450,7 +455,7 @@ nvc_driver_mount(struct nvc_context *ctx, const struct nvc_container *cnt, const
450455
rv = nsenterat(&ctx->err, ctx->mnt_ns, CLONE_NEWNS);
451456
}
452457

453-
array_free(mnt, nmnt);
458+
array_free((char **)mnt, nmnt);
454459
return (rv);
455460
}
456461

src/utils.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -355,6 +355,16 @@ array_pack(char *arr[], size_t *size)
355355
}
356356
}
357357

358+
size_t
359+
array_size(const char * const arr[])
360+
{
361+
size_t n = 0;
362+
363+
while (*arr++ != NULL)
364+
++n;
365+
return (n);
366+
}
367+
358368
void *
359369
file_map(struct error *err, const char *path, size_t *length)
360370
{

src/utils.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ int nsenter(struct error *, const char *, int);
5858
char **array_new(struct error *, size_t);
5959
void array_free(char *[], size_t);
6060
void array_pack(char *[], size_t *);
61+
size_t array_size(const char * const []);
6162
const char **array_append(const char **, const char * const [], size_t);
6263

6364
void *file_map(struct error *, const char *, size_t *);

0 commit comments

Comments
 (0)