diff options
Diffstat (limited to 'openwrt/package/samba/patches/200-security.patch')
-rw-r--r-- | openwrt/package/samba/patches/200-security.patch | 611 |
1 files changed, 611 insertions, 0 deletions
diff --git a/openwrt/package/samba/patches/200-security.patch b/openwrt/package/samba/patches/200-security.patch new file mode 100644 index 0000000..7fb34f9 --- /dev/null +++ b/openwrt/package/samba/patches/200-security.patch @@ -0,0 +1,611 @@ +diff -ur samba-2.0.10/source/include/smb.h samba-2.0.10-security/source/include/smb.h +--- samba-2.0.10/source/include/smb.h 2001-06-23 12:52:20.000000000 +0400 ++++ samba-2.0.10-security/source/include/smb.h 2005-05-21 21:51:17.206995728 +0400 +@@ -256,6 +256,7 @@ + #define ERRlock 33 /* Lock request conflicts with existing lock */ + #define ERRunsup 50 /* Request unsupported, returned by Win 95, RJS 20Jun98 */ + #define ERRfilexists 80 /* File in operation already exists */ ++#define ERRinvalidparam 87 + #define ERRcannotopen 110 /* Cannot open the file specified */ + #define ERRunknownlevel 124 + #define ERRrename 183 +@@ -1893,4 +1894,7 @@ + + #define SAFE_NETBIOS_CHARS ". -_" + ++#ifndef SAFE_FREE ++#define SAFE_FREE(x) do { if ((x) != NULL) {free((x)); (x)=NULL;} } while(0) ++#endif + #endif /* _SMB_H */ +diff -ur samba-2.0.10/source/include/version.h samba-2.0.10-security/source/include/version.h +--- samba-2.0.10/source/include/version.h 2001-06-23 17:23:59.000000000 +0400 ++++ samba-2.0.10-security/source/include/version.h 2005-05-21 21:51:17.227992536 +0400 +@@ -1 +1 @@ +-#define VERSION "2.0.10" ++#define VERSION "2.0.10-security-rollup" +diff -ur samba-2.0.10/source/smbd/filename.c samba-2.0.10-security/source/smbd/filename.c +--- samba-2.0.10/source/smbd/filename.c 2000-03-17 01:59:44.000000000 +0300 ++++ samba-2.0.10-security/source/smbd/filename.c 2005-05-21 21:51:17.403965784 +0400 +@@ -172,7 +172,7 @@ + * StrnCpy always null terminates. + */ + +- StrnCpy(orig_name, full_orig_name, namelen); ++ StrnCpy(orig_name, full_orig_name, MIN(namelen, sizeof(orig_name)-1)); + if(!case_sensitive) + strupper( orig_name ); + +diff -ur samba-2.0.10/source/smbd/ipc.c samba-2.0.10-security/source/smbd/ipc.c +--- samba-2.0.10/source/smbd/ipc.c 2000-03-30 02:20:06.000000000 +0400 ++++ samba-2.0.10-security/source/smbd/ipc.c 2005-05-21 21:51:17.269986152 +0400 +@@ -3550,18 +3550,18 @@ + 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); + + memset(name, '\0',sizeof(name)); + fstrcpy(name,smb_buf(inbuf)); +@@ -3572,31 +3572,48 @@ + + 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)); + return(ERROR(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)); ++ SAFE_FREE(data); + return(ERROR(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)))); +- return(ERROR(ERRDOS,ERRnomem)); +- } ++ DEBUG(0,("reply_trans: setup malloc fail for %u bytes !\n", (unsigned int)(suwcnt * sizeof(uint16)))); ++ SAFE_FREE(data); ++ SAFE_FREE(params); ++ return(ERROR(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); + } + +- + if (pscnt < tpscnt || dscnt < tdscnt) { + /* We need to send an interim response then receive the rest + of the parameter/data bytes */ +@@ -3608,7 +3625,7 @@ + /* 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); + +@@ -3619,19 +3636,19 @@ + DEBUG(0,("reply_trans: %s in getting secondary trans response.\n", + (smb_read_error == READ_ERROR) ? "error" : "timeout" )); + } +- if (params) +- free(params); +- if (data) +- free(data); +- if (setup) +- free(setup); ++ SAFE_FREE(params); ++ SAFE_FREE(data); ++ SAFE_FREE(setup); + return(ERROR(ERRSRV,ERRerror)); + } + + 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); +@@ -3644,17 +3661,36 @@ + pscnt += pcnt; + dscnt += dcnt; + +- if (dscnt > tdscnt || pscnt > tpscnt) { +- exit_server("invalid trans parameters\n"); +- } ++ 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); ++ } + } +- +- ++ + DEBUG(3,("trans <%s> data=%d params=%d setup=%d\n", + name,tdscnt,tpscnt,suwcnt)); + +@@ -3694,4 +3730,12 @@ + return(ERROR(ERRSRV,ERRnosupport)); + + return(outsize); ++ ++ bad_param: ++ ++ DEBUG(0,("reply_trans: invalid trans parameters\n")); ++ SAFE_FREE(data); ++ SAFE_FREE(params); ++ SAFE_FREE(setup); ++ return(ERROR(ERRSRV,ERRerror)); + } +diff -ur samba-2.0.10/source/smbd/nttrans.c samba-2.0.10-security/source/smbd/nttrans.c +--- samba-2.0.10/source/smbd/nttrans.c 2000-04-24 21:27:30.000000000 +0400 ++++ samba-2.0.10-security/source/smbd/nttrans.c 2005-05-21 21:51:17.314979312 +0400 +@@ -2575,11 +2575,14 @@ + params = (char *)malloc(total_parameter_count); + if (total_data_count > 0) + data = (char *)malloc(total_data_count); +- ++ + if ((total_parameter_count && !params) || (total_data_count && !data) || + (setup_count && !setup)) { ++ SAFE_FREE(setup); ++ SAFE_FREE(params); ++ SAFE_FREE(data); + DEBUG(0,("reply_nttrans : Out of memory\n")); +- return(ERROR(ERRDOS,ERRnomem)); ++ return ERROR(ERRDOS,ERRnomem); + } + + /* Copy the param and data bytes sent with this request into +@@ -2588,64 +2591,112 @@ + num_data_sofar = data_count; + + if (parameter_count > total_parameter_count || data_count > total_data_count) +- exit_server("reply_nttrans: invalid sizes in packet.\n"); ++ goto bad_param; + + if(setup) { +- memcpy( setup, &inbuf[smb_nt_SetupStart], setup_count); + DEBUG(10,("reply_nttrans: setup_count = %d\n", setup_count)); +- dump_data(10, setup, 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); + } + if(params) { +- memcpy( params, smb_base(inbuf) + parameter_offset, parameter_count); + DEBUG(10,("reply_nttrans: parameter_count = %d\n", parameter_count)); +- dump_data(10, params, 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); + } + if(data) { +- memcpy( data, smb_base(inbuf) + data_offset, data_count); + DEBUG(10,("reply_nttrans: data_count = %d\n",data_count)); +- dump_data(10, data, 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); ++ + } + + if(num_data_sofar < total_data_count || num_params_sofar < total_parameter_count) { + /* We need to send an interim response then receive the rest + of the parameter/data bytes */ + outsize = set_message(outbuf,0,0,True); +- send_smb(Client,outbuf); ++ if (!send_smb(Client,outbuf)) ++ exit_server("reply_nttrans: send_smb failed."); + + 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); +- ++ + if((ret && (CVAL(inbuf, smb_com) != SMBnttranss)) || !ret) { +- outsize = set_message(outbuf,0,0,True); +- if(ret) { +- DEBUG(0,("reply_nttrans: Invalid secondary nttrans packet\n")); +- } else { +- DEBUG(0,("reply_nttrans: %s in getting secondary nttrans response.\n", +- (smb_read_error == READ_ERROR) ? "error" : "timeout" )); ++ outsize = set_message(outbuf,0,0,True); ++ if(ret) { ++ DEBUG(0,("reply_nttrans: Invalid secondary nttrans packet\n")); ++ } else { ++ DEBUG(0,("reply_nttrans: %s in getting secondary nttrans response.\n", ++ (smb_read_error == READ_ERROR) ? "error" : "timeout" )); + } +- if(params) +- free(params); +- if(data) +- free(data); +- if(setup) +- free(setup); +- return(ERROR(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\n"); +- +- memcpy( ¶ms[ 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_DataOffset); ++ 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 (params + parameter_displacement < params) ++ goto bad_param; ++ ++ memcpy( ¶ms[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 + data_displacement < data) ++ goto bad_param; ++ ++ memcpy( &data[data_displacement], smb_base(inbuf)+ data_offset, data_count); ++ } + } + } + +@@ -2714,4 +2765,10 @@ + 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); ++ return ERROR(ERRDOS,ERRinvalidparam); + } +diff -ur samba-2.0.10/source/smbd/password.c samba-2.0.10-security/source/smbd/password.c +--- samba-2.0.10/source/smbd/password.c 2000-03-17 01:59:48.000000000 +0300 ++++ samba-2.0.10-security/source/smbd/password.c 2005-05-21 21:51:17.336975968 +0400 +@@ -770,7 +770,7 @@ + if (!ok && lp_username(snum)) { + char *auser; + pstring user_list; +- StrnCpy(user_list,lp_username(snum),sizeof(pstring)); ++ StrnCpy(user_list,lp_username(snum),sizeof(pstring)-1); + + pstring_sub(user_list,"%S",lp_servicename(snum)); + +diff -ur samba-2.0.10/source/smbd/reply.c samba-2.0.10-security/source/smbd/reply.c +--- samba-2.0.10/source/smbd/reply.c 2001-06-23 12:51:24.000000000 +0400 ++++ samba-2.0.10-security/source/smbd/reply.c 2005-05-21 21:51:17.378969584 +0400 +@@ -1413,6 +1413,9 @@ + + for (i=numentries;(i<maxentries) && !finished;i++) + { ++ /* check to make sure we have room in the buffer */ ++ if ( ((PTR_DIFF(p, outbuf))+DIR_STRUCT_SIZE) > BUFFER_SIZE ) ++ break; + finished = + !get_dir_entry(conn,mask,dirtype,fname,&size,&mode,&date,check_descend); + if (!finished) +@@ -3122,6 +3125,9 @@ + + + for (i=first;i<first+num_to_get;i++) { ++ /* check to make sure we have room in the buffer */ ++ if ( (PTR_DIFF(p, outbuf)+28) > BUFFER_SIZE ) ++ break; + put_dos_date2(p,0,queue[i].time); + CVAL(p,4) = (queue[i].status==LPQ_PRINTING?2:3); + SSVAL(p,5,printjob_encode(SNUM(conn), +diff -ur samba-2.0.10/source/smbd/trans2.c samba-2.0.10-security/source/smbd/trans2.c +--- samba-2.0.10/source/smbd/trans2.c 2000-04-24 21:27:31.000000000 +0400 ++++ samba-2.0.10-security/source/smbd/trans2.c 2005-05-21 21:51:17.402965936 +0400 +@@ -201,7 +201,6 @@ + int16 open_ofun = SVAL(params,12); + int32 open_size = IVAL(params,14); + char *pname = ¶ms[28]; +- int16 namelen = strlen(pname)+1; + + pstring fname; + mode_t unixmode; +@@ -213,7 +212,7 @@ + BOOL bad_path = False; + files_struct *fsp; + +- StrnCpy(fname,pname,namelen); ++ pstrcpy(fname,pname); + + DEBUG(3,("trans2open %s mode=%d attr=%d ofun=%d size=%d\n", + fname,open_mode, open_attr, open_ofun, open_size)); +@@ -2185,7 +2184,7 @@ + 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; + + if(global_oplock_break && (tran_call == TRANSACT2_OPEN)) { + /* Queue this open message as we are the process of an +@@ -2203,8 +2202,9 @@ + /* All trans2 messages we handle have smb_sucnt == 1 - ensure this + is so as a sanity check */ + if (suwcnt != 1) { +- DEBUG(2,("Invalid smb_sucnt in trans2 call\n")); +- return(ERROR(ERRSRV,ERRerror)); ++ DEBUG(2,("Invalid smb_sucnt in trans2 call(%u)\n",suwcnt)); ++ DEBUG(2,("Transaction is %d\n",tran_call)); ++ ERROR(ERRDOS,ERRinvalidparam); + } + + /* Allocate the space for the maximum needed parameters and data */ +@@ -2215,11 +2215,9 @@ + + if ((total_params && !params) || (total_data && !data)) { + DEBUG(2,("Out of memory in reply_trans2\n")); +- if(params) +- free(params); +- if(data) +- free(data); +- return(ERROR(ERRDOS,ERRnomem)); ++ SAFE_FREE(params); ++ SAFE_FREE(data); ++ return ERROR(ERRDOS,ERRnomem); + } + + /* Copy the param and data bytes sent with this request into +@@ -2230,20 +2228,37 @@ + 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 + of the parameter/data bytes */ + outsize = set_message(outbuf,0,0,True); +- send_smb(Client,outbuf); ++ if (!send_smb(Client,outbuf)) ++ exit_server("reply_trans2: send_smb failed."); + + 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); + +@@ -2255,26 +2270,55 @@ + else + DEBUG(0,("reply_trans2: %s in getting secondary trans2 response.\n", + (smb_read_error == READ_ERROR) ? "error" : "timeout" )); +- if(params) +- free(params); +- if(data) +- free(data); +- return(ERROR(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( ¶ms[ 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( ¶ms[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); ++ } + } + } + +@@ -2367,4 +2411,10 @@ + 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); ++ return (ERROR(ERRDOS,ERRinvalidparam)); + } |