History

Make filldir[64]() verify the directory entry filename is valid

This has been discussed several times, and now filesystem people are talking about doing it individually at the filesystem layer, so head that off at the pass and just do it in getdents{64}(). This is partially based on a patch by Jann Horn, but checks for NUL bytes as well, and somewhat simplified. There's also commentary about how it might be better if invalid names due to filesystem corruption don't cause an immediate failure, but only an error at the end of the readdir(), so that people can still see the filenames that are ok. There's also been discussion about just how much POSIX strictly speaking requires this since it's about filesystem corruption. It's really more "protect user space from bad behavior" as pointed out by Jann. But since Eric Biederman looked up the POSIX wording, here it is for context: "From readdir: The readdir() function shall return a pointer to a structure representing the directory entry at the current position in the directory stream specified by the argument dirp, and position the directory stream at the next entry. It shall return a null pointer upon reaching the end of the directory stream. The structure dirent defined in the <dirent.h> header describes a directory entry. From definitions: 3.129 Directory Entry (or Link) An object that associates a filename with a file. Several directory entries can associate names with the same file. ... 3.169 Filename A name consisting of 1 to {NAME_MAX} bytes used to name a file. The characters composing the name may be selected from the set of all character values excluding the slash character and the null byte. The filenames dot and dot-dot have special meaning. A filename is sometimes referred to as a 'pathname component'." Note that I didn't bother adding the checks to any legacy interfaces that nobody uses. Also note that if this ends up being noticeable as a performance regression, we can fix that to do a much more optimized model that checks for both NUL and '/' at the same time one word at a time. We haven't really tended to optimize 'memchr()', and it only checks for one pattern at a time anyway, and we really _should_ check for NUL too (but see the comment about "soft errors" in the code about why it currently only checks for '/') See the CONFIG_DCACHE_WORD_ACCESS case of hash_name() for how the name lookup code looks for pathname terminating characters in parallel.

Linus Torvalds committed 7 years ago

Commit 8a23eb81 parent 9f79b781 file · +40 −0Browse files

Unified · Split

fs/readdir.c+40−0
@@ -118,6 +118,40 @@ out: · 117 unmodified lines
118}118}
119EXPORT_SYMBOL(iterate_dir);119EXPORT_SYMBOL(iterate_dir);
120 120
121/*
122 * POSIX says that a dirent name cannot contain NULL or a '/'.
123 *
124 * It's not 100% clear what we should really do in this case.
125 * The filesystem is clearly corrupted, but returning a hard
126 * error means that you now don't see any of the other names
127 * either, so that isn't a perfect alternative.
128 *
129 * And if you return an error, what error do you use? Several
130 * filesystems seem to have decided on EUCLEAN being the error
131 * code for EFSCORRUPTED, and that may be the error to use. Or
132 * just EIO, which is perhaps more obvious to users.
133 *
134 * In order to see the other file names in the directory, the
135 * caller might want to make this a "soft" error: skip the
136 * entry, and return the error at the end instead.
137 *
138 * Note that this should likely do a "memchr(name, 0, len)"
139 * check too, since that would be filesystem corruption as
140 * well. However, that case can't actually confuse user space,
141 * which has to do a strlen() on the name anyway to find the
142 * filename length, and the above "soft error" worry means
143 * that it's probably better left alone until we have that
144 * issue clarified.
145 */
146static int verify_dirent_name(const char *name, int len)
147{
148 if (WARN_ON_ONCE(!len))
149 return -EIO;
150 if (WARN_ON_ONCE(memchr(name, '/', len)))
151 return -EIO;
152 return 0;
153}
154
121/*155/*
122 * Traditional linux readdir() handling..156 * Traditional linux readdir() handling..
123 *157 *
@@ -227,6 +261,9 @@ static int filldir(struct dir_context *ctx, const char *name, int namlen, · 103 unmodified lines
227 int reclen = ALIGN(offsetof(struct linux_dirent, d_name) + namlen + 2,261 int reclen = ALIGN(offsetof(struct linux_dirent, d_name) + namlen + 2,
228 sizeof(long));262 sizeof(long));
229 263
264 buf->error = verify_dirent_name(name, namlen);
265 if (unlikely(buf->error))
266 return buf->error;
230 buf->error = -EINVAL; /* only used if we fail.. */267 buf->error = -EINVAL; /* only used if we fail.. */
231 if (reclen > buf->count)268 if (reclen > buf->count)
232 return -EINVAL;269 return -EINVAL;
@@ -316,6 +353,9 @@ static int filldir64(struct dir_context *ctx, const char *name, int namlen, · 83 unmodified lines
316 int reclen = ALIGN(offsetof(struct linux_dirent64, d_name) + namlen + 1,353 int reclen = ALIGN(offsetof(struct linux_dirent64, d_name) + namlen + 1,
317 sizeof(u64));354 sizeof(u64));
318 355
356 buf->error = verify_dirent_name(name, namlen);
357 if (unlikely(buf->error))
358 return buf->error;
319 buf->error = -EINVAL; /* only used if we fail.. */359 buf->error = -EINVAL; /* only used if we fail.. */
320 if (reclen > buf->count)360 if (reclen > buf->count)
321 return -EINVAL;361 return -EINVAL;