Found at Connectathon, .NET RC1 arranges trans/trans2/nttrans parameters
authorJeremy Allison <jra@samba.org>
Fri, 7 Mar 2003 00:30:47 +0000 (00:30 +0000)
committerJeremy Allison <jra@samba.org>
Fri, 7 Mar 2003 00:30:47 +0000 (00:30 +0000)
differently to W2K, cope with this.
Jeremy.

source/smbd/ipc.c
source/smbd/nttrans.c
source/smbd/trans2.c

index 7fe02dbccf97e4239ff70ce296eb768b89df1f1f..08337c2901ac2d54fd50c545fafcaf87bcb8ff4e 100644 (file)
@@ -360,52 +360,66 @@ int reply_trans(connection_struct *conn, char *inbuf,char *outbuf, int size, int
        uint16 *setup=NULL;
        int outsize = 0;
        uint16 vuid = SVAL(inbuf,smb_uid);
-       int tpscnt = SVAL(inbuf,smb_vwv0);
-       int tdscnt = SVAL(inbuf,smb_vwv1);
-       int mprcnt = SVAL(inbuf,smb_vwv2);
-       int mdrcnt = SVAL(inbuf,smb_vwv3);
-       int msrcnt = CVAL(inbuf,smb_vwv4);
+       unsigned int tpscnt = SVAL(inbuf,smb_vwv0);
+       unsigned int tdscnt = SVAL(inbuf,smb_vwv1);
+       unsigned int mprcnt = SVAL(inbuf,smb_vwv2);
+       unsigned int mdrcnt = SVAL(inbuf,smb_vwv3);
+       unsigned int msrcnt = CVAL(inbuf,smb_vwv4);
        BOOL close_on_completion = BITSETW(inbuf+smb_vwv5,0);
        BOOL one_way = BITSETW(inbuf+smb_vwv5,1);
-       int pscnt = SVAL(inbuf,smb_vwv9);
-       int psoff = SVAL(inbuf,smb_vwv10);
-       int dscnt = SVAL(inbuf,smb_vwv11);
-       int dsoff = SVAL(inbuf,smb_vwv12);
-       int suwcnt = CVAL(inbuf,smb_vwv13);
+       unsigned int pscnt = SVAL(inbuf,smb_vwv9);
+       unsigned int psoff = SVAL(inbuf,smb_vwv10);
+       unsigned int dscnt = SVAL(inbuf,smb_vwv11);
+       unsigned int dsoff = SVAL(inbuf,smb_vwv12);
+       unsigned int suwcnt = CVAL(inbuf,smb_vwv13);
        START_PROFILE(SMBtrans);
 
        memset(name, '\0',sizeof(name));
        srvstr_pull_buf(inbuf, name, smb_buf(inbuf), sizeof(name), STR_TERMINATE);
 
-       if (dscnt > tdscnt || pscnt > tpscnt) {
-               exit_server("invalid trans parameters");
-       }
+       if (dscnt > tdscnt || pscnt > tpscnt)
+               goto bad_param;
   
        if (tdscnt)  {
                if((data = (char *)malloc(tdscnt)) == NULL) {
-                       DEBUG(0,("reply_trans: data malloc fail for %d bytes !\n", tdscnt));
+                       DEBUG(0,("reply_trans: data malloc fail for %u bytes !\n", tdscnt));
                        END_PROFILE(SMBtrans);
                        return(ERROR_DOS(ERRDOS,ERRnomem));
                } 
+               if ((dsoff+dscnt < dsoff) || (dsoff+dscnt < dscnt))
+                       goto bad_param;
+               if (smb_base(inbuf)+dsoff+dscnt > inbuf + size)
+                       goto bad_param;
+
                memcpy(data,smb_base(inbuf)+dsoff,dscnt);
        }
 
        if (tpscnt) {
                if((params = (char *)malloc(tpscnt)) == NULL) {
-                       DEBUG(0,("reply_trans: param malloc fail for %d bytes !\n", tpscnt));
+                       DEBUG(0,("reply_trans: param malloc fail for %u bytes !\n", tpscnt));
                        END_PROFILE(SMBtrans);
                        return(ERROR_DOS(ERRDOS,ERRnomem));
                } 
+               if ((psoff+pscnt < psoff) || (psoff+pscnt < pscnt))
+                        goto bad_param;
+               if (smb_base(inbuf)+psoff+pscnt > inbuf + size)
+                       goto bad_param;
+
                memcpy(params,smb_base(inbuf)+psoff,pscnt);
        }
 
        if (suwcnt) {
                int i;
                if((setup = (uint16 *)malloc(suwcnt*sizeof(uint16))) == NULL) {
-          DEBUG(0,("reply_trans: setup malloc fail for %d bytes !\n", (int)(suwcnt * sizeof(uint16))));
-                 END_PROFILE(SMBtrans);
-                 return(ERROR_DOS(ERRDOS,ERRnomem));
-        } 
+                       DEBUG(0,("reply_trans: setup malloc fail for %u bytes !\n", (unsigned int)(suwcnt * sizeof(uint16))));
+                       END_PROFILE(SMBtrans);
+                       return(ERROR_DOS(ERRDOS,ERRnomem));
+               } 
+               if (inbuf+smb_vwv14+(suwcnt*SIZEOFWORD) > inbuf + size)
+                       goto bad_param;
+               if ((smb_vwv14+(suwcnt*SIZEOFWORD) < smb_vwv14) || (smb_vwv14+(suwcnt*SIZEOFWORD) < (suwcnt*SIZEOFWORD)))
+                       goto bad_param;
+
                for (i=0;i<suwcnt;i++)
                        setup[i] = SVAL(inbuf,smb_vwv14+i*SIZEOFWORD);
        }
