Metric.cpp

Go to the documentation of this file.
00001 /*------------------------------------------------------------------------------
00002     This file is part of PHP-AST Project by Romain Gaucher (http://rgaucher.info).
00003 
00004     PHP-AST is free software: you can redistribute it and/or modify
00005     it under the terms of the GNU General Public License as published by
00006     the Free Software Foundation, either version 3 of the License, or
00007     (at your option) any later version.
00008 
00009     PHP-AST/ORACLE is distributed in the hope that it will be useful,
00010     but WITHOUT ANY WARRANTY; without even the implied warranty of
00011     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012     GNU General Public License for more details.
00013 
00014     You should have received a copy of the GNU General Public License
00015     along with PHP-AST.  If not, see <http://www.gnu.org/licenses/>.
00016 ------------------------------------------------------------------------------*/
00017 
00018 
00019 #include "AstNode.h"
00020 #include "tree.h"
00021 #include "AstContainer.h"
00022 #include "Metric.h"
00023 #include "Utils.h"
00024 #include <cstdlib>
00025 #include <string>
00026 #include <map>
00027 #include <iostream>
00028 #include <stack>
00029 using namespace std;
00030 
00031 std::ostream& operator<<(std::ostream& stream, const NumericResult& num) {
00032     stream << num.toString();
00033     return stream;
00034 }
00035 
00036 std::ostream& operator<<(std::ostream& stream, const MetricResult& metric) {
00037     stream << "(main=" << metric.main << ')';
00038     for (map<string, NumericResult>::const_iterator iter=metric.storage.begin(); iter!=metric.storage.end();++iter)
00039         stream << '(' << iter->first << "=" <<  iter->second << ')';
00040     return stream;
00041 }
00042 
00043 
00044 MetricResult NumberFunctions::operator()(const tree<AstNode>&, const MapClasses* classes , const MapVariables* vars, 
00045                                          const MapFunctions *func, const MapAssignments *assigns, const MapVarEquivalent *equiv)
00046 {
00047     MetricResult  result;
00048     NumericResult num;
00049     // return the number of functions in the current source code
00050     num = func->size();
00051     result.main = num;
00052     return result;
00053 }
00054 
00055 
00056 MetricResult NumberSinks::operator()(const tree<AstNode>& tr, const MapClasses* classes , const MapVariables* vars,
00057                                      const MapFunctions *func, const MapAssignments *assigns, const MapVarEquivalent *equiv)
00058 {
00059     MetricResult  result;
00060     NumericResult num;
00061     unsigned n = 0;
00062     // Get the outputs functions in the tree-functions. if there is one, just add the function into the list of sensitive
00063     std::map<std::string, BoxedFunction> boxedFunctions = ast->getBoxedFunctions();
00064     for (std::map<std::string, BoxedFunction>::iterator iter=boxedFunctions.begin();iter!=boxedFunctions.end();++iter)
00065     {
00066         // iterate through the boxedFunctions output
00067         bool add = false;
00068         for(MapFunctions::iterator jter=iter->second.output.begin();jter!=iter->second.output.end();++jter) {
00069             if (find(sensitive.begin(), sensitive.end(), jter->first) != sensitive.end()) {
00070                 add = true;
00071                 break;
00072             }
00073         }
00074         if (add) {
00075             if (find(sensitive.begin(), sensitive.end(), iter->first) == sensitive.end())
00076                 sensitive.push_back(iter->first);
00077         }
00078     }
00079 
00080     // return the number of functions in the current source code
00081     for (tree<AstNode>::iterator iter = tr.begin(); iter != tr.end(); ++iter) {
00082         string t = iter->getType();
00083         if (t == "unticked_function_declaration_statement") {
00084             iter = tr.end(iter);
00085         }
00086         else if (t == "function_call") {
00087             tree<AstNode>::iterator son = tr.begin(iter);
00088             if (son->getType() == "T_STRING") {
00089                 tree<AstNode>::iterator  textable = tr.begin(son);
00090                 if (textable->getType() == "text" && find(sensitive.begin(), sensitive.end(), textable->getValue()) != sensitive.end()) {
00091                     n++;
00092                 }
00093             }
00094         }
00095         else if (t == "unticked_statement" || t == "expr_without_variable") {
00096             tree<AstNode>::iterator son = tr.begin(iter);
00097             if (utils::start_with(son->getType(), "T_")) {
00098                 tree<AstNode>::iterator  textable = tr.begin(son);
00099                 if (textable->getType() == "text" && find(sensitive.begin(), sensitive.end(), textable->getValue()) != sensitive.end()) {
00100                     n++;
00101                 }
00102             }
00103         }
00104     }
00105     num = n;
00106     result.main = num;
00107     return result;
00108 }
00109 
00110 
00111 MetricResult NumberResources::operator()(const tree<AstNode>& tr, const MapClasses* classes , const MapVariables* vars,
00112                                      const MapFunctions *func, const MapAssignments *assigns, const MapVarEquivalent *equiv)
00113 {
00114     MetricResult  result;
00115     NumericResult num;
00116     unsigned n = 0;
00117     // Get the outputs functions in the tree-functions. if there is one, just add the function into the list of sensitive
00118     std::map<std::string, BoxedFunction> boxedFunctions = ast->getBoxedFunctions();
00119     for (std::map<std::string, BoxedFunction>::iterator iter=boxedFunctions.begin();iter!=boxedFunctions.end();++iter)
00120     {
00121         // iterate through the boxedFunctions output
00122         bool add = false;
00123         for(MapFunctions::iterator jter=iter->second.input.begin();jter!=iter->second.input.end();++jter) {
00124             if (find(taintedinput.begin(), taintedinput.end(), jter->first) != taintedinput.end()) {
00125                 add = true;
00126                 break;
00127             }
00128         }
00129         if (add) {
00130             if (find(taintedinput.begin(), taintedinput.end(), iter->first) == taintedinput.end())
00131                 taintedinput.push_back(iter->first);
00132         }
00133     }
00134     // return the number of functions in the current source code
00135     for (tree<AstNode>::iterator iter = tr.begin(); iter != tr.end(); ++iter) {
00136         string t = iter->getType();
00137         if (t == "unticked_function_declaration_statement") {
00138             iter = tr.end(iter);
00139         }
00140         else if (t == "function_call") {
00141             tree<AstNode>::iterator son = tr.begin(iter);
00142             if (son->getType() == "T_STRING") {
00143                 tree<AstNode>::iterator  textable = tr.begin(son);
00144                 if (textable->getType() == "text" && find(taintedinput.begin(), taintedinput.end(), textable->getValue()) != taintedinput.end()) {
00145                     n++;
00146                 }
00147             }
00148         }
00149         else if (t == "unticked_statement" || t == "expr_without_variable") {
00150             tree<AstNode>::iterator son = tr.begin(iter);
00151             if (utils::start_with(son->getType(), "T_")) {
00152                 tree<AstNode>::iterator  textable = tr.begin(son);
00153                 if (textable->getType() == "text" && find(taintedinput.begin(), taintedinput.end(), textable->getValue()) != taintedinput.end()) {
00154                     n++;
00155                 }
00156             }
00157         }
00158     }
00159 
00160     // add the boxed source
00161 
00162 
00163 
00164 
00165 
00166     num = n;
00167     result.main = num;
00168     return result;
00169 }
00170 
00171 
00172 
00173 
00174 
00175 MetricResult NumberVariables::operator()(const tree<AstNode>&, const MapClasses* classes , const MapVariables* vars,
00176                                          const MapFunctions *func, const MapAssignments *assigns, const MapVarEquivalent *equiv)
00177 {
00178     MetricResult  result;   
00179     NumericResult num;
00180     // return the number of functions in the current source code
00181     num = vars->size();
00182     result.main = num;
00183     return result;
00184 }
00185 
00186 
00187 MetricResult NumberClasses::operator()(const tree<AstNode>&, const MapClasses* classes , const MapVariables* vars, 
00188                                          const MapFunctions *func, const MapAssignments *assigns, const MapVarEquivalent *equiv)
00189 {
00190     MetricResult  result;   
00191     NumericResult num;
00192     // return the number of functions in the current source code
00193     num = classes->size();
00194     result.main = num;
00195     return result;
00196 }
00197 
00198 
00199 MetricResult NumberInput::operator()(const tree<AstNode>& tr, const MapClasses* classes , const MapVariables* vars, 
00200                                          const MapFunctions *func, const MapAssignments *assigns, const MapVarEquivalent *equiv)
00201 {
00202     MetricResult  result;   
00203     unsigned num=0;
00204     // Get the pointer on the tree with input entry defintion
00205     list<string> scanned;
00206     string temp,fullvarname;
00207     const tree<AstNode>*  def = defAST.getTreeConstPtr();
00208     // Go through all variables
00209     for(MapVariables::const_iterator iter=vars->begin(); iter!=vars->end();++iter)
00210     {
00211         for (AstVarBaseList::const_iterator jter=iter->second.begin();jter!=iter->second.end();++jter)
00212         {
00213             temp = jter->name;
00214             fullvarname = jter->name;
00215             if (jter->index.length() > 0) {
00216                  fullvarname += ('[' + jter->index + ']');
00217             }
00218             for (tree<AstNode>::leaf_iterator lter=def->begin_leaf();lter!=def->end_leaf();++lter)
00219             {
00220                 if (lter->getValue() == temp) {
00221                     if (find(scanned.begin(), scanned.end(), fullvarname) == scanned.end()) {
00222                         // Am I looking for an array somewhere?
00223                         tree<AstNode>::iterator tter=tr.parent(tr.begin(jter->position));
00224                         if (tr.number_of_children(tter) > 1)
00225                             num++;                          
00226                         scanned.push_back(fullvarname);
00227                     }                       
00228                 }
00229             }
00230         }
00231     }
00232     result.main = num;
00233     return result;
00234 }
00235 
00236 
00237 /**
00238     Same as NumberInput but counting with the dataflow:
00239 
00240     a = $_GET['b']
00241     b = $_GET['b']
00242 
00243     => 2
00244 */
00245 MetricResult NumberDiffuseInputs::operator()(const tree<AstNode>& tr, const MapClasses* classes , const MapVariables* vars,
00246                                          const MapFunctions *func, const MapAssignments *assigns, const MapVarEquivalent *equiv)
00247 {
00248     MetricResult  result;   
00249     unsigned num=0;
00250     // Get the pointer on the tree with input entry defintion
00251     list<string> scanned;
00252     string temp,fullvarname;
00253     const tree<AstNode>*  def = defAST.getTreeConstPtr();
00254     
00255     // Go through all variables
00256     for(MapVariables::const_iterator iter=vars->begin(); iter!=vars->end();++iter)
00257     {
00258         for (AstVarBaseList::const_iterator jter=iter->second.begin();jter!=iter->second.end();++jter)
00259         {
00260             temp = jter->name;
00261             fullvarname = jter->name;
00262             if (jter->index.length() > 0) {
00263                  fullvarname += ('[' + jter->index + ']');
00264             }
00265             for (tree<AstNode>::leaf_iterator lter=def->begin_leaf();lter!=def->end_leaf();++lter)
00266             {
00267                 if (lter->getValue() == temp) {
00268                     if (find(scanned.begin(), scanned.end(), fullvarname) == scanned.end()) {
00269                         // Am I looking for an array somewhere?
00270                         tree<AstNode>::iterator tter=tr.parent(tr.begin(jter->position));
00271                         if (tr.number_of_children(tter) > 1)
00272                             num++;                          
00273                         scanned.push_back(fullvarname);
00274                     }                       
00275                 }
00276             }
00277         }
00278     }
00279 
00280     // Then, add the assignments variables recursivle of the scanned listen
00281     // cerr << "Equivalences:" << endl;
00282     for (MapAssignments::const_iterator iter = assigns->begin(); iter != assigns->end(); ++iter)
00283     {
00284         fullvarname = iter->second.name;
00285         if (iter->second.index.length() > 0) {
00286              fullvarname += ('[' + iter->second.index + ']');
00287         }
00288         
00289         string tname = iter->first.name;
00290         if (iter->first.index.length() > 0) {
00291              tname += ('[' + iter->first.index + ']');
00292         }
00293         if (find(scanned.begin(), scanned.end(), fullvarname) != scanned.end()){
00294             num++;  
00295         }
00296     }
00297     result.main = num;
00298     return result;
00299 }
00300 
00301 
00302 MetricResult NumberSunkDiffuseInputs::operator()(const tree<AstNode>& tr, const MapClasses* classes , const MapVariables* vars,
00303                                          const MapFunctions *func, const MapAssignments *assigns, const MapVarEquivalent *equiv)
00304 {
00305     MetricResult  result;
00306     unsigned num = 0;
00307     
00308     // Get the pointer on the tree with input entry defintion
00309     list<string> scanned, varsList;
00310     list<VarBase> varBaseList;
00311     string temp,fullvarname;
00312     const tree<AstNode>*  def = defAST.getTreeConstPtr();
00313 
00314     std::map<std::string, BoxedFunction> boxedFunctions = ast->getBoxedFunctions();
00315     for (std::map<std::string, BoxedFunction>::iterator iter=boxedFunctions.begin();iter!=boxedFunctions.end();++iter)
00316     {
00317         // iterate through the boxedFunctions output
00318         bool add = false;
00319         for(MapFunctions::iterator jter=iter->second.output.begin();jter!=iter->second.output.end();++jter) {
00320             if (find(sensitive.begin(), sensitive.end(), jter->first) != sensitive.end()) {
00321                 add = true;
00322                 cout << "Add this function into sensitive sinks: '" << iter->first <<  "' because of -- " << jter->first <<endl;
00323                 break;
00324             }
00325         }
00326         if (add) {
00327             if (find(sensitive.begin(), sensitive.end(), iter->first) == sensitive.end())
00328                 sensitive.push_back(iter->first);
00329         }
00330     }
00331 
00332     // Go through all variables
00333     for(MapVariables::const_iterator iter=vars->begin(); iter!=vars->end();++iter)
00334     {
00335         for (AstVarBaseList::const_iterator jter=iter->second.begin();jter!=iter->second.end();++jter)
00336         {
00337             temp = jter->name;
00338             fullvarname = jter->name;
00339             if (jter->index.length() > 0) {
00340                  fullvarname += ('[' + jter->index + ']');
00341             }
00342             for (tree<AstNode>::leaf_iterator lter=def->begin_leaf();lter!=def->end_leaf();++lter)
00343             {
00344                 if (lter->getValue() == temp) {
00345                     if (find(scanned.begin(), scanned.end(), fullvarname) == scanned.end()) {
00346                         // Am I looking for an array somewhere?
00347                         tree<AstNode>::iterator tter=tr.parent(tr.begin(jter->position));
00348                         //if (tr.number_of_children(tter) > 1)
00349                         //  num++;                          
00350                         scanned.push_back(fullvarname);
00351                         varsList.push_back(fullvarname);
00352                         varBaseList.push_back(*jter);
00353                     }                       
00354                 }
00355             }
00356         }
00357     }
00358 
00359     // Then, add the assignments variables recursivly of the scanned listen
00360     string asname, bsname;
00361 
00362     list<string> curVars, forbidden;
00363 
00364     for (list<string>::const_iterator jter=varsList.begin(); jter!=varsList.end();++jter) 
00365         if (find(curVars.begin(),curVars.end(),*jter) == curVars.end())
00366             curVars.push_back(*jter);
00367     while(curVars.size() > 0)
00368     {
00369         // take the first element on the stack
00370         string elmt = *(curVars.begin());
00371         // look at all assignement
00372         for (MapAssignments::const_iterator iter = assigns->begin(); iter != assigns->end(); ++iter)
00373         {
00374             asname = iter->first.name;
00375             if (iter->first.index.length() > 0) {
00376                  asname += ('[' + iter->first.index + ']');
00377             }
00378             bsname = iter->second.name;
00379             if (iter->second.index.length() > 0) {
00380                  bsname += ('[' + iter->second.index + ']');
00381             }
00382             if (bsname == elmt && find(forbidden.begin(),forbidden.end(),asname) == forbidden.end()) {
00383                 if (find(curVars.begin(),curVars.end(),asname) == curVars.end())
00384                     curVars.push_back(asname);
00385                 if (find(varsList.begin(),varsList.end(),asname) == varsList.end()) {
00386                     varsList.push_back(asname);
00387                     varBaseList.push_back(iter->first);
00388                 }
00389             }
00390         }
00391         curVars.pop_front();
00392         forbidden.push_back(elmt);
00393     }
00394 
00395     // What about the equivalences now?
00396     for (MapVarEquivalent::const_iterator iter = equiv->begin(); iter != equiv->end(); ++iter)
00397     {
00398         asname = iter->first.name;
00399         if (iter->first.index.length() > 0) {
00400              asname += ('[' + iter->first.index + ']');
00401         }
00402         // does the variable has an equivalence?
00403         for (AstVarBaseList::const_iterator jter=iter->second.begin(); jter!=iter->second.end();++jter) {
00404             bsname = jter->name;
00405             if (jter->index.length() > 0) {
00406                  bsname += ('[' + jter->index + ']');
00407             }
00408 
00409             if (find(varsList.begin(),varsList.end(),bsname) != varsList.end()) {
00410                 if (find(varsList.begin(), varsList.end(), asname) == varsList.end()){
00411                     //num++;
00412                     varsList.push_back(asname);
00413                     varBaseList.push_back(iter->first);
00414                 }
00415             }
00416         }
00417     }
00418     // So, what do we have in the varsList?
00419     cerr << endl << "####################" << endl << "List of variables:" << endl;
00420     for(list<string>::const_iterator k=varsList.begin();k!=varsList.end();++k)
00421         cerr << *k << ',';
00422     cerr << endl << "####################" << endl << endl;
00423 
00424     string type,function;
00425     tree<AstNode>::iterator child, parent;
00426     // Now, for now, for all variables, look if there are called in sensitive sinks
00427     for (tree<AstNode>::iterator iter=tr.begin();iter!=tr.end();++iter)
00428     {
00429         type = iter->getType();
00430         //
00431         if (type == "function_call"
00432         || (utils::start_with(type, "T_") && (type != "T_CONSTANT_ENCAPSED_STRING" && type != "T_VARIABLE" && type != "T_STRING") )) {
00433             // we have a possible position
00434             if (type == "function_call")
00435             {
00436                 // get the T_STRING value
00437                 for (tree<AstNode>::iterator jter=iter;jter!=tr.end(iter);++jter) {
00438                     if (jter->getType() == "T_STRING") {
00439                         // gotcha!
00440                         child = jter;
00441                         break;
00442                     }
00443                 }
00444                 // get the function name
00445                 if (tr.number_of_children(child) == 1) {
00446                     function = tr.child(child,0)->getValue();
00447                     if (find(sensitive.begin(),sensitive.end(),function) != sensitive.end())
00448                     {
00449                         // we now have a sensitive sinks, let's look in the parameters
00450                         list<VarBase> subVariables= ast->getSubVariables(iter);
00451                         // print subvariable's
00452                         //cerr << function << '(';
00453                         //for (list<VarBase>::const_iterator vter=subVariables.begin();vter!=subVariables.end();++vter)
00454                         //  cerr << *vter << ',';
00455                         //cerr << ')' << endl;
00456 
00457                         for (list<VarBase>::const_iterator vter=subVariables.begin();vter!=subVariables.end();++vter)
00458                         {
00459                             string tname = vter->name;
00460                             if (vter->index.length() > 0) {
00461                                  tname += ('[' + vter->index + ']');
00462                             }
00463                             if (find(varsList.begin(), varsList.end(), tname) != varsList.end()) {
00464                                 // found one!
00465                                 num++;
00466                                 cerr << "(function_call) Sink |Diffuse input : " << function << " (" << tname << ")" << endl;
00467                                 break;
00468                             }
00469                         }
00470                     }
00471                 }
00472                 // skipping...
00473                 iter = child;
00474             }
00475             else
00476             {
00477                 function = "";
00478                 // get name of the T_ call ? die, echo, print, assert ?
00479                 tree<AstNode>::iterator jter = tr.begin(iter);
00480                 for (;jter!=tr.end(iter);++jter) {
00481                     if (jter->getType() == "text") {// gotcha!
00482                         function = jter->getValue();
00483                         break;
00484                     }
00485                 }
00486                 if (find(sensitive.begin(),sensitive.end(),function) != sensitive.end())
00487                 {
00488                 
00489                     // we now have a sensitive sinks, let's look in the parameters
00490                     list<VarBase> subVariables= ast->getSubVariables(tr.parent(iter));
00491                     // print subvariable's
00492                     //cerr << function << '(';
00493                     //for (list<VarBase>::const_iterator vter=subVariables.begin();vter!=subVariables.end();++vter)
00494                     //  cerr << *vter << ',';
00495                     //cerr << ')' << endl;
00496 
00497                     for (list<VarBase>::const_iterator vter=subVariables.begin();vter!=subVariables.end();++vter)
00498                     {
00499                         string tname = vter->name;
00500                         if (vter->index.length() > 0) {
00501                              tname += ('[' + vter->index + ']');
00502                         }
00503                         //cerr << tname << endl;
00504                         if (find(varsList.begin(), varsList.end(), tname) != varsList.end()) {
00505                             // found one!
00506                             num++;
00507                             cerr << "(language_dependant) Sink |Diffuse input : " << function << " | " << tname << endl;
00508                             break;
00509                         }
00510                         else
00511                         {
00512                             // maybe we can count it.
00513                             // echo $array[$i] in a loop or with the index
00514                             if (vter->index.length() > 0)
00515                             {
00516                                 // look at if there is a var
00517                                 for (list<VarBase>::const_iterator bter=varBaseList.begin();bter!=varBaseList.end();++bter)
00518                                 {
00519                                     if (bter->name == vter->name && find(varsList.begin(), varsList.end(), vter->index) == varsList.end()) {
00520                                         // if the index is a variable?
00521                                         if (vter->index[0] == '$') {
00522                                             num++;
00523                                             cerr << "(language_dependant) Sink |Diffuse input : " << function << " | " << tname << endl;
00524                                         }
00525                                         break;
00526                                     }
00527                                 }
00528                             }
00529                         }
00530                     }
00531                 }
00532                 // skipping...
00533                 iter = jter;
00534             }
00535         }
00536     }
00537     
00538     
00539     
00540     result.main = num;
00541     return result;
00542 }

Generated on Wed Feb 27 20:31:06 2008 for php.ast.svn.src. by  doxygen 1.5.3