shithub: opusfile

Download patch

ref: d0c82543d55f1f5938460022777301b8de023bc9
parent: cc69f7efa898d0ffd547bddbabf50881a790fbe5
author: Timothy B. Terriberry <tterribe@xiph.org>
date: Fri Sep 16 11:41:27 EDT 2016

Fix MSVC warnings.

Some of these pointed to real potential overflows (given arbitrary
 inputs by the calling application).
I was sad about stripping const qualifiers from the struct addrinfo
 pointers, but MSVC seems to erroneously think that an array of
 pointers to constant data is itself a pointer to constant data (or
 maybe that it is not compatible with a const void *?), and
 converting the memmove()s to for loops triggered an erroneous
 warning about out-of-bounds array accesses in gcc (but on only one
 of the two identical loops).

--- a/src/http.c
+++ b/src/http.c
@@ -307,6 +307,12 @@
    operate on sockets, because we don't use non-socket I/O here, and this
    minimizes the changes needed to deal with Winsock.*/
 #  define close(_fd) closesocket(_fd)
+/*This takes an int for the address length, even though the value is of type
+   socklen_t (defined as an unsigned integer type with at least 32 bits).*/
+#  define connect(_fd,_addr,_addrlen) \
+ (OP_UNLIKELY((_addrlen)>(socklen_t)INT_MAX)? \
+  WSASetLastError(WSA_NOT_ENOUGH_MEMORY),-1: \
+  connect(_fd,_addr,(int)(_addrlen)))
 /*This relies on sizeof(u_long)==sizeof(int), which is always true on both
    Win32 and Win64.*/
 #  define ioctl(_fd,_req,_arg) ioctlsocket(_fd,_req,(u_long *)(_arg))
@@ -471,7 +477,7 @@
   scheme_end=_src+strspn(_src,OP_URL_SCHEME);
   if(OP_UNLIKELY(*scheme_end!=':')
    ||OP_UNLIKELY(scheme_end-_src<4)||OP_UNLIKELY(scheme_end-_src>5)
-   ||OP_UNLIKELY(op_strncasecmp(_src,"https",scheme_end-_src)!=0)){
+   ||OP_UNLIKELY(op_strncasecmp(_src,"https",(int)(scheme_end-_src))!=0)){
     /*Unsupported protocol.*/
     return OP_EIMPL;
   }