@@ -423,7 +437,7 @@ int reply_trans(connection_struct *conn, char *inbuf,char *outbuf, int size, int
        /* receive the rest of the trans packet */
        while (pscnt < tpscnt || dscnt < tdscnt) {
                BOOL ret;
-               int pcnt,poff,dcnt,doff,pdisp,ddisp;
+               unsigned int pcnt,poff,dcnt,doff,pdisp,ddisp;
       
                ret = receive_next_smb(inbuf,bufsize,SMB_SECONDARY_WAIT);
 
@@ -443,8 +457,11 @@ int reply_trans(connection_struct *conn, char *inbuf,char *outbuf, int size, int
 
                show_msg(inbuf);
       
-               tpscnt = SVAL(inbuf,smb_vwv0);
-               tdscnt = SVAL(inbuf,smb_vwv1);
+               /* Revise total_params and total_data in case they have changed downwards */
+               if (SVAL(inbuf,smb_vwv0) < tpscnt)
+                       tpscnt = SVAL(inbuf,smb_vwv0);
+               if (SVAL(inbuf,smb_vwv1) < tdscnt)
+                       tdscnt = SVAL(inbuf,smb_vwv1);
 
                pcnt = SVAL(inbuf,smb_vwv2);
                poff = SVAL(inbuf,smb_vwv3);
@@ -457,14 +474,34 @@ int reply_trans(connection_struct *conn, char *inbuf,char *outbuf, int size, int
                pscnt += pcnt;
                dscnt += dcnt;
                
-               if (dscnt > tdscnt || pscnt > tpscnt) {
-                       exit_server("invalid trans parameters");
-               }
+               if (dscnt > tdscnt || pscnt > tpscnt)
+                       goto bad_param;
                
-               if (pcnt)
+               if (pcnt) {
+                       if (pdisp+pcnt >= tpscnt)
+                               goto bad_param;
+                       if ((pdisp+pcnt < pdisp) || (pdisp+pcnt < pcnt))
+                                goto bad_param;
+                       if (smb_base(inbuf) + poff + pcnt >= inbuf + bufsize)
+                               goto bad_param;
+                       if (params + pdisp < params)
+                               goto bad_param;
+
                        memcpy(params+pdisp,smb_base(inbuf)+poff,pcnt);
-               if (dcnt)
+               }
+
+               if (dcnt) {
+                       if (ddisp+dcnt >= tdscnt)
+                               goto bad_param;
+                       if ((ddisp+dcnt < ddisp) || (ddisp+dcnt < dcnt))
+                               goto bad_param;
+                       if (smb_base(inbuf) + doff + dcnt >= inbuf + bufsize)
+                               goto bad_param;
+                       if (data + ddisp < data)
+                               goto bad_param;
+
                        memcpy(data+ddisp,smb_base(inbuf)+doff,dcnt);      
+               }
        }
        
        
@@ -517,4 +554,14 @@ int reply_trans(connection_struct *conn, char *inbuf,char *outbuf, int size, int
        
        END_PROFILE(SMBtrans);
        return(outsize);
+
+
+  bad_param:
+
+       DEBUG(0,("reply_trans: invalid trans parameters\n"));
+       SAFE_FREE(data);
+       SAFE_FREE(params);
+       SAFE_FREE(setup);
+       END_PROFILE(SMBtrans);
+       return ERROR_DOS(ERRDOS,ERRinvalidparam);
 }
index bfac4e82e361fdcaf0befbf691837b46aafa6705..375c6c44f63b40f50b15e749097ac9909f774ad6 100644 (file)
@@ -1771,8 +1771,7 @@ due to being in oplock break state.\n", (unsigned int)function_code ));
        if(CVAL(inbuf, smb_wct) != 19 + (setup_count/2)) {
                DEBUG(2,("Invalid smb_wct %d in nttrans call (should be %d)\n",
                        CVAL(inbuf, smb_wct), 19 + (setup_count/2)));
-               END_PROFILE(SMBnttrans);
-               return ERROR_DOS(ERRSRV,ERRerror);
+               goto bad_param;
        }
     
        /* Allocate the space for the setup, the maximum needed parameters and data */
@@ -1799,21 +1798,38 @@ due to being in oplock break state.\n", (unsigned int)function_code ));
        num_data_sofar = data_count;
 
        if (parameter_count > total_parameter_count || data_count > total_data_count)
-               exit_server("reply_nttrans: invalid sizes in packet.");
+               goto bad_param;
 
        if(setup) {
-               memcpy( setup, &inbuf[smb_nt_SetupStart], setup_count);
                DEBUG(10,("reply_nttrans: setup_count = %d\n", setup_count));
+               if ((smb_nt_SetupStart + setup_count < smb_nt_SetupStart) ||
+                               (smb_nt_SetupStart + setup_count < setup_count))
+                       goto bad_param;
+               if (smb_nt_SetupStart + setup_count > length)
+                       goto bad_param;
+
+               memcpy( setup, &inbuf[smb_nt_SetupStart], setup_count);
                dump_data(10, setup, setup_count);
        }
        if(params) {
-               memcpy( params, smb_base(inbuf) + parameter_offset, parameter_count);
                DEBUG(10,("reply_nttrans: parameter_count = %d\n", parameter_count));
+               if ((parameter_offset + parameter_count < parameter_offset) ||
+                               (parameter_offset + parameter_count < parameter_count))
+                       goto bad_param;
+               if (smb_base(inbuf) + parameter_offset + parameter_count > inbuf + length)
+                       goto bad_param;
+
+               memcpy( params, smb_base(inbuf) + parameter_offset, parameter_count);
                dump_data(10, params, parameter_count);
        }
        if(data) {
-               memcpy( data, smb_base(inbuf) + data_offset, data_count);
                DEBUG(10,("reply_nttrans: data_count = %d\n",data_count));
+               if ((data_offset + data_count < data_offset) || (data_offset + data_count < data_count))
+                       goto bad_param;
+               if (smb_base(inbuf) + data_offset + data_count > inbuf + length)
+                       goto bad_param;
+
+               memcpy( data, smb_base(inbuf) + data_offset, data_count);
                dump_data(10, data, data_count);
        }
 
@@ -1826,6 +1842,8 @@ due to being in oplock break state.\n", (unsigned int)function_code ));
 
                while( num_data_sofar < total_data_count || num_params_sofar < total_parameter_count) {
                        BOOL ret;
+                       uint32 parameter_displacement;
+                       uint32 data_displacement;
 
                        ret = receive_next_smb(inbuf,bufsize,SMB_SECONDARY_WAIT);
 
@@ -1837,25 +1855,57 @@ due to being in oplock break state.\n", (unsigned int)function_code ));
                                        DEBUG(0,("reply_nttrans: %s in getting secondary nttrans response.\n",
                                                (smb_read_error == READ_ERROR) ? "error" : "timeout" ));
                                }
-                               SAFE_FREE(params);
-                               SAFE_FREE(data);
-                               SAFE_FREE(setup);
-                               END_PROFILE(SMBnttrans);
-                               return ERROR_DOS(ERRSRV,ERRerror);
+                               goto bad_param;
                        }
       
                        /* Revise total_params and total_data in case they have changed downwards */
-                       total_parameter_count = IVAL(inbuf, smb_nts_TotalParameterCount);
-                       total_data_count = IVAL(inbuf, smb_nts_TotalDataCount);
-                       num_params_sofar += (parameter_count = IVAL(inbuf,smb_nts_ParameterCount));
-                       num_data_sofar += ( data_count = IVAL(inbuf, smb_nts_DataCount));
-                       if (num_params_sofar > total_parameter_count || num_data_sofar > total_data_count)
-                               exit_server("reply_nttrans2: data overflow in secondary nttrans packet");
-
-                       memcpy( &params[ IVAL(inbuf, smb_nts_ParameterDisplacement)], 
-                               smb_base(inbuf) + IVAL(inbuf, smb_nts_ParameterOffset), parameter_count);
-                       memcpy( &data[IVAL(inbuf, smb_nts_DataDisplacement)],
-                               smb_base(inbuf)+ IVAL(inbuf, smb_nts_DataOffset), data_count);
+                       if (IVAL(inbuf, smb_nts_TotalParameterCount) < total_parameter_count)
+                               total_parameter_count = IVAL(inbuf, smb_nts_TotalParameterCount);
+                       if (IVAL(inbuf, smb_nts_TotalDataCount) < total_data_count)
+                               total_data_count = IVAL(inbuf, smb_nts_TotalDataCount);
+
+                       parameter_count = IVAL(inbuf,smb_nts_ParameterCount);
+                       parameter_offset = IVAL(inbuf, smb_nts_ParameterOffset);
+                       parameter_displacement = IVAL(inbuf, smb_nts_ParameterDisplacement);
+                       num_params_sofar += parameter_count;
+
+                       data_count = IVAL(inbuf, smb_nts_DataCount);
+                       data_displacement = IVAL(inbuf, smb_nts_DataDisplacement);
+                       data_offset = IVAL(inbuf, smb_nts_DataDisplacement);
+                       num_data_sofar += data_count;
+
+                       if (num_params_sofar > total_parameter_count || num_data_sofar > total_data_count) {
+                               DEBUG(0,("reply_nttrans2: data overflow in secondary nttrans packet"));
+                               goto bad_param;
+                       }
+
+                       if (parameter_count) {
+                               if (parameter_displacement + parameter_count >= total_parameter_count)
+                                       goto bad_param;
+                               if ((parameter_displacement + parameter_count < parameter_displacement) ||
+                                               (parameter_displacement + parameter_count < parameter_count))
+                                       goto bad_param;
+                               if (smb_base(inbuf) + parameter_offset + parameter_count >= inbuf + bufsize)
+                                       goto bad_param;
+                               if (parameter_displacement + params < params)
+                                       goto bad_param;
+
+                               memcpy( &params[parameter_displacement], smb_base(inbuf) + parameter_offset, parameter_count);
+                       }
+
+                       if (data_count) {
+                               if (data_displacement + data_count >= total_data_count)
+                                       goto bad_param;
+                               if ((data_displacement + data_count < data_displacement) ||
+                                               (data_displacement + data_count < data_count))
+                                       goto bad_param;
+                               if (smb_base(inbuf) + data_offset + data_count >= inbuf + bufsize)
+                                       goto bad_param;
+                               if (data_displacement + data < data)
+                                       goto bad_param;
+
+                               memcpy( &data[data_displacement], smb_base(inbuf)+ data_offset, data_count);
+                       }
                }
        }
 
