mirror of
https://github.com/github/codeql.git
synced 2026-04-12 18:44:00 +02:00
Merge branch 'main' of https://github.com/github/codeql into post-release-prep/codeql-cli-2.25.1
This commit is contained in:
@@ -11,10 +11,14 @@
|
||||
*/
|
||||
|
||||
import python
|
||||
private import LegacyPointsTo
|
||||
private import semmle.python.dataflow.new.internal.DataFlowDispatch
|
||||
|
||||
from PropertyObject prop, ClassObject cls
|
||||
where cls.declaredAttribute(_) = prop and not cls.failedInference() and not cls.isNewStyle()
|
||||
select prop,
|
||||
from Function prop, Class cls, Name decorator
|
||||
where
|
||||
prop.getScope() = cls and
|
||||
decorator = prop.getADecorator() and
|
||||
decorator.getId() = "property" and
|
||||
not DuckTyping::isNewStyle(cls)
|
||||
select decorator,
|
||||
"Property " + prop.getName() + " will not work properly, as class " + cls.getName() +
|
||||
" is an old-style class."
|
||||
|
||||
@@ -14,10 +14,12 @@
|
||||
*/
|
||||
|
||||
import python
|
||||
private import LegacyPointsTo
|
||||
private import semmle.python.dataflow.new.internal.DataFlowDispatch
|
||||
|
||||
from ClassValue c
|
||||
where not c.isBuiltin() and not c.isContextManager() and exists(c.declaredAttribute("__del__"))
|
||||
from Class c
|
||||
where
|
||||
not DuckTyping::isContextManager(c) and
|
||||
exists(c.getMethod("__del__"))
|
||||
select c,
|
||||
"Class " + c.getName() +
|
||||
" implements __del__ (presumably to release some resource). Consider making it a context manager."
|
||||
|
||||
@@ -12,9 +12,11 @@
|
||||
*/
|
||||
|
||||
import python
|
||||
private import LegacyPointsTo
|
||||
private import semmle.python.dataflow.new.internal.DataFlowDispatch
|
||||
|
||||
from ClassObject c
|
||||
where not c.isNewStyle() and c.declaresAttribute("__slots__") and not c.failedInference()
|
||||
from Class c
|
||||
where
|
||||
not DuckTyping::isNewStyle(c) and
|
||||
DuckTyping::declaresAttribute(c, "__slots__")
|
||||
select c,
|
||||
"Using '__slots__' in an old style class just creates a class attribute called '__slots__'."
|
||||
|
||||
@@ -11,14 +11,13 @@
|
||||
*/
|
||||
|
||||
import python
|
||||
private import LegacyPointsTo
|
||||
private import semmle.python.dataflow.new.internal.DataFlowDispatch
|
||||
|
||||
predicate uses_of_super_in_old_style_class(Call s) {
|
||||
exists(Function f, ClassObject c |
|
||||
exists(Function f, Class c |
|
||||
s.getScope() = f and
|
||||
f.getScope() = c.getPyClass() and
|
||||
not c.failedInference() and
|
||||
not c.isNewStyle() and
|
||||
f.getScope() = c and
|
||||
not DuckTyping::isNewStyle(c) and
|
||||
s.getFunc().(Name).getId() = "super"
|
||||
)
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
*/
|
||||
|
||||
import python
|
||||
private import LegacyPointsTo
|
||||
private import semmle.python.dataflow.new.internal.DataFlowDispatch
|
||||
|
||||
predicate fewer_than_two_public_methods(Class cls, int methods) {
|
||||
(methods = 0 or methods = 1) and
|
||||
@@ -25,13 +25,8 @@ predicate does_not_define_special_method(Class cls) {
|
||||
}
|
||||
|
||||
predicate no_inheritance(Class c) {
|
||||
not exists(ClassValue cls, ClassValue other |
|
||||
cls.getScope() = c and
|
||||
other != ClassValue::object()
|
||||
|
|
||||
other.getABaseType() = cls or
|
||||
cls.getABaseType() = other
|
||||
) and
|
||||
not exists(getADirectSubclass(c)) and
|
||||
not exists(getADirectSuperclass(c)) and
|
||||
not exists(Expr base | base = c.getABase() |
|
||||
not base instanceof Name or base.(Name).getId() != "object"
|
||||
)
|
||||
|
||||
@@ -10,9 +10,10 @@
|
||||
*/
|
||||
|
||||
import python
|
||||
private import LegacyPointsTo
|
||||
private import semmle.python.types.Builtins
|
||||
private import semmle.python.ApiGraphs
|
||||
|
||||
from CallNode call, ControlFlowNodeWithPointsTo func
|
||||
where major_version() = 2 and call.getFunction() = func and func.pointsTo(Value::named("apply"))
|
||||
from CallNode call
|
||||
where
|
||||
major_version() = 2 and
|
||||
call = API::builtin("apply").getACall().asCfgNode()
|
||||
select call, "Call to the obsolete builtin function 'apply'."
|
||||
|
||||
@@ -10,16 +10,17 @@
|
||||
*/
|
||||
|
||||
import python
|
||||
private import LegacyPointsTo
|
||||
private import semmle.python.dataflow.new.internal.DataFlowDispatch
|
||||
|
||||
predicate slice_method_name(string name) {
|
||||
name = "__getslice__" or name = "__setslice__" or name = "__delslice__"
|
||||
}
|
||||
|
||||
from PythonFunctionValue f, string meth
|
||||
from Function f, string meth
|
||||
where
|
||||
f.getScope().isMethod() and
|
||||
not f.isOverridingMethod() and
|
||||
f.isMethod() and
|
||||
slice_method_name(meth) and
|
||||
f.getName() = meth
|
||||
f.getName() = meth and
|
||||
not DuckTyping::overridesMethod(f) and
|
||||
not DuckTyping::hasUnresolvedBase(getADirectSuperclass*(f.getScope()))
|
||||
select f, meth + " method has been deprecated since Python 2.0."
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
*/
|
||||
|
||||
import python
|
||||
private import LegacyPointsTo
|
||||
private import semmle.python.ApiGraphs
|
||||
|
||||
/**
|
||||
* Holds if the module `name` was deprecated in Python version `major`.`minor`,
|
||||
@@ -80,7 +80,7 @@ where
|
||||
name = imp.getName() and
|
||||
deprecated_module(name, instead, _, _) and
|
||||
not exists(Try try, ExceptStmt except | except = try.getAHandler() |
|
||||
except.getType().(ExprWithPointsTo).pointsTo(ClassValue::importError()) and
|
||||
except.getType() = API::builtin("ImportError").getAValueReachableFromSource().asExpr() and
|
||||
except.containsInScope(imp)
|
||||
)
|
||||
select imp, deprecation_message(name) + replacement_message(name)
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* cause a cross-site scripting vulnerability.
|
||||
* @kind problem
|
||||
* @problem.severity error
|
||||
* @security-severity 6.1
|
||||
* @security-severity 7.8
|
||||
* @precision medium
|
||||
* @id py/jinja2/autoescape-false
|
||||
* @tags security
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* allows for a cross-site scripting vulnerability.
|
||||
* @kind path-problem
|
||||
* @problem.severity error
|
||||
* @security-severity 6.1
|
||||
* @security-severity 7.8
|
||||
* @sub-severity high
|
||||
* @precision high
|
||||
* @id py/reflective-xss
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* insertion of forged log entries by a malicious user.
|
||||
* @kind path-problem
|
||||
* @problem.severity error
|
||||
* @security-severity 7.8
|
||||
* @security-severity 6.1
|
||||
* @precision medium
|
||||
* @id py/log-injection
|
||||
* @tags security
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
*/
|
||||
|
||||
import python
|
||||
private import LegacyPointsTo
|
||||
private import semmle.python.dataflow.new.internal.DataFlowDispatch
|
||||
|
||||
predicate needs_docstring(Scope s) {
|
||||
s.isPublic() and
|
||||
@@ -29,15 +29,13 @@ predicate needs_docstring(Scope s) {
|
||||
}
|
||||
|
||||
predicate function_needs_docstring(FunctionMetrics f) {
|
||||
not exists(FunctionValue fo, FunctionValue base | fo.overrides(base) and fo.getScope() = f |
|
||||
not function_needs_docstring(base.getScope())
|
||||
not exists(Function base |
|
||||
DuckTyping::overridesMethod(f, _, base) and
|
||||
not function_needs_docstring(base)
|
||||
) and
|
||||
f.getName() != "lambda" and
|
||||
(f.getNumberOfLinesOfCode() - count(f.getADecorator())) > 2 and
|
||||
not exists(PythonPropertyObject p |
|
||||
p.getGetter().getFunction() = f or
|
||||
p.getSetter().getFunction() = f
|
||||
)
|
||||
not DuckTyping::isPropertyAccessor(f)
|
||||
}
|
||||
|
||||
string scope_type(Scope s) {
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
*/
|
||||
|
||||
import python
|
||||
private import LegacyPointsTo
|
||||
private import semmle.python.ApiGraphs
|
||||
|
||||
predicate func_with_side_effects(Expr e) {
|
||||
exists(string name | name = e.(Attribute).getName() or name = e.(Name).getId() |
|
||||
@@ -24,11 +24,11 @@ predicate func_with_side_effects(Expr e) {
|
||||
}
|
||||
|
||||
predicate call_with_side_effect(Call e) {
|
||||
e.getAFlowNode() = Value::named("subprocess.call").getACall()
|
||||
or
|
||||
e.getAFlowNode() = Value::named("subprocess.check_call").getACall()
|
||||
or
|
||||
e.getAFlowNode() = Value::named("subprocess.check_output").getACall()
|
||||
e.getAFlowNode() =
|
||||
API::moduleImport("subprocess")
|
||||
.getMember(["call", "check_call", "check_output"])
|
||||
.getACall()
|
||||
.asCfgNode()
|
||||
}
|
||||
|
||||
predicate probable_side_effect(Expr e) {
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
*/
|
||||
|
||||
import python
|
||||
private import LegacyPointsTo
|
||||
|
||||
predicate main_eq_name(If i) {
|
||||
exists(Name n, StringLiteral m, Compare c |
|
||||
@@ -32,10 +31,19 @@ predicate is_print_stmt(Stmt s) {
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if module `m` is likely used as a module (imported by another module),
|
||||
* as opposed to being exclusively used as a script.
|
||||
*/
|
||||
predicate is_used_as_module(Module m) {
|
||||
m.isPackageInit()
|
||||
or
|
||||
exists(ImportingStmt i | i.getAnImportedModuleName() = m.getName())
|
||||
}
|
||||
|
||||
from Stmt p
|
||||
where
|
||||
is_print_stmt(p) and
|
||||
// TODO: Need to discuss how we would like to handle ModuleObject.getKind in the glorious future
|
||||
exists(ModuleValue m | m.getScope() = p.getScope() and m.isUsedAsModule()) and
|
||||
is_used_as_module(p.getScope()) and
|
||||
not exists(If i | main_eq_name(i) and i.getASubStatement().getASubStatement*() = p)
|
||||
select p, "Print statement may execute during import."
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
*/
|
||||
|
||||
import python
|
||||
private import LegacyPointsTo
|
||||
private import semmle.python.ApiGraphs
|
||||
|
||||
predicate isInsideLoop(AstNode node) {
|
||||
node.getParentNode() instanceof While
|
||||
@@ -33,9 +33,9 @@ where
|
||||
not isInsideLoop(del) and
|
||||
// False positive: calling `sys.exc_info` within a function results in a
|
||||
// reference cycle, and an explicit call to `del` helps break this cycle.
|
||||
not exists(FunctionValue ex |
|
||||
ex = Value::named("sys.exc_info") and
|
||||
ex.getACall().getScope() = f
|
||||
not exists(API::CallNode call |
|
||||
call = API::moduleImport("sys").getMember("exc_info").getACall() and
|
||||
call.getScope() = f
|
||||
)
|
||||
select del, "Unnecessary deletion of local variable $@ in function $@.", e, e.toString(), f,
|
||||
f.getName()
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
*/
|
||||
|
||||
import python
|
||||
private import LegacyPointsTo
|
||||
private import semmle.python.ApiGraphs
|
||||
import Definition
|
||||
|
||||
predicate is_increment(Stmt s) {
|
||||
@@ -41,26 +41,19 @@ predicate one_item_only(For f) {
|
||||
)
|
||||
}
|
||||
|
||||
predicate points_to_call_to_range(ControlFlowNode f) {
|
||||
/* (x)range is a function in Py2 and a class in Py3, so we must treat it as a plain object */
|
||||
exists(Value range |
|
||||
range = Value::named("range") or
|
||||
range = Value::named("xrange")
|
||||
|
|
||||
f = range.getACall()
|
||||
)
|
||||
/** Holds if `node` is a call to `range`, `xrange`, or `list(range(...))`. */
|
||||
predicate call_to_range(DataFlow::Node node) {
|
||||
node = API::builtin(["range", "xrange"]).getACall()
|
||||
or
|
||||
/* In case points-to fails due to 'from six.moves import range' or similar. */
|
||||
exists(string range | f.getNode().(Call).getFunc().(Name).getId() = range |
|
||||
range = "range" or range = "xrange"
|
||||
)
|
||||
/* Handle 'from six.moves import range' or similar. */
|
||||
node = API::moduleImport("six").getMember("moves").getMember(["range", "xrange"]).getACall()
|
||||
or
|
||||
/* Handle list(range(...)) and list(list(range(...))) */
|
||||
f.(CallNode).(ControlFlowNodeWithPointsTo).pointsTo().getClass() = ClassValue::list() and
|
||||
points_to_call_to_range(f.(CallNode).getArg(0))
|
||||
node = API::builtin("list").getACall() and
|
||||
call_to_range(node.(DataFlow::CallCfgNode).getArg(0))
|
||||
}
|
||||
|
||||
/** Whether n is a use of a variable that is a not effectively a constant. */
|
||||
/** Whether n is a use of a variable that is not effectively a constant. */
|
||||
predicate use_of_non_constant(Name n) {
|
||||
exists(Variable var |
|
||||
n.uses(var) and
|
||||
@@ -102,8 +95,8 @@ from For f, Variable v, string msg
|
||||
where
|
||||
f.getTarget() = v.getAnAccess() and
|
||||
not f.getAStmt().contains(v.getAnAccess()) and
|
||||
not points_to_call_to_range(f.getIter().getAFlowNode()) and
|
||||
not points_to_call_to_range(get_comp_iterable(f)) and
|
||||
not call_to_range(DataFlow::exprNode(f.getIter())) and
|
||||
not call_to_range(DataFlow::exprNode(get_comp_iterable(f).getNode())) and
|
||||
not name_acceptable_for_unused_variable(v) and
|
||||
not f.getScope().getName() = "genexpr" and
|
||||
not empty_loop(f) and
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
category: queryMetadata
|
||||
---
|
||||
* The `@security-severity` metadata of `py/log-injection` has been reduced from 7.8 (high) to 6.1 (medium).
|
||||
* The `@security-severity` metadata of `py/jinja2/autoescape-false` and `py/reflective-xss` has been increased from 6.1 (medium) to 7.8 (high).
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
category: majorAnalysis
|
||||
---
|
||||
|
||||
- Several quality queries have been ported away from using the legacy points-to library. This may lead to changes in alerts.
|
||||
Reference in New Issue
Block a user