@@ -674,7 +680,10 @@
 }
 
 static int op_sb_append_string(OpusStringBuf *_sb,const char *_s){
-  return op_sb_append(_sb,_s,strlen(_s));
+  size_t len;
+  len=strlen(_s);
+  if(OP_UNLIKELY(len>(size_t)INT_MAX))return OP_EFAULT;
+  return op_sb_append(_sb,_s,(int)len);
 }
 
 static int op_sb_append_port(OpusStringBuf *_sb,unsigned _port){
@@ -962,7 +971,8 @@
       ret=send(fd.fd,_buf,_buf_size,0);
       if(ret>0){
         _buf+=ret;
-        _buf_size-=ret;
+        OP_ASSERT(ret<=_buf_size);
+        _buf_size-=(int)ret;
         continue;
       }
       err=op_errno();
@@ -1077,8 +1087,9 @@
       if(ret>0){
         /*Read some data.
           Keep going to see if there's more.*/
-        nread+=ret;
-        nread_unblocked+=ret;
+        OP_ASSERT(ret<=_buf_size-nread);
+        nread+=(int)ret;
+        nread_unblocked+=(int)ret;
         continue;
       }
       /*If we already read some data or the connection was closed, return
@@ -1620,6 +1631,7 @@
   size_t      pattern_label_len;
   size_t      pattern_prefix_len;
   size_t      pattern_suffix_len;
+  if(OP_UNLIKELY(_host_len>(size_t)INT_MAX))return 0;
   pattern=(const char *)ASN1_STRING_data(_pattern);
   pattern_len=strlen(pattern);
   /*Check the pattern for embedded NULs.*/
@@ -1627,6 +1639,7 @@
   pattern_label_len=strcspn(pattern,".");
   OP_ASSERT(pattern_label_len<=pattern_len);
   pattern_prefix_len=strcspn(pattern,"*");
+  if(OP_UNLIKELY(pattern_prefix_len>(size_t)INT_MAX))return 0;
   if(pattern_prefix_len>=pattern_label_len){
     /*"The client SHOULD NOT attempt to match a presented identifier in which
        the wildcard character comprises a label other than the left-most label
@@ -1637,7 +1650,8 @@
       Don't use the system strcasecmp here, as that uses the locale and
        RFC 4343 makes clear that DNS's case-insensitivity only applies to
        the ASCII range.*/
-    return _host_len==pattern_len&&op_strncasecmp(_host,pattern,_host_len)==0;
+    return _host_len==pattern_len
+     &&op_strncasecmp(_host,pattern,(int)_host_len)==0;
   }
   /*"However, the client SHOULD NOT attempt to match a presented identifier
      where the wildcard character is embedded within an A-label or U-label of
@@ -1672,10 +1686,11 @@
   pattern_suffix_len=pattern_len-pattern_prefix_len-1;
   host_suffix_len=_host_len-host_label_len
    +pattern_label_len-pattern_prefix_len-1;
+  OP_ASSERT(host_suffix_len<=_host_len);
   return pattern_suffix_len==host_suffix_len
-   &&op_strncasecmp(_host,pattern,pattern_prefix_len)==0
+   &&op_strncasecmp(_host,pattern,(int)pattern_prefix_len)==0
    &&op_strncasecmp(_host+_host_len-host_suffix_len,
-   pattern+pattern_prefix_len+1,host_suffix_len)==0;
+   pattern+pattern_prefix_len+1,(int)host_suffix_len)==0;
 }
 
 /*Convert a host to a numeric address, if possible.
@@ -1851,7 +1866,8 @@
   BIO         *ssl_bio;
   int          skip_certificate_check;
   int          ret;
-  ssl_bio=BIO_new_socket(_fd,BIO_NOCLOSE);
+  /*This always takes an int, even though with Winsock op_sock is a SOCKET.*/
+  ssl_bio=BIO_new_socket((int)_fd,BIO_NOCLOSE);
   if(OP_LIKELY(ssl_bio==NULL))return OP_FALSE;
 # if !defined(OPENSSL_NO_TLSEXT)
   /*Support for RFC 6066 Server Name Indication.*/
@@ -1911,11 +1927,10 @@
                     left to try.
                     *_addr will be set to NULL in this case.*/
 static int op_sock_connect_next(op_sock _fd,
- const struct addrinfo **_addr,int _ai_family){
-  const struct addrinfo *addr;
-  int                    err;
-  addr=*_addr;
-  for(;;){
+ struct addrinfo **_addr,int _ai_family){
+  struct addrinfo *addr;
+  int              err;
+  for(addr=*_addr;;addr=addr->ai_next){
     /*Move to the next address of the requested type.*/
     for(;addr!=NULL&&addr->ai_family!=_ai_family;addr=addr->ai_next);
     *_addr=addr;
@@ -1925,7 +1940,6 @@
     err=op_errno();
     /*Winsock will set WSAEWOULDBLOCK.*/
     if(OP_LIKELY(err==EINPROGRESS||err==EWOULDBLOCK))return 0;
-    addr=addr->ai_next;
   }
 }
 
@@ -1933,15 +1947,15 @@
 # define OP_NPROTOS (2)
 
 static int op_http_connect_impl(OpusHTTPStream *_stream,OpusHTTPConn *_conn,
- const struct addrinfo *_addrs,struct timeb *_start_time){
-  const struct addrinfo *addr;
-  const struct addrinfo *addrs[OP_NPROTOS];
-  struct pollfd          fds[OP_NPROTOS];
-  int                    ai_family;
-  int                    nprotos;
-  int                    ret;
-  int                    pi;
-  int                    pj;
+ struct addrinfo *_addrs,struct timeb *_start_time){
+  struct addrinfo *addr;
+  struct addrinfo *addrs[OP_NPROTOS];
+  struct pollfd    fds[OP_NPROTOS];
+  int              ai_family;
+  int              nprotos;
+  int              ret;
+  int              pi;
+  int              pj;
   for(pi=0;pi<OP_NPROTOS;pi++)addrs[pi]=NULL;
   /*Try connecting via both IPv4 and IPv6 simultaneously, and keep the first
      one that succeeds.
@@ -2065,7 +2079,7 @@
 }
 
 static int op_http_connect(OpusHTTPStream *_stream,OpusHTTPConn *_conn,
- const struct addrinfo *_addrs,struct timeb *_start_time){
+ struct addrinfo *_addrs,struct timeb *_start_time){
   struct timeb     resolve_time;
   struct addrinfo *new_addrs;
   int              ret;
@@ -2138,19 +2152,20 @@
    Scheme and append it to the given string buffer.*/
 static int op_sb_append_basic_auth_header(OpusStringBuf *_sb,
  const char *_header,const char *_user,const char *_pass){
-  int user_len;
-  int pass_len;
-  int user_pass_len;
-  int base64_len;
-  int nbuf_total;
-  int ret;
+  size_t user_len;
+  size_t pass_len;
+  int    user_pass_len;
+  int    base64_len;
+  int    nbuf_total;
+  int    ret;
   ret=op_sb_append_string(_sb,_header);
   ret|=op_sb_append(_sb,": Basic ",8);
   user_len=strlen(_user);
   pass_len=strlen(_pass);
+  if(OP_UNLIKELY(user_len>(size_t)INT_MAX))return OP_EFAULT;
   if(OP_UNLIKELY(pass_len>INT_MAX-user_len))return OP_EFAULT;
-  if(OP_UNLIKELY(user_len+pass_len>(INT_MAX>>2)*3-3))return OP_EFAULT;
-  user_pass_len=user_len+1+pass_len;
+  if(OP_UNLIKELY((int)(user_len+pass_len)>(INT_MAX>>2)*3-3))return OP_EFAULT;
+  user_pass_len=(int)(user_len+pass_len)+1;
   base64_len=OP_BASE64_LENGTH(user_pass_len);
   /*Stick "user:pass" at the end of the buffer so we can Base64 encode it
      in-place.*/
@@ -2160,9 +2175,9 @@
   ret|=op_sb_ensure_capacity(_sb,nbuf_total);
   if(OP_UNLIKELY(ret<0))return ret;
   _sb->nbuf=nbuf_total-user_pass_len;
-  OP_ALWAYS_TRUE(!op_sb_append(_sb,_user,user_len));
+  OP_ALWAYS_TRUE(!op_sb_append(_sb,_user,(int)user_len));
   OP_ALWAYS_TRUE(!op_sb_append(_sb,":",1));
-  OP_ALWAYS_TRUE(!op_sb_append(_sb,_pass,pass_len));
+  OP_ALWAYS_TRUE(!op_sb_append(_sb,_pass,(int)pass_len));
   op_base64_encode(_sb->buf+nbuf_total-base64_len,
    _sb->buf+nbuf_total-user_pass_len,user_pass_len);
   return op_sb_append(_sb,"\r\n",2);
@@ -2781,7 +2796,7 @@
   ret=op_http_conn_handle_response(_stream,_conn);
   if(OP_UNLIKELY(ret!=0))return OP_FALSE;
   ftime(&end_time);
-  _stream->cur_conni=_conn-_stream->conns;
+  _stream->cur_conni=(int)(_conn-_stream->conns);
   OP_ASSERT(_stream->cur_conni>=0&&_stream->cur_conni<OP_NCONNS_MAX);
   /*The connection has been successfully opened.
     Update the connection time estimate.*/
@@ -2885,7 +2900,7 @@
       content_length=_stream->content_length;
     }
     OP_ASSERT(end_pos>pos);
-    _buf_size=OP_MIN(_buf_size,end_pos-pos);
+    _buf_size=(int)OP_MIN(_buf_size,end_pos-pos);
   }
   nread=op_http_conn_read(_conn,(char *)_buf,_buf_size,1);
   if(OP_UNLIKELY(nread<0))return nread;
@@ -2921,7 +2936,7 @@
 static int op_http_stream_read(void *_stream,
  unsigned char *_ptr,int _buf_size){
   OpusHTTPStream *stream;
-  ptrdiff_t       nread;
+  int             nread;
   opus_int64      size;
   opus_int64      pos;
   int             ci;
@@ -3125,7 +3140,8 @@
       *pnext=conn->next;
       conn->next=stream->lru_head;
       stream->lru_head=conn;
-      stream->cur_conni=conn-stream->conns;
+      stream->cur_conni=(int)(conn-stream->conns);
+      OP_ASSERT(stream->cur_conni>=0&&stream->cur_conni<OP_NCONNS_MAX);
       return 0;
     }
     pnext=&conn->next;
@@ -3177,7 +3193,8 @@
       *pnext=conn->next;
       conn->next=stream->lru_head;
       stream->lru_head=conn;
-      stream->cur_conni=conn-stream->conns;
+      stream->cur_conni=(int)(conn-stream->conns);
+      OP_ASSERT(stream->cur_conni>=0&&stream->cur_conni<OP_NCONNS_MAX);
       return 0;
     }
     close_pnext=pnext;
--- a/src/info.c
+++ b/src/info.c
@@ -279,11 +279,11 @@
 }
 
 int opus_tags_add(OpusTags *_tags,const char *_tag,const char *_value){
-  char *comment;
-  int   tag_len;
-  int   value_len;
-  int   ncomments;
-  int   ret;
+  char   *comment;
+  size_t  tag_len;
+  size_t  value_len;
+  int     ncomments;
+  int     ret;
   ncomments=_tags->comments;
   ret=op_tags_ensure_capacity(_tags,ncomments+1);
   if(OP_UNLIKELY(ret<0))return ret;
@@ -290,6 +290,8 @@
   tag_len=strlen(_tag);
   value_len=strlen(_value);
   /*+2 for '=' and '\0'.*/
+  if(tag_len+value_len<tag_len)return OP_EFAULT;
+  if(tag_len+value_len>(size_t)INT_MAX-2)return OP_EFAULT;
   comment=(char *)_ogg_malloc(sizeof(*comment)*(tag_len+value_len+2));
   if(OP_UNLIKELY(comment==NULL))return OP_EFAULT;
   memcpy(comment,_tag,sizeof(*comment)*tag_len);
@@ -296,7 +298,7 @@
   comment[tag_len]='=';
   memcpy(comment+tag_len+1,_value,sizeof(*comment)*(value_len+1));
   _tags->user_comments[ncomments]=comment;
-  _tags->comment_lengths[ncomments]=tag_len+value_len+1;
+  _tags->comment_lengths[ncomments]=(int)(tag_len+value_len+1);
   _tags->comments=ncomments+1;
   return 0;
 }
