Don't rely on mkdir returning EEXISTS (fixing NFS)
For NFS mounts if we call mkdir() on a read-only mount (such as when we've created a read-only bind mount) the kernel will nor return EEXIST even when the directory exists, instead returning EROFS. So, we add (and use) an ensure_dir() helper that stats before calling mkdir. Closes: #258 Approved by: giuseppe
This commit is contained in:

committed by
Atomic Bot

parent
3c488585bd
commit
1e90a18a08
16
bubblewrap.c
16
bubblewrap.c
@@ -980,7 +980,7 @@ setup_newroot (bool unshare_pid,
|
||||
case SETUP_BIND_MOUNT:
|
||||
if (source_mode == S_IFDIR)
|
||||
{
|
||||
if (mkdir (dest, 0755) != 0 && errno != EEXIST)
|
||||
if (ensure_dir (dest, 0755) != 0)
|
||||
die_with_error ("Can't mkdir %s", op->dest);
|
||||
}
|
||||
else if (ensure_file (dest, 0666) != 0)
|
||||
@@ -999,7 +999,7 @@ setup_newroot (bool unshare_pid,
|
||||
break;
|
||||
|
||||
case SETUP_MOUNT_PROC:
|
||||
if (mkdir (dest, 0755) != 0 && errno != EEXIST)
|
||||
if (ensure_dir (dest, 0755) != 0)
|
||||
die_with_error ("Can't mkdir %s", op->dest);
|
||||
|
||||
if (unshare_pid)
|
||||
@@ -1036,7 +1036,7 @@ setup_newroot (bool unshare_pid,
|
||||
break;
|
||||
|
||||
case SETUP_MOUNT_DEV:
|
||||
if (mkdir (dest, 0755) != 0 && errno != EEXIST)
|
||||
if (ensure_dir (dest, 0755) != 0)
|
||||
die_with_error ("Can't mkdir %s", op->dest);
|
||||
|
||||
privileged_op (privileged_op_socket,
|
||||
@@ -1112,7 +1112,7 @@ setup_newroot (bool unshare_pid,
|
||||
break;
|
||||
|
||||
case SETUP_MOUNT_TMPFS:
|
||||
if (mkdir (dest, 0755) != 0 && errno != EEXIST)
|
||||
if (ensure_dir (dest, 0755) != 0)
|
||||
die_with_error ("Can't mkdir %s", op->dest);
|
||||
|
||||
privileged_op (privileged_op_socket,
|
||||
@@ -1121,7 +1121,7 @@ setup_newroot (bool unshare_pid,
|
||||
break;
|
||||
|
||||
case SETUP_MOUNT_MQUEUE:
|
||||
if (mkdir (dest, 0755) != 0 && errno != EEXIST)
|
||||
if (ensure_dir (dest, 0755) != 0)
|
||||
die_with_error ("Can't mkdir %s", op->dest);
|
||||
|
||||
privileged_op (privileged_op_socket,
|
||||
@@ -1130,7 +1130,7 @@ setup_newroot (bool unshare_pid,
|
||||
break;
|
||||
|
||||
case SETUP_MAKE_DIR:
|
||||
if (mkdir (dest, 0755) != 0 && errno != EEXIST)
|
||||
if (ensure_dir (dest, 0755) != 0)
|
||||
die_with_error ("Can't mkdir %s", op->dest);
|
||||
|
||||
break;
|
||||
@@ -2081,11 +2081,11 @@ main (int argc,
|
||||
/* We need *some* mountpoint where we can mount the root tmpfs.
|
||||
We first try in /run, and if that fails, try in /tmp. */
|
||||
base_path = xasprintf ("/run/user/%d/.bubblewrap", real_uid);
|
||||
if (mkdir (base_path, 0755) && errno != EEXIST)
|
||||
if (ensure_dir (base_path, 0755))
|
||||
{
|
||||
free (base_path);
|
||||
base_path = xasprintf ("/tmp/.bubblewrap-%d", real_uid);
|
||||
if (mkdir (base_path, 0755) && errno != EEXIST)
|
||||
if (ensure_dir (base_path, 0755))
|
||||
die_with_error ("Creating root mountpoint failed");
|
||||
}
|
||||
|
||||
|
41
utils.c
41
utils.c
@@ -434,7 +434,7 @@ ensure_file (const char *path,
|
||||
|
||||
/* We check this ahead of time, otherwise
|
||||
the create file will fail in the read-only
|
||||
case with EROFD instead of EEXIST */
|
||||
case with EROFS instead of EEXIST */
|
||||
if (stat (path, &buf) == 0 &&
|
||||
S_ISREG (buf.st_mode))
|
||||
return 0;
|
||||
@@ -593,6 +593,34 @@ get_file_mode (const char *pathname)
|
||||
return buf.st_mode & S_IFMT;
|
||||
}
|
||||
|
||||
int
|
||||
ensure_dir (const char *path,
|
||||
mode_t mode)
|
||||
{
|
||||
struct stat buf;
|
||||
|
||||
/* We check this ahead of time, otherwise
|
||||
the mkdir call can fail in the read-only
|
||||
case with EROFS instead of EEXIST on some
|
||||
filesystems (such as NFS) */
|
||||
if (stat (path, &buf) == 0)
|
||||
{
|
||||
if (!S_ISDIR (buf.st_mode))
|
||||
{
|
||||
errno = ENOTDIR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (mkdir (path, mode) == -1 && errno != EEXIST)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Sets errno on error (!= 0) */
|
||||
int
|
||||
mkdir_with_parents (const char *pathname,
|
||||
@@ -601,7 +629,6 @@ mkdir_with_parents (const char *pathname,
|
||||
{
|
||||
cleanup_free char *fn = NULL;
|
||||
char *p;
|
||||
struct stat buf;
|
||||
|
||||
if (pathname == NULL || *pathname == '\0')
|
||||
{
|
||||
@@ -628,16 +655,8 @@ mkdir_with_parents (const char *pathname,
|
||||
if (!create_last && p == NULL)
|
||||
break;
|
||||
|
||||
if (stat (fn, &buf) != 0)
|
||||
{
|
||||
if (mkdir (fn, mode) == -1 && errno != EEXIST)
|
||||
if (ensure_dir (fn, mode) != 0)
|
||||
return -1;
|
||||
}
|
||||
else if (!S_ISDIR (buf.st_mode))
|
||||
{
|
||||
errno = ENOTDIR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (p)
|
||||
{
|
||||
|
Reference in New Issue
Block a user