mirror of
https://github.com/containers/fuse-overlayfs.git
synced 2025-08-03 18:05:58 -04:00
Merge pull request #237 from giuseppe/check-ENAMETOOLONG
main: prevent ENAMETOOLONG for whiteout files
This commit is contained in:
commit
04ed72d155
101
main.c
101
main.c
@ -145,6 +145,7 @@ open_by_handle_at (int mount_fd, struct file_handle *handle, int flags)
|
|||||||
#define PRIVILEGED_OPAQUE_XATTR "trusted.overlay.opaque"
|
#define PRIVILEGED_OPAQUE_XATTR "trusted.overlay.opaque"
|
||||||
#define PRIVILEGED_ORIGIN_XATTR "trusted.overlay.origin"
|
#define PRIVILEGED_ORIGIN_XATTR "trusted.overlay.origin"
|
||||||
#define OPAQUE_WHITEOUT ".wh..wh..opq"
|
#define OPAQUE_WHITEOUT ".wh..wh..opq"
|
||||||
|
#define WHITEOUT_MAX_LEN (sizeof (".wh.")-1)
|
||||||
|
|
||||||
#if !defined FICLONE && defined __linux__
|
#if !defined FICLONE && defined __linux__
|
||||||
# define FICLONE _IOW (0x94, 9, int)
|
# define FICLONE _IOW (0x94, 9, int)
|
||||||
@ -1365,7 +1366,7 @@ make_ovl_node (struct ovl_data *lo, const char *path, struct ovl_layer *layer, c
|
|||||||
int r;
|
int r;
|
||||||
|
|
||||||
r = it->ds->file_exists (it, whiteout_path);
|
r = it->ds->file_exists (it, whiteout_path);
|
||||||
if (r < 0 && errno != ENOENT && errno != ENOTDIR)
|
if (r < 0 && errno != ENOENT && errno != ENOTDIR && errno != ENAMETOOLONG)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
if (r == 0)
|
if (r == 0)
|
||||||
@ -1546,7 +1547,7 @@ load_dir (struct ovl_data *lo, struct ovl_node *n, struct ovl_layer *layer, char
|
|||||||
stop_lookup = true;
|
stop_lookup = true;
|
||||||
|
|
||||||
ret = it->ds->file_exists (it, parent_whiteout_path);
|
ret = it->ds->file_exists (it, parent_whiteout_path);
|
||||||
if (ret < 0 && errno != ENOENT && errno != ENOTDIR)
|
if (ret < 0 && errno != ENOENT && errno != ENOTDIR && errno != ENAMETOOLONG)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
if (ret == 0)
|
if (ret == 0)
|
||||||
@ -1600,7 +1601,7 @@ load_dir (struct ovl_data *lo, struct ovl_node *n, struct ovl_layer *layer, char
|
|||||||
strconcat3 (node_path, PATH_MAX, n->path, "/", dent->d_name);
|
strconcat3 (node_path, PATH_MAX, n->path, "/", dent->d_name);
|
||||||
|
|
||||||
ret = it->ds->file_exists (it, whiteout_path);
|
ret = it->ds->file_exists (it, whiteout_path);
|
||||||
if (ret < 0 && errno != ENOENT && errno != ENOTDIR)
|
if (ret < 0 && errno != ENOENT && errno != ENOTDIR && errno != ENAMETOOLONG)
|
||||||
{
|
{
|
||||||
it->ds->closedir (dp);
|
it->ds->closedir (dp);
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -1908,7 +1909,7 @@ do_lookup_file (struct ovl_data *lo, fuse_ino_t parent, const char *name)
|
|||||||
strconcat3 (whpath, PATH_MAX, pnode->path, "/.wh.", name);
|
strconcat3 (whpath, PATH_MAX, pnode->path, "/.wh.", name);
|
||||||
|
|
||||||
ret = it->ds->file_exists (it, whpath);
|
ret = it->ds->file_exists (it, whpath);
|
||||||
if (ret < 0 && errno != ENOENT && errno != ENOTDIR)
|
if (ret < 0 && errno != ENOENT && errno != ENOTDIR && errno != ENAMETOOLONG)
|
||||||
return NULL;
|
return NULL;
|
||||||
if (ret == 0)
|
if (ret == 0)
|
||||||
{
|
{
|
||||||
@ -1937,7 +1938,7 @@ do_lookup_file (struct ovl_data *lo, fuse_ino_t parent, const char *name)
|
|||||||
|
|
||||||
strconcat3 (whpath, PATH_MAX, pnode->path, "/.wh.", name);
|
strconcat3 (whpath, PATH_MAX, pnode->path, "/.wh.", name);
|
||||||
ret = it->ds->file_exists (it, whpath);
|
ret = it->ds->file_exists (it, whpath);
|
||||||
if (ret < 0 && errno != ENOENT && errno != ENOTDIR)
|
if (ret < 0 && errno != ENOENT && errno != ENOTDIR && errno != ENAMETOOLONG)
|
||||||
return NULL;
|
return NULL;
|
||||||
if (ret == 0)
|
if (ret == 0)
|
||||||
node = make_whiteout_node (path, name);
|
node = make_whiteout_node (path, name);
|
||||||
@ -3582,6 +3583,43 @@ do_getattr (fuse_req_t req, struct fuse_entry_param *e, struct ovl_node *node, i
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
do_statfs (struct ovl_data *lo, struct statvfs *sfs)
|
||||||
|
{
|
||||||
|
int ret, fd;
|
||||||
|
|
||||||
|
fd = get_first_layer (lo)->fd;
|
||||||
|
|
||||||
|
if (fd >= 0)
|
||||||
|
ret = fstatvfs (fd, sfs);
|
||||||
|
else
|
||||||
|
ret = statvfs (lo->mountpoint, sfs);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
sfs->f_namemax -= WHITEOUT_MAX_LEN;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static short
|
||||||
|
get_fs_namemax (struct ovl_data *lo)
|
||||||
|
{
|
||||||
|
static short namemax = 0;
|
||||||
|
if (namemax == 0)
|
||||||
|
{
|
||||||
|
struct statvfs sfs;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = do_statfs (lo, &sfs);
|
||||||
|
/* On errors use a sane default. */
|
||||||
|
if (ret < 0)
|
||||||
|
namemax = 255 - WHITEOUT_MAX_LEN;
|
||||||
|
else
|
||||||
|
namemax = sfs.f_namemax;
|
||||||
|
}
|
||||||
|
return namemax;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
ovl_create (fuse_req_t req, fuse_ino_t parent, const char *name,
|
ovl_create (fuse_req_t req, fuse_ino_t parent, const char *name,
|
||||||
mode_t mode, struct fuse_file_info *fi)
|
mode_t mode, struct fuse_file_info *fi)
|
||||||
@ -3590,12 +3628,19 @@ ovl_create (fuse_req_t req, fuse_ino_t parent, const char *name,
|
|||||||
cleanup_close int fd = -1;
|
cleanup_close int fd = -1;
|
||||||
struct fuse_entry_param e;
|
struct fuse_entry_param e;
|
||||||
struct ovl_node *node = NULL;
|
struct ovl_node *node = NULL;
|
||||||
|
struct ovl_data *lo = ovl_data (req);
|
||||||
struct stat st;
|
struct stat st;
|
||||||
|
|
||||||
if (UNLIKELY (ovl_debug (req)))
|
if (UNLIKELY (ovl_debug (req)))
|
||||||
fprintf (stderr, "ovl_create(parent=%" PRIu64 ", name=%s)\n",
|
fprintf (stderr, "ovl_create(parent=%" PRIu64 ", name=%s)\n",
|
||||||
parent, name);
|
parent, name);
|
||||||
|
|
||||||
|
if (strlen (name) > get_fs_namemax (lo))
|
||||||
|
{
|
||||||
|
fuse_reply_err (req, ENAMETOOLONG);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
fi->flags = fi->flags | O_CREAT;
|
fi->flags = fi->flags | O_CREAT;
|
||||||
|
|
||||||
fd = ovl_do_open (req, parent, name, fi->flags, mode, &node, &st);
|
fd = ovl_do_open (req, parent, name, fi->flags, mode, &node, &st);
|
||||||
@ -3868,6 +3913,12 @@ ovl_link (fuse_req_t req, fuse_ino_t ino, fuse_ino_t newparent, const char *newn
|
|||||||
if (UNLIKELY (ovl_debug (req)))
|
if (UNLIKELY (ovl_debug (req)))
|
||||||
fprintf (stderr, "ovl_link(ino=%" PRIu64 "s, newparent=%" PRIu64 "s, newname=%s)\n", ino, newparent, newname);
|
fprintf (stderr, "ovl_link(ino=%" PRIu64 "s, newparent=%" PRIu64 "s, newname=%s)\n", ino, newparent, newname);
|
||||||
|
|
||||||
|
if (strlen (newname) > get_fs_namemax (lo))
|
||||||
|
{
|
||||||
|
fuse_reply_err (req, ENAMETOOLONG);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
node = do_lookup_file (lo, ino, NULL);
|
node = do_lookup_file (lo, ino, NULL);
|
||||||
if (node == NULL || node->whiteout)
|
if (node == NULL || node->whiteout)
|
||||||
{
|
{
|
||||||
@ -4007,6 +4058,12 @@ ovl_symlink (fuse_req_t req, const char *link, fuse_ino_t parent, const char *na
|
|||||||
if (UNLIKELY (ovl_debug (req)))
|
if (UNLIKELY (ovl_debug (req)))
|
||||||
fprintf (stderr, "ovl_symlink(link=%s, ino=%" PRIu64 "s, name=%s)\n", link, parent, name);
|
fprintf (stderr, "ovl_symlink(link=%s, ino=%" PRIu64 "s, name=%s)\n", link, parent, name);
|
||||||
|
|
||||||
|
if (strlen (name) > get_fs_namemax (lo))
|
||||||
|
{
|
||||||
|
fuse_reply_err (req, ENAMETOOLONG);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
pnode = do_lookup_file (lo, parent, NULL);
|
pnode = do_lookup_file (lo, parent, NULL);
|
||||||
if (pnode == NULL || pnode->whiteout)
|
if (pnode == NULL || pnode->whiteout)
|
||||||
{
|
{
|
||||||
@ -4410,9 +4467,17 @@ ovl_rename (fuse_req_t req, fuse_ino_t parent, const char *name,
|
|||||||
unsigned int flags)
|
unsigned int flags)
|
||||||
{
|
{
|
||||||
cleanup_lock int l = enter_big_lock ();
|
cleanup_lock int l = enter_big_lock ();
|
||||||
|
struct ovl_data *lo = ovl_data (req);
|
||||||
|
|
||||||
if (UNLIKELY (ovl_debug (req)))
|
if (UNLIKELY (ovl_debug (req)))
|
||||||
fprintf (stderr, "ovl_rename(ino=%" PRIu64 "s, name=%s , ino=%" PRIu64 "s, name=%s)\n", parent, name, newparent, newname);
|
fprintf (stderr, "ovl_rename(ino=%" PRIu64 "s, name=%s , ino=%" PRIu64 "s, name=%s)\n", parent, name, newparent, newname);
|
||||||
|
|
||||||
|
if (strlen (newname) > get_fs_namemax (lo))
|
||||||
|
{
|
||||||
|
fuse_reply_err (req, ENAMETOOLONG);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (flags & RENAME_EXCHANGE)
|
if (flags & RENAME_EXCHANGE)
|
||||||
ovl_rename_exchange (req, parent, name, newparent, newname, flags);
|
ovl_rename_exchange (req, parent, name, newparent, newname, flags);
|
||||||
else
|
else
|
||||||
@ -4422,24 +4487,17 @@ ovl_rename (fuse_req_t req, fuse_ino_t parent, const char *name,
|
|||||||
static void
|
static void
|
||||||
ovl_statfs (fuse_req_t req, fuse_ino_t ino)
|
ovl_statfs (fuse_req_t req, fuse_ino_t ino)
|
||||||
{
|
{
|
||||||
int ret, fd;
|
int ret;
|
||||||
struct statvfs sfs;
|
struct statvfs sfs;
|
||||||
struct ovl_data *lo = ovl_data (req);
|
struct ovl_data *lo = ovl_data (req);
|
||||||
|
|
||||||
if (UNLIKELY (ovl_debug (req)))
|
ret = do_statfs (lo, &sfs);
|
||||||
fprintf (stderr, "ovl_statfs(ino=%" PRIu64 "s)\n", ino);
|
|
||||||
|
|
||||||
fd = get_first_layer (lo)->fd;
|
|
||||||
|
|
||||||
if (fd >= 0)
|
|
||||||
ret = fstatvfs (fd, &sfs);
|
|
||||||
else
|
|
||||||
ret = statvfs (lo->mountpoint, &sfs);
|
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
{
|
{
|
||||||
fuse_reply_err (req, errno);
|
fuse_reply_err (req, errno);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
fuse_reply_statfs (req, &sfs);
|
fuse_reply_statfs (req, &sfs);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4551,6 +4609,12 @@ ovl_mknod (fuse_req_t req, fuse_ino_t parent, const char *name, mode_t mode, dev
|
|||||||
fprintf (stderr, "ovl_mknod(ino=%" PRIu64 ", name=%s, mode=%d, rdev=%lu)\n",
|
fprintf (stderr, "ovl_mknod(ino=%" PRIu64 ", name=%s, mode=%d, rdev=%lu)\n",
|
||||||
parent, name, mode, rdev);
|
parent, name, mode, rdev);
|
||||||
|
|
||||||
|
if (strlen (name) > get_fs_namemax (lo))
|
||||||
|
{
|
||||||
|
fuse_reply_err (req, ENAMETOOLONG);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
mode = mode & ~ctx->umask;
|
mode = mode & ~ctx->umask;
|
||||||
|
|
||||||
node = do_lookup_file (lo, parent, name);
|
node = do_lookup_file (lo, parent, name);
|
||||||
@ -4661,6 +4725,13 @@ ovl_mkdir (fuse_req_t req, fuse_ino_t parent, const char *name, mode_t mode)
|
|||||||
fprintf (stderr, "ovl_mkdir(ino=%" PRIu64 ", name=%s, mode=%d)\n",
|
fprintf (stderr, "ovl_mkdir(ino=%" PRIu64 ", name=%s, mode=%d)\n",
|
||||||
parent, name, mode);
|
parent, name, mode);
|
||||||
|
|
||||||
|
|
||||||
|
if (strlen (name) > get_fs_namemax (lo))
|
||||||
|
{
|
||||||
|
fuse_reply_err (req, ENAMETOOLONG);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
node = do_lookup_file (lo, parent, name);
|
node = do_lookup_file (lo, parent, name);
|
||||||
if (node != NULL && !node->whiteout)
|
if (node != NULL && !node->whiteout)
|
||||||
{
|
{
|
||||||
|
@ -188,3 +188,14 @@ mkdir merged/adir
|
|||||||
touch -h -d "2020-01-02 10:11:12" merged/adir
|
touch -h -d "2020-01-02 10:11:12" merged/adir
|
||||||
stat --format "%y" merged/adir | grep "10:11:12"
|
stat --format "%y" merged/adir | grep "10:11:12"
|
||||||
stat --format "%x" merged/adir | grep "10:11:12"
|
stat --format "%x" merged/adir | grep "10:11:12"
|
||||||
|
|
||||||
|
upper_max_filename_len=$(stat -f -c %l upper)
|
||||||
|
merged_max_filename_len=$(stat -f -c %l merged)
|
||||||
|
|
||||||
|
test $merged_max_filename_len -lt $upper_max_filename_len
|
||||||
|
|
||||||
|
if touch merged/$(printf %${upper_max_filename_len}s | tr ' ' A}); then
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
touch merged/$(printf %${merged_max_filename_len}s | tr ' ' A})
|
||||||
|
Loading…
x
Reference in New Issue
Block a user