@@ -337,7 +339,10 @@
 }
 
 int opus_tagcompare(const char *_tag_name,const char *_comment){
-  return opus_tagncompare(_tag_name,strlen(_tag_name),_comment);
+  size_t tag_len;
+  tag_len=strlen(_tag_name);
+  if(OP_UNLIKELY(tag_len>(size_t)INT_MAX))return -1;
+  return opus_tagncompare(_tag_name,(int)tag_len,_comment);
 }
 
 int opus_tagncompare(const char *_tag_name,int _tag_len,const char *_comment){
@@ -348,17 +353,18 @@
 }
 
 const char *opus_tags_query(const OpusTags *_tags,const char *_tag,int _count){
-  char **user_comments;
-  int    tag_len;
-  int    found;
-  int    ncomments;
-  int    ci;
+  char   **user_comments;
+  size_t   tag_len;
+  int      found;
+  int      ncomments;
+  int      ci;
   tag_len=strlen(_tag);
+  if(OP_UNLIKELY(tag_len>(size_t)INT_MAX))return NULL;
   ncomments=_tags->comments;
   user_comments=_tags->user_comments;
   found=0;
   for(ci=0;ci<ncomments;ci++){
-    if(!opus_tagncompare(_tag,tag_len,user_comments[ci])){
+    if(!opus_tagncompare(_tag,(int)tag_len,user_comments[ci])){
       /*We return a pointer to the data, not a copy.*/
       if(_count==found++)return user_comments[ci]+tag_len+1;
     }
@@ -368,17 +374,18 @@
 }
 
 int opus_tags_query_count(const OpusTags *_tags,const char *_tag){
-  char **user_comments;
-  int    tag_len;
-  int    found;
-  int    ncomments;
-  int    ci;
+  char   **user_comments;
+  size_t   tag_len;
+  int      found;
+  int      ncomments;
+  int      ci;
   tag_len=strlen(_tag);
+  if(OP_UNLIKELY(tag_len>(size_t)INT_MAX))return 0;
   ncomments=_tags->comments;
   user_comments=_tags->user_comments;
   found=0;
   for(ci=0;ci<ncomments;ci++){
-    if(!opus_tagncompare(_tag,tag_len,user_comments[ci]))found++;
+    if(!opus_tagncompare(_tag,(int)tag_len,user_comments[ci]))found++;
   }
   return found;
 }
@@ -403,7 +410,8 @@
   ncomments=_tags->comments;
   /*Look for the first valid tag with the name _tag_name and use that.*/
   for(ci=0;ci<ncomments;ci++){
-    if(opus_tagncompare(_tag_name,_tag_len,comments[ci])==0){
+    OP_ASSERT(tag_len<=(size_t)INT_MAX);
+    if(opus_tagncompare(_tag_name,(int)_tag_len,comments[ci])==0){
       char       *p;
       opus_int32  gain_q8;
       int         negative;
--- a/src/opusfile.c
+++ b/src/opusfile.c
@@ -86,14 +86,15 @@
     This is to prevent us spending a lot of time allocating memory and looking
      for Ogg pages in non-Ogg files.*/
   if(memcmp(_initial_data,"OggS",4)!=0)return OP_ENOTFORMAT;
+  if(OP_UNLIKELY(_initial_bytes>(size_t)LONG_MAX))return OP_EFAULT;
   ogg_sync_init(&oy);
-  data=ogg_sync_buffer(&oy,_initial_bytes);
+  data=ogg_sync_buffer(&oy,(long)_initial_bytes);
   if(data!=NULL){
     ogg_stream_state os;
     ogg_page         og;
     int              ret;
     memcpy(data,_initial_data,_initial_bytes);
-    ogg_sync_wrote(&oy,_initial_bytes);
+    ogg_sync_wrote(&oy,(long)_initial_bytes);
     ogg_stream_init(&os,-1);
     err=OP_FALSE;
     do{
@@ -1504,6 +1505,7 @@
   int       seekable;
   int       ret;
   memset(_of,0,sizeof(*_of));
+  if(OP_UNLIKELY(_initial_bytes>(size_t)LONG_MAX))return OP_EFAULT;
   _of->end=-1;
   _of->source=_source;
   *&_of->callbacks=*_cb;
@@ -1520,9 +1522,9 @@
      decoding entire files from RAM.*/
   if(_initial_bytes>0){
     char *buffer;
-    buffer=ogg_sync_buffer(&_of->oy,_initial_bytes);
+    buffer=ogg_sync_buffer(&_of->oy,(long)_initial_bytes);
     memcpy(buffer,_initial_data,_initial_bytes*sizeof(*buffer));
-    ogg_sync_wrote(&_of->oy,_initial_bytes);
+    ogg_sync_wrote(&_of->oy,(long)_initial_bytes);
   }
   /*Can we seek?
     Stevens suggests the seek test is portable.*/
--- a/src/wincerts.c
+++ b/src/wincerts.c
@@ -100,7 +100,8 @@
          representation for something, it's the answer that 9 of them would
          give you back.
         I don't think OpenSSL's encoding qualifies.*/
-      find_para.cbData=_name->bytes->length;
+      if(OP_UNLIKELY(_name->bytes->length>MAXDWORD))return 0;
+      find_para.cbData=(DWORD)_name->bytes->length;
       find_para.pbData=(unsigned char *)_name->bytes->data;
       cert=CertFindCertificateInStore(h_store,X509_ASN_ENCODING,0,
        CERT_FIND_SUBJECT_NAME,&find_para,NULL);
@@ -122,7 +123,8 @@
       ret=op_capi_retrieve_by_subject(_lu,_type,_name,_ret);
       if(ret>0)return ret;
       memset(&cert_info,0,sizeof(cert_info));
-      cert_info.Issuer.cbData=_name->bytes->length;
+      if(OP_UNLIKELY(_name->bytes->length>MAXDWORD))return 0;
+      cert_info.Issuer.cbData=(DWORD)_name->bytes->length;
       cert_info.Issuer.pbData=(unsigned char *)_name->bytes->data;
       memset(&find_para,0,sizeof(find_para));
       find_para.pCertInfo=&cert_info;