@@ -1933,4 +1983,12 @@ due to being in oplock break state.\n", (unsigned int)function_code ));
        return outsize; /* If a correct response was needed the call_nt_transact_xxxx 
                                calls have already sent it. If outsize != -1 then it is
                                returning an error packet. */
+
+ bad_param:
+
+       SAFE_FREE(params);
+       SAFE_FREE(data);
+       SAFE_FREE(setup);
+       END_PROFILE(SMBnttrans);
+       return ERROR_DOS(ERRDOS,ERRinvalidparam);
 }
index 155c9963146ee684d6177db7eda33d5dd7beb759..d57a29ff7739a0e9a9895f75e59b12074c61fbba 100644 (file)
@@ -3094,7 +3094,7 @@ int reply_trans2(connection_struct *conn,
        unsigned int suwcnt = SVAL(inbuf, smb_suwcnt);
        unsigned int tran_call = SVAL(inbuf, smb_setup0);
        char *params = NULL, *data = NULL;
-       int num_params, num_params_sofar, num_data, num_data_sofar;
+       unsigned int num_params, num_params_sofar, num_data, num_data_sofar;
        START_PROFILE(SMBtrans2);
 
        if(global_oplock_break && (tran_call == TRANSACT2_OPEN)) {
@@ -3133,10 +3133,10 @@ int reply_trans2(connection_struct *conn,
                                (SVAL(inbuf,(smb_setup+6)) == LMFUNC_GETJOBID)) {
                        DEBUG(2,("Got Trans2 DevIOctl jobid\n"));
                } else {
-                       DEBUG(2,("Invalid smb_sucnt in trans2 call(%d)\n",suwcnt));
+                       DEBUG(2,("Invalid smb_sucnt in trans2 call(%u)\n",suwcnt));
                        DEBUG(2,("Transaction is %d\n",tran_call));
                        END_PROFILE(SMBtrans2);
-                       return ERROR_DOS(ERRSRV,ERRerror);
+                       ERROR_DOS(ERRDOS,ERRinvalidparam);
                }
        }
     
@@ -3162,10 +3162,22 @@ int reply_trans2(connection_struct *conn,
        if (num_params > total_params || num_data > total_data)
                exit_server("invalid params in reply_trans2");
 
-       if(params)
-               memcpy( params, smb_base(inbuf) + SVAL(inbuf, smb_psoff), num_params);
-       if(data)
-               memcpy( data, smb_base(inbuf) + SVAL(inbuf, smb_dsoff), num_data);
+       if(params) {
+               unsigned int psoff = SVAL(inbuf, smb_psoff);
+               if ((psoff + num_params < psoff) || (psoff + num_params < num_params))
+                       goto bad_param;
+               if (smb_base(inbuf) + psoff + num_params > inbuf + length)
+                       goto bad_param;
+               memcpy( params, smb_base(inbuf) + psoff, num_params);
+       }
+       if(data) {
+               unsigned int dsoff = SVAL(inbuf, smb_dsoff);
+               if ((dsoff + num_data < dsoff) || (dsoff + num_data < num_data))
+                       goto bad_param;
+               if (smb_base(inbuf) + dsoff + num_data > inbuf + length)
+                       goto bad_param;
+               memcpy( data, smb_base(inbuf) + dsoff, num_data);
+       }
 
        if(num_data_sofar < total_data || num_params_sofar < total_params)  {
                /* We need to send an interim response then receive the rest
@@ -3177,6 +3189,10 @@ int reply_trans2(connection_struct *conn,
                while (num_data_sofar < total_data || 
                       num_params_sofar < total_params) {
                        BOOL ret;
+                       unsigned int param_disp;
+                       unsigned int param_off;
+                       unsigned int data_disp;
+                       unsigned int data_off;
 
                        ret = receive_next_smb(inbuf,bufsize,SMB_SECONDARY_WAIT);
                        
@@ -3188,25 +3204,55 @@ int reply_trans2(connection_struct *conn,
                                else
                                        DEBUG(0,("reply_trans2: %s in getting secondary trans2 response.\n",
                                                 (smb_read_error == READ_ERROR) ? "error" : "timeout" ));
-                               SAFE_FREE(params);
-                               SAFE_FREE(data);
-                               END_PROFILE(SMBtrans2);
-                               return ERROR_DOS(ERRSRV,ERRerror);
+                               goto bad_param;
                        }
       
                        /* Revise total_params and total_data in case
                            they have changed downwards */
-                       total_params = SVAL(inbuf, smb_tpscnt);
-                       total_data = SVAL(inbuf, smb_tdscnt);
-                       num_params_sofar += (num_params = SVAL(inbuf,smb_spscnt));
-                       num_data_sofar += ( num_data = SVAL(inbuf, smb_sdscnt));
+                       if (SVAL(inbuf, smb_tpscnt) < total_params)
+                               total_params = SVAL(inbuf, smb_tpscnt);
+                       if (SVAL(inbuf, smb_tdscnt) < total_data)
+                               total_data = SVAL(inbuf, smb_tdscnt);
+
+                       num_params = SVAL(inbuf,smb_spscnt);
+                       param_off = SVAL(inbuf, smb_spsoff);
+                       param_disp = SVAL(inbuf, smb_spsdisp);
+                       num_params_sofar += num_params;
+
+                       num_data = SVAL(inbuf, smb_sdscnt);
+                       data_off = SVAL(inbuf, smb_sdsoff);
+                       data_disp = SVAL(inbuf, smb_sdsdisp);
+                       num_data_sofar += num_data;
+
                        if (num_params_sofar > total_params || num_data_sofar > total_data)
-                               exit_server("data overflow in trans2");
+                               goto bad_param;
                        
-                       memcpy( &params[ SVAL(inbuf, smb_spsdisp)], 
-                               smb_base(inbuf) + SVAL(inbuf, smb_spsoff), num_params);
-                       memcpy( &data[SVAL(inbuf, smb_sdsdisp)],
-                               smb_base(inbuf)+ SVAL(inbuf, smb_sdsoff), num_data);
+                       if (num_params) {
+                               if (param_disp + num_params >= total_params)
+                                       goto bad_param;
+                               if ((param_disp + num_params < param_disp) ||
+                                               (param_disp + num_params < num_params))
+                                       goto bad_param;
+                               if (smb_base(inbuf) + param_off + num_params >= inbuf + bufsize)
+                                       goto bad_param;
+                               if (params + param_disp < params)
+                                       goto bad_param;
+
+                               memcpy( &params[param_disp], smb_base(inbuf) + param_off, num_params);
+                       }
+                       if (num_data) {
+                               if (data_disp + num_data >= total_data)
+                                       goto bad_param;
+                               if ((data_disp + num_data < data_disp) ||
+                                               (data_disp + num_data < num_data))
+                                       goto bad_param;
+                               if (smb_base(inbuf) + data_off + num_data >= inbuf + bufsize)
+                                       goto bad_param;
+                               if (data + data_disp < data)
+                                       goto bad_param;
+
+                               memcpy( &data[data_disp], smb_base(inbuf) + data_off, num_data);
+                       }
                }
        }
        
@@ -3320,4 +3366,11 @@ int reply_trans2(connection_struct *conn,
        return outsize; /* If a correct response was needed the
                           call_trans2xxx calls have already sent
                           it. If outsize != -1 then it is returning */
+
+  bad_param:
+
+       SAFE_FREE(params);
+       SAFE_FREE(data);
+       END_PROFILE(SMBtrans2);
+       return ERROR_DOS(ERRDOS,ERRinvalidparam);
 }