From: Dan Carpenter <dan.carpenter@oracle.com>
To: dwysocha@redhat.com
Cc: linux-nfs@vger.kernel.org
Subject: [bug report] nfs: Convert to new fscache volume/cookie API
Date: Wed, 1 Dec 2021 11:54:43 +0300 [thread overview]
Message-ID: <20211201085443.GA24725@kili> (raw)
Hi Dave,
The patch 1234f5681081: "nfs: Convert to new fscache volume/cookie
API" from Nov 14, 2020, leads to the following Smatch static checker
warning:
fs/nfs/fscache.c:32 nfs_append_int()
warn: array off by one? 'key[(*_len)++]'
This is an unpublished check which assumes all > comparisons are wrong
until proven otherwise.
fs/nfs/fscache.c
27 static bool nfs_append_int(char *key, int *_len, unsigned long long x)
28 {
29 if (*_len > NFS_MAX_KEY_LEN)
30 return false;
31 if (x == 0)
--> 32 key[(*_len)++] = ',';
33 else
34 *_len += sprintf(key + *_len, ",%llx", x);
35 return true;
36 }
This function is very badly broken. As the checker suggests, the >
should be >= to prevent an array overflow. But it's actually off by
two because we have to leave space for the NUL terminator so the buffer
is full when "*_len == NFS_MAX_KEY_LEN - 1". That means the check
should be:
if (*_len >= NFS_MAX_KEY_LEN - 1)
return false;
Except NFS_MAX_KEY_LEN is not the correct limit. The buffer is larger
than that.
Unfortunately if we fixed the array overflow check then the sprintf()
will now corrupt memory... There is a missing check after the sprintf()
so it does not tell you if we printed everything or not. It just
returns true and the next caller detects the overflow.
I feel like append() functions are easier to use if we keep the start
pointer and and len value constant and just modify the *offset.
static bool nfs_append_int(char *key, int *off, int len, unsigned long long x)
{
if (*off >= len - 1)
return false;
if (x == 0)
key[(*off)++] = ',';
else
*off + snprintf(key + *off, len - *off, ",%llx", x);
if (*off >= len)
return false;
return true;
}
[ snip ]
86 void nfs_fscache_get_super_cookie(struct super_block *sb, const char *uniq, int ulen)
87 {
88 struct nfs_server *nfss = NFS_SB(sb);
89 unsigned int len = 3;
90 char *key;
91
92 if (uniq) {
93 nfss->fscache_uniq = kmemdup_nul(uniq, ulen, GFP_KERNEL);
94 if (!nfss->fscache_uniq)
95 return;
96 }
97
98 key = kmalloc(NFS_MAX_KEY_LEN + 24, GFP_KERNEL);
99 if (!key)
100 return;
101
102 memcpy(key, "nfs", 3);
103 if (!nfs_fscache_get_client_key(nfss->nfs_client, key, &len) ||
104 !nfs_append_int(key, &len, nfss->fsid.major) ||
So then we do:
len = NFS_MAX_KEY_LEN + 24;
It's not totally clear to me where the 24 comes from or I would have
sent a patch instead of a bug report.
memcpy(key, "nfs", 3);
off = 3;
if (!nfs_fscache_get_client_key(nfss->nfs_client, key, &off) ||
!nfs_append_int(key, &off, len, nfss->fsid.major) ||
!nfs_append_int(key, &off, len, nfss->fsid.minor) ||
105 !nfs_append_int(key, &len, nfss->fsid.minor) ||
106 !nfs_append_int(key, &len, sb->s_flags & NFS_SB_MASK) ||
107 !nfs_append_int(key, &len, nfss->flags) ||
108 !nfs_append_int(key, &len, nfss->rsize) ||
109 !nfs_append_int(key, &len, nfss->wsize) ||
110 !nfs_append_int(key, &len, nfss->acregmin) ||
111 !nfs_append_int(key, &len, nfss->acregmax) ||
112 !nfs_append_int(key, &len, nfss->acdirmin) ||
113 !nfs_append_int(key, &len, nfss->acdirmax) ||
114 !nfs_append_int(key, &len, nfss->client->cl_auth->au_flavor))
115 goto out;
116
117 if (ulen > 0) {
118 if (ulen > NFS_MAX_KEY_LEN - len)
This check is also off. It does not take into consideration the comma
or the NUL terminator. We need a "+ 2".
if (ulen + 2 > len - off) {
119 goto out;
120 key[len++] = ',';
121 memcpy(key + len, uniq, ulen);
122 len += ulen;
123 }
124 key[len] = 0;
125
126 /* create a cache index for looking up filehandles */
regards,
dan carpenter
next reply other threads:[~2021-12-01 8:54 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
2021-12-01 8:54 Dan Carpenter [this message]
2021-12-03 13:39 ` [bug report] nfs: Convert to new fscache volume/cookie API David Wysochanski
2021-12-03 16:06 ` David Howells
2021-12-03 20:05 ` David Wysochanski
2021-12-06 9:28 ` David Howells
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20211201085443.GA24725@kili \
--to=dan.carpenter@oracle.com \
--cc=dwysocha@redhat.com \
--cc=linux-nfs@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.