Re: broken hash use in fs/cifs/dfs_cache.c

Paulo Alcantara
2021-03-22T18:24:32Z

Al Viro <viro@zeniv.linux.org.uk> writes:

> Found while trying to untangle some... unidiomatic string handling
> in cifs:
>
> static struct cache_entry *__lookup_cache_entry(const char *path)
> {
> struct cache_entry *ce;
> unsigned int h;
> bool found = false;
>
> h = cache_entry_hash(path, strlen(path));
>
> hlist_for_each_entry(ce, &cache_htable[h], hlist) {
> if (!strcasecmp(path, ce->path)) {
> found = true;
> dump_ce(ce);
> break;
> }
> }
>
> if (!found)
> ce = ERR_PTR(-ENOENT);
> return ce;
> }
>
> combined with
>
> static inline unsigned int cache_entry_hash(const void *data, int size)
> {
> unsigned int h;
>
> h = jhash(data, size, 0);
> return h & (CACHE_HTABLE_SIZE - 1);
> }
>
> That can't possibly work. The fundamental requirement for hashes is that
> lookups for all keys matching an entry *MUST* lead to searches in the same
> hash chain. Here the test is strcasecmp(), so "foo" and "Foo" are expected
> to match the same entry. But jhash() yields different values on those -
> it's a general-purpose hash, and it doesn't give a damn about upper and
> lower case letters. Moreover, even though we look at the value modulo
> 32, I don't believe that it's going to be case-insensitive.

Good catch! Yes, it is completely broken.

> Either the key comparison or the hash function is wrong here. *IF* something
> external guarantees the full match, we don't need strcasecmp() - strcmp()
> would work. Otherwise, the hash function needs to be changed.

Agreed.

I'll look into it. Thanks!