On Tue, 2006-08-29 at 21:44 -0700, David Miller wrote: > From: Sridhar Samudrala <[EMAIL PROTECTED]> > Date: Tue, 29 Aug 2006 10:55:29 -0700 > > > verify_iovec() has the following piece of code that allows overflow > > of iov_len values in an iovec. > > > > for (ct = 0; ct < m->msg_iovlen; ct++) { > > err += iov[ct].iov_len; > > /* > > * Goal is not to verify user data, but to prevent returning > > * negative value, which is interpreted as errno. > > * Overflow is still possible, but it is harmless. > > */ > > if (err < 0) > > return -EMSGSIZE; > > } > > > > The comment specifically says that overflow is harmless, but I don't see any > > valid reason to allow overflow. > > > > Also, iov_len is of type size_t which is a 64-bit value on 64-bit systems, > > but we store and return the overall iovec length in an int. > > Just some notes so that it is understood the context in which > such changes are being proposed. > > First of all, several memcpy() and copy_{to,from}_user() > implementations BUG trap on lengths which have bit 31 or higher set. > It always indicates a bug of some sort in the call chain, so behaving > as if we support larger than positive signed 32-bit lengths here is > probably asking for trouble. > > Also, the protocol downcalls all return "int", not "long" so it's even > impossible to report successful sending of larger than positive signed > 32-bit lengths. Even kernel_sendmsg() and friends return "int". > > We can pretend that larger than positive signed 32-bit lengths in an > iovec will work, but they surely won't. > > And since the sendmsg() man page was quoted: > > If the message is too long to pass atomically through the underlying > protocol, the error EMSGSIZE is returned, and the message is not > trans$,1rp > mitted. > > which matches perfectly with the fact that the protocol downcalls > return "int" not "size_t" nor "ssize_t".
OK. So the maximum message size that can be supported via sendmsg/recvmsg is limited to INT_MAX. Then i think we should limit each iov_len value and the sum of all iov_len values to INT_MAX. It looks like copy_{to,from}_user() support upto LONG_MAX but most of the networking routines return only an int. Currently if we pass an iovec with 2 iov_len values 0x7fffffff and 0x80000002, verify_iovec returns a total length as 1 and we proceed without any error with a truncated user message. The following patch avoids overflow of iov_len values beyond INT_MAX. diff --git a/net/compat.c b/net/compat.c index d5d69fa..e8f5345 100644 --- a/net/compat.c +++ b/net/compat.c @@ -44,7 +44,11 @@ static inline int iov_from_user_compat_t tot_len = -EFAULT; break; } + if (unlikely(len > INT_MAX)) + return -EMSGSIZE; tot_len += len; + if (unlikely(tot_len < 0)) + return -EMSGSIZE; kiov->iov_base = compat_ptr(buf); kiov->iov_len = (__kernel_size_t) len; uiov32++; diff --git a/net/core/iovec.c b/net/core/iovec.c index 65e4b56..ee5a265 100644 --- a/net/core/iovec.c +++ b/net/core/iovec.c @@ -61,11 +61,12 @@ int verify_iovec(struct msghdr *m, struc err = 0; for (ct = 0; ct < m->msg_iovlen; ct++) { + if (unlikely(iov[ct].iov_len > INT_MAX)) + return -EMSGSIZE; err += iov[ct].iov_len; /* * Goal is not to verify user data, but to prevent returning * negative value, which is interpreted as errno. - * Overflow is still possible, but it is harmless. */ if (err < 0) return -EMSGSIZE; - To unsubscribe from this list: send the line "unsubscribe netdev" in the body of a message to [EMAIL PROTECTED] More majordomo info at http://vger.kernel.org/majordomo-info.html