[U-Boot] Remote code execution vulnerabilities in U-Boot's NFS and other IP parsing code
Fermín Serna
fermin at semmle.com
Tue Jul 23 14:02:18 UTC 2019
Of course, sorry about that.
Please note this was a quick untested patch used for highlighting the
vulnerabilities. I would start with it but most likely needs some
extra work. At this time, I would appreciate someone else to take it
form here.
See inline below.
diff --git a/net/net.c b/net/net.c
index 58b0417cbe..9957450392 100644
--- a/net/net.c
+++ b/net/net.c
@@ -1256,6 +1256,12 @@ void net_process_received_packet(uchar
*in_packet, int len)
"received UDP (to=%pI4, from=%pI4, len=%d)\n",
&dst_ip, &src_ip, len);
+ if ((ntohs(ip->udp_len) < UDP_HDR_SIZE) ||
+ (ntohs(ip->udp_len) > len)) {
+ printf(" Invalid IP->udp_len field\n");
+ return;
+ }
+
#ifdef CONFIG_UDP_CHECKSUM
if (ip->udp_xsum != 0) {
ulong xsum;
@@ -1305,6 +1311,7 @@ void net_process_received_packet(uchar
*in_packet, int len)
ntohs(ip->udp_src),
ntohs(ip->udp_len) - UDP_HDR_SIZE);
#endif
+
/*
* IP header OK. Pass the packet to the current handler.
*/
diff --git a/net/nfs.c b/net/nfs.c
index d6a7f8e827..da6fd76327 100644
--- a/net/nfs.c
+++ b/net/nfs.c
@@ -48,12 +48,12 @@
static int fs_mounted;
static unsigned long rpc_id;
static int nfs_offset = -1;
-static int nfs_len;
+static unsigned int nfs_len;
static ulong nfs_timeout = NFS_TIMEOUT;
static char dirfh[NFS_FHSIZE]; /* NFSv2 / NFSv3 file handle of directory */
static char filefh[NFS3_FHSIZE]; /* NFSv2 / NFSv3 file handle */
-static int filefh3_length; /* (variable) length of filefh when NFSv3 */
+static unsigned int filefh3_length; /* (variable) length of filefh
when NFSv3 */
static enum net_loop_state nfs_download_state;
static struct in_addr nfs_server_ip;
@@ -432,7 +432,8 @@ static int rpc_lookup_reply(int prog, uchar *pkt,
unsigned len)
{
struct rpc_t rpc_pkt;
- memcpy(&rpc_pkt.u.data[0], pkt, len);
+ memset(&rpc_pkt.u.data[0], 0, sizeof(struct rpc_t));
+ memcpy(&rpc_pkt.u.data[0], pkt, min(len, sizeof(struct rpc_t)));
debug("%s\n", __func__);
@@ -464,7 +465,8 @@ static int nfs_mount_reply(uchar *pkt, unsigned len)
debug("%s\n", __func__);
- memcpy(&rpc_pkt.u.data[0], pkt, len);
+ memset(&rpc_pkt.u.data[0], 0, sizeof(struct rpc_t));
+ memcpy(&rpc_pkt.u.data[0], pkt, min(len, sizeof(struct rpc_t)));
if (ntohl(rpc_pkt.u.reply.id) > rpc_id)
return -NFS_RPC_ERR;
@@ -490,7 +492,8 @@ static int nfs_umountall_reply(uchar *pkt, unsigned len)
debug("%s\n", __func__);
- memcpy(&rpc_pkt.u.data[0], pkt, len);
+ memset(&rpc_pkt.u.data[0], 0, sizeof(struct rpc_t));
+ memcpy(&rpc_pkt.u.data[0], pkt, min(len, sizeof(struct rpc_t)));
if (ntohl(rpc_pkt.u.reply.id) > rpc_id)
return -NFS_RPC_ERR;
@@ -514,7 +517,8 @@ static int nfs_lookup_reply(uchar *pkt, unsigned len)
debug("%s\n", __func__);
- memcpy(&rpc_pkt.u.data[0], pkt, len);
+ memset(&rpc_pkt.u.data[0], 0, sizeof(struct rpc_t));
+ memcpy(&rpc_pkt.u.data[0], pkt, min(len, sizeof(struct rpc_t)));
if (ntohl(rpc_pkt.u.reply.id) > rpc_id)
return -NFS_RPC_ERR;
@@ -608,12 +612,13 @@ static int nfs3_get_attributes_offset(uint32_t *data)
static int nfs_readlink_reply(uchar *pkt, unsigned len)
{
struct rpc_t rpc_pkt;
- int rlen;
- int nfsv3_data_offset = 0;
+ unsigned int rlen;
+ unsigned int nfsv3_data_offset = 0;
debug("%s\n", __func__);
- memcpy((unsigned char *)&rpc_pkt, pkt, len);
+ memset(&rpc_pkt.u.data[0], 0, sizeof(struct rpc_t));
+ memcpy(&rpc_pkt.u.data[0], pkt, min(len, sizeof(struct rpc_t)));
if (ntohl(rpc_pkt.u.reply.id) > rpc_id)
return -NFS_RPC_ERR;
@@ -639,15 +644,23 @@ static int nfs_readlink_reply(uchar *pkt, unsigned len)
strcat(nfs_path, "/");
pathlen = strlen(nfs_path);
+
+ if (rlen > sizeof(nfs_path_buff) - pathlen)
+ return -NFS_RPC_ERR;
+
memcpy(nfs_path + pathlen,
(uchar *)&(rpc_pkt.u.reply.data[2 + nfsv3_data_offset]),
rlen);
- nfs_path[pathlen + rlen] = 0;
+ nfs_path[pathlen + rlen - 1] = 0;
} else {
+
+ if (rlen > sizeof(nfs_path_buff))
+ return -NFS_RPC_ERR;
+
memcpy(nfs_path,
(uchar *)&(rpc_pkt.u.reply.data[2 + nfsv3_data_offset]),
rlen);
- nfs_path[rlen] = 0;
+ nfs_path[rlen - 1] = 0;
}
return 0;
}
@@ -655,12 +668,13 @@ static int nfs_readlink_reply(uchar *pkt, unsigned len)
static int nfs_read_reply(uchar *pkt, unsigned len)
{
struct rpc_t rpc_pkt;
- int rlen;
+ unsigned int rlen;
uchar *data_ptr;
debug("%s\n", __func__);
- memcpy(&rpc_pkt.u.data[0], pkt, sizeof(rpc_pkt.u.reply));
+ memset(&rpc_pkt.u.data[0], 0, sizeof(struct rpc_t));
+ memcpy(&rpc_pkt.u.data[0], pkt, min(len, sizeof(struct rpc_t)));
if (ntohl(rpc_pkt.u.reply.id) > rpc_id)
return -NFS_RPC_ERR;
@@ -687,6 +701,11 @@ static int nfs_read_reply(uchar *pkt, unsigned len)
if (supported_nfs_versions & NFSV2_FLAG) {
rlen = ntohl(rpc_pkt.u.reply.data[18]);
data_ptr = (uchar *)&(rpc_pkt.u.reply.data[19]);
+
+ // Make sure at rlen at least does not goes OOB.
+ if (rlen > sizeof(struct rpc_t) - 19 * sizeof(uint32_t))
+ return -NFS_RPC_ERR;
+
} else { /* NFSV3_FLAG */
int nfsv3_data_offset =
nfs3_get_attributes_offset(rpc_pkt.u.reply.data);
@@ -699,6 +718,11 @@ static int nfs_read_reply(uchar *pkt, unsigned len)
*/
data_ptr = (uchar *)
&(rpc_pkt.u.reply.data[4 + nfsv3_data_offset]);
+
+ // Make sure at rlen at least does not goes OOB.
+ if (rlen > sizeof(struct rpc_t) - (4 +
nfsv3_data_offset]) * sizeof(uint32_t))
+ return -NFS_RPC_ERR;
+
}
if (store_block(data_ptr, nfs_offset, rlen))
On Tue, 23 Jul 2019 at 02:10, Simon Goldschmidt
<simon.k.r.goldschmidt at gmail.com> wrote:
>
> On Tue, Jul 23, 2019 at 1:09 AM Fermín Serna <fermin at semmle.com> wrote:
> >
> > Hello,
> >
> > Find attached more information about 13 vulnerabilities we found at
> > U-Boot and its NFS and networking code. Also, find attached a proposed
> > quick patch that should serve as a first initial one and should
> > probably go through iterations of code review.
> >
> > Please note, these vulnerabilities are not patched yet at the source
> > repository. Tom Rini (U-boot's master custodian) requested the
> > attached report to be published at this mailing list. At this time,
> > and because of this email, we consider these vulnerabilities public.
>
> Would you mind sending the patch again as plain text mail so it can undergo a
> proper review process on this list?
>
> Regards,
> Simon
>
> >
> > For reference, MITRE has issued CVEs for the vulnerabilities:
> > CVE-2019-14192, CVE-2019-14193, CVE-2019-14194, CVE-2019-14195,
> > CVE-2019-14196, CVE-2019-14197, CVE-2019-14198, CVE-2019-14199,
> > CVE-2019-14200, CVE-2019-14201, CVE-2019-14202, CVE-2019-14203 and
> > CVE-2019-14204
> >
> > Best regards,
> > --
> > Fermin
> > Semmle Security Research Team
> > _______________________________________________
> > U-Boot mailing list
> > U-Boot at lists.denx.de
> > https://lists.denx.de/listinfo/u-boot
More information about the U-Boot
mailing list