Skip to content

Commit 04ed72d

Browse files
authored
Merge pull request #237 from giuseppe/check-ENAMETOOLONG
main: prevent ENAMETOOLONG for whiteout files
2 parents 421c64d + 573cfac commit 04ed72d

File tree

2 files changed

+97
-15
lines changed

2 files changed

+97
-15
lines changed

main.c

Lines changed: 86 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,7 @@ open_by_handle_at (int mount_fd, struct file_handle *handle, int flags)
145145
#define PRIVILEGED_OPAQUE_XATTR "trusted.overlay.opaque"
146146
#define PRIVILEGED_ORIGIN_XATTR "trusted.overlay.origin"
147147
#define OPAQUE_WHITEOUT ".wh..wh..opq"
148+
#define WHITEOUT_MAX_LEN (sizeof (".wh.")-1)
148149

149150
#if !defined FICLONE && defined __linux__
150151
# 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
13651366
int r;
13661367

13671368
r = it->ds->file_exists (it, whiteout_path);
1368-
if (r < 0 && errno != ENOENT && errno != ENOTDIR)
1369+
if (r < 0 && errno != ENOENT && errno != ENOTDIR && errno != ENAMETOOLONG)
13691370
return NULL;
13701371

13711372
if (r == 0)
@@ -1546,7 +1547,7 @@ load_dir (struct ovl_data *lo, struct ovl_node *n, struct ovl_layer *layer, char
15461547
stop_lookup = true;
15471548

15481549
ret = it->ds->file_exists (it, parent_whiteout_path);
1549-
if (ret < 0 && errno != ENOENT && errno != ENOTDIR)
1550+
if (ret < 0 && errno != ENOENT && errno != ENOTDIR && errno != ENAMETOOLONG)
15501551
return NULL;
15511552

15521553
if (ret == 0)
@@ -1600,7 +1601,7 @@ load_dir (struct ovl_data *lo, struct ovl_node *n, struct ovl_layer *layer, char
16001601
strconcat3 (node_path, PATH_MAX, n->path, "/", dent->d_name);
16011602

16021603
ret = it->ds->file_exists (it, whiteout_path);
1603-
if (ret < 0 && errno != ENOENT && errno != ENOTDIR)
1604+
if (ret < 0 && errno != ENOENT && errno != ENOTDIR && errno != ENAMETOOLONG)
16041605
{
16051606
it->ds->closedir (dp);
16061607
return NULL;
@@ -1908,7 +1909,7 @@ do_lookup_file (struct ovl_data *lo, fuse_ino_t parent, const char *name)
19081909
strconcat3 (whpath, PATH_MAX, pnode->path, "/.wh.", name);
19091910

19101911
ret = it->ds->file_exists (it, whpath);
1911-
if (ret < 0 && errno != ENOENT && errno != ENOTDIR)
1912+
if (ret < 0 && errno != ENOENT && errno != ENOTDIR && errno != ENAMETOOLONG)
19121913
return NULL;
19131914
if (ret == 0)
19141915
{
@@ -1937,7 +1938,7 @@ do_lookup_file (struct ovl_data *lo, fuse_ino_t parent, const char *name)
19371938

19381939
strconcat3 (whpath, PATH_MAX, pnode->path, "/.wh.", name);
19391940
ret = it->ds->file_exists (it, whpath);
1940-
if (ret < 0 && errno != ENOENT && errno != ENOTDIR)
1941+
if (ret < 0 && errno != ENOENT && errno != ENOTDIR && errno != ENAMETOOLONG)
19411942
return NULL;
19421943
if (ret == 0)
19431944
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
35823583
return 0;
35833584
}
35843585

3586+
static int
3587+
do_statfs (struct ovl_data *lo, struct statvfs *sfs)
3588+
{
3589+
int ret, fd;
3590+
3591+
fd = get_first_layer (lo)->fd;
3592+
3593+
if (fd >= 0)
3594+
ret = fstatvfs (fd, sfs);
3595+
else
3596+
ret = statvfs (lo->mountpoint, sfs);
3597+
if (ret < 0)
3598+
return ret;
3599+
3600+
sfs->f_namemax -= WHITEOUT_MAX_LEN;
3601+
return 0;
3602+
}
3603+
3604+
static short
3605+
get_fs_namemax (struct ovl_data *lo)
3606+
{
3607+
static short namemax = 0;
3608+
if (namemax == 0)
3609+
{
3610+
struct statvfs sfs;
3611+
int ret;
3612+
3613+
ret = do_statfs (lo, &sfs);
3614+
/* On errors use a sane default. */
3615+
if (ret < 0)
3616+
namemax = 255 - WHITEOUT_MAX_LEN;
3617+
else
3618+
namemax = sfs.f_namemax;
3619+
}
3620+
return namemax;
3621+
}
3622+
35853623
static void
35863624
ovl_create (fuse_req_t req, fuse_ino_t parent, const char *name,
35873625
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,
35903628
cleanup_close int fd = -1;
35913629
struct fuse_entry_param e;
35923630
struct ovl_node *node = NULL;
3631+
struct ovl_data *lo = ovl_data (req);
35933632
struct stat st;
35943633

35953634
if (UNLIKELY (ovl_debug (req)))
35963635
fprintf (stderr, "ovl_create(parent=%" PRIu64 ", name=%s)\n",
35973636
parent, name);
35983637

3638+
if (strlen (name) > get_fs_namemax (lo))
3639+
{
3640+
fuse_reply_err (req, ENAMETOOLONG);
3641+
return;
3642+
}
3643+
35993644
fi->flags = fi->flags | O_CREAT;
36003645

36013646
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
38683913
if (UNLIKELY (ovl_debug (req)))
38693914
fprintf (stderr, "ovl_link(ino=%" PRIu64 "s, newparent=%" PRIu64 "s, newname=%s)\n", ino, newparent, newname);
38703915

3916+
if (strlen (newname) > get_fs_namemax (lo))
3917+
{
3918+
fuse_reply_err (req, ENAMETOOLONG);
3919+
return;
3920+
}
3921+
38713922
node = do_lookup_file (lo, ino, NULL);
38723923
if (node == NULL || node->whiteout)
38733924
{
@@ -4007,6 +4058,12 @@ ovl_symlink (fuse_req_t req, const char *link, fuse_ino_t parent, const char *na
40074058
if (UNLIKELY (ovl_debug (req)))
40084059
fprintf (stderr, "ovl_symlink(link=%s, ino=%" PRIu64 "s, name=%s)\n", link, parent, name);
40094060

4061+
if (strlen (name) > get_fs_namemax (lo))
4062+
{
4063+
fuse_reply_err (req, ENAMETOOLONG);
4064+
return;
4065+
}
4066+
40104067
pnode = do_lookup_file (lo, parent, NULL);
40114068
if (pnode == NULL || pnode->whiteout)
40124069
{
@@ -4410,9 +4467,17 @@ ovl_rename (fuse_req_t req, fuse_ino_t parent, const char *name,
44104467
unsigned int flags)
44114468
{
44124469
cleanup_lock int l = enter_big_lock ();
4470+
struct ovl_data *lo = ovl_data (req);
4471+
44134472
if (UNLIKELY (ovl_debug (req)))
44144473
fprintf (stderr, "ovl_rename(ino=%" PRIu64 "s, name=%s , ino=%" PRIu64 "s, name=%s)\n", parent, name, newparent, newname);
44154474

4475+
if (strlen (newname) > get_fs_namemax (lo))
4476+
{
4477+
fuse_reply_err (req, ENAMETOOLONG);
4478+
return;
4479+
}
4480+
44164481
if (flags & RENAME_EXCHANGE)
44174482
ovl_rename_exchange (req, parent, name, newparent, newname, flags);
44184483
else
@@ -4422,24 +4487,17 @@ ovl_rename (fuse_req_t req, fuse_ino_t parent, const char *name,
44224487
static void
44234488
ovl_statfs (fuse_req_t req, fuse_ino_t ino)
44244489
{
4425-
int ret, fd;
4490+
int ret;
44264491
struct statvfs sfs;
44274492
struct ovl_data *lo = ovl_data (req);
44284493

4429-
if (UNLIKELY (ovl_debug (req)))
4430-
fprintf (stderr, "ovl_statfs(ino=%" PRIu64 "s)\n", ino);
4431-
4432-
fd = get_first_layer (lo)->fd;
4433-
4434-
if (fd >= 0)
4435-
ret = fstatvfs (fd, &sfs);
4436-
else
4437-
ret = statvfs (lo->mountpoint, &sfs);
4494+
ret = do_statfs (lo, &sfs);
44384495
if (ret < 0)
44394496
{
44404497
fuse_reply_err (req, errno);
44414498
return;
44424499
}
4500+
44434501
fuse_reply_statfs (req, &sfs);
44444502
}
44454503

@@ -4551,6 +4609,12 @@ ovl_mknod (fuse_req_t req, fuse_ino_t parent, const char *name, mode_t mode, dev
45514609
fprintf (stderr, "ovl_mknod(ino=%" PRIu64 ", name=%s, mode=%d, rdev=%lu)\n",
45524610
parent, name, mode, rdev);
45534611

4612+
if (strlen (name) > get_fs_namemax (lo))
4613+
{
4614+
fuse_reply_err (req, ENAMETOOLONG);
4615+
return;
4616+
}
4617+
45544618
mode = mode & ~ctx->umask;
45554619

45564620
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)
46614725
fprintf (stderr, "ovl_mkdir(ino=%" PRIu64 ", name=%s, mode=%d)\n",
46624726
parent, name, mode);
46634727

4728+
4729+
if (strlen (name) > get_fs_namemax (lo))
4730+
{
4731+
fuse_reply_err (req, ENAMETOOLONG);
4732+
return;
4733+
}
4734+
46644735
node = do_lookup_file (lo, parent, name);
46654736
if (node != NULL && !node->whiteout)
46664737
{

tests/fedora-installs.sh

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,3 +188,14 @@ mkdir merged/adir
188188
touch -h -d "2020-01-02 10:11:12" merged/adir
189189
stat --format "%y" merged/adir | grep "10:11:12"
190190
stat --format "%x" merged/adir | grep "10:11:12"
191+
192+
upper_max_filename_len=$(stat -f -c %l upper)
193+
merged_max_filename_len=$(stat -f -c %l merged)
194+
195+
test $merged_max_filename_len -lt $upper_max_filename_len
196+
197+
if touch merged/$(printf %${upper_max_filename_len}s | tr ' ' A}); then
198+
exit 1
199+
fi
200+
201+
touch merged/$(printf %${merged_max_filename_len}s | tr ' ' A})

0 commit comments

Comments
 (0)