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:
Alexander Larsson
2018-03-14 15:22:12 +01:00
committed by Atomic Bot
parent 3c488585bd
commit 1e90a18a08
3 changed files with 41 additions and 20 deletions

View File

@@ -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");
}

43
utils.c
View File

@@ -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)
return -1;
}
else if (!S_ISDIR (buf.st_mode))
{
errno = ENOTDIR;
return -1;
}
if (ensure_dir (fn, mode) != 0)
return -1;
if (p)
{

View File

@@ -101,6 +101,8 @@ int create_file (const char *path,
const char *content);
int ensure_file (const char *path,
mode_t mode);
int ensure_dir (const char *path,
mode_t mode);
int get_file_mode (const char *pathname);
int mkdir_with_parents (const char *pathname,
int mode,