Skip to content

Commit 9c8e232

Browse files
committed
Merge branch 'main' into criemen/js-bazel
2 parents be02512 + 697a7b8 commit 9c8e232

File tree

45 files changed

+1014
-349
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

45 files changed

+1014
-349
lines changed

cpp/ql/lib/semmle/code/cpp/models/implementations/Inet.qll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@ private class Getaddrinfo extends TaintFunction, ArrayFunction, RemoteFlowSource
157157
override predicate hasArrayWithNullTerminator(int bufParam) { bufParam in [0, 1] }
158158

159159
override predicate hasRemoteFlowSource(FunctionOutput output, string description) {
160-
output.isParameterDeref(3) and
160+
output.isParameterDeref(3, 2) and
161161
description = "address returned by " + this.getName()
162162
}
163163
}

cpp/ql/lib/semmle/code/cpp/models/implementations/Send.qll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ private class Send extends AliasFunction, ArrayFunction, SideEffectFunction, Rem
5858
override ParameterIndex getParameterSizeIndex(ParameterIndex i) { i = 1 and result = 2 }
5959

6060
override predicate hasRemoteFlowSink(FunctionInput input, string description) {
61-
input.isParameterDeref(1) and description = "buffer sent by " + this.getName()
61+
input.isParameterDeref(1, 1) and description = "buffer sent by " + this.getName()
6262
}
6363

6464
override predicate hasSocketInput(FunctionInput input) { input.isParameter(0) }

cpp/ql/lib/semmle/code/cpp/models/interfaces/FunctionInputsAndOutputs.qll

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import semmle.code.cpp.Parameter
88

99
private newtype TFunctionInput =
1010
TInParameter(ParameterIndex i) or
11-
TInParameterDeref(ParameterIndex i) or
11+
TInParameterDeref(ParameterIndex i, int indirectionIndex) { indirectionIndex = [1, 2] } or
1212
TInQualifierObject() or
1313
TInQualifierAddress() or
1414
TInReturnValueDeref()
@@ -245,15 +245,18 @@ class InParameter extends FunctionInput, TInParameter {
245245
*/
246246
class InParameterDeref extends FunctionInput, TInParameterDeref {
247247
ParameterIndex index;
248+
int indirectionIndex;
248249

249-
InParameterDeref() { this = TInParameterDeref(index) }
250+
InParameterDeref() { this = TInParameterDeref(index, indirectionIndex) }
250251

251252
override string toString() { result = "InParameterDeref " + index.toString() }
252253

253254
/** Gets the zero-based index of the parameter. */
254255
ParameterIndex getIndex() { result = index }
255256

256-
override predicate isParameterDeref(ParameterIndex i) { i = index }
257+
override predicate isParameterDeref(ParameterIndex i, int indirection) {
258+
i = index and indirectionIndex = indirection
259+
}
257260
}
258261

259262
/**
@@ -321,10 +324,10 @@ class InReturnValueDeref extends FunctionInput, TInReturnValueDeref {
321324
}
322325

323326
private newtype TFunctionOutput =
324-
TOutParameterDeref(ParameterIndex i) or
327+
TOutParameterDeref(ParameterIndex i, int indirectionIndex) { indirectionIndex = [1, 2] } or
325328
TOutQualifierObject() or
326329
TOutReturnValue() or
327-
TOutReturnValueDeref()
330+
TOutReturnValueDeref(int indirections) { indirections = [1, 2] }
328331

329332
/**
330333
* An output from a function. This can be:
@@ -498,17 +501,16 @@ class FunctionOutput extends TFunctionOutput {
498501
*/
499502
class OutParameterDeref extends FunctionOutput, TOutParameterDeref {
500503
ParameterIndex index;
504+
int indirectionIndex;
501505

502-
OutParameterDeref() { this = TOutParameterDeref(index) }
506+
OutParameterDeref() { this = TOutParameterDeref(index, indirectionIndex) }
503507

504508
override string toString() { result = "OutParameterDeref " + index.toString() }
505509

506510
ParameterIndex getIndex() { result = index }
507511

508-
override predicate isParameterDeref(ParameterIndex i) { i = index }
509-
510512
override predicate isParameterDeref(ParameterIndex i, int ind) {
511-
this.isParameterDeref(i) and ind = 1
513+
i = index and ind = indirectionIndex
512514
}
513515
}
514516

@@ -572,4 +574,8 @@ class OutReturnValueDeref extends FunctionOutput, TOutReturnValueDeref {
572574
override string toString() { result = "OutReturnValueDeref" }
573575

574576
override predicate isReturnValueDeref() { any() }
577+
578+
override predicate isReturnValueDeref(int indirectionIndex) {
579+
this = TOutReturnValueDeref(indirectionIndex)
580+
}
575581
}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
failures
21
testFailures
2+
failures

cpp/ql/test/library-tests/dataflow/taint-tests/localTaint.expected

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6646,6 +6646,17 @@ WARNING: Module TaintTracking has been deprecated and may be removed in future (
66466646
| taint.cpp:738:17:738:31 | call to indirect_source | taint.cpp:739:30:739:35 | source | |
66476647
| taint.cpp:739:22:739:28 | call to realloc | taint.cpp:740:7:740:10 | dest | |
66486648
| taint.cpp:739:30:739:35 | source | taint.cpp:739:22:739:28 | call to realloc | TAINT |
6649+
| taint.cpp:743:40:743:45 | buffer | taint.cpp:744:5:744:10 | buffer | |
6650+
| taint.cpp:743:40:743:45 | buffer | taint.cpp:745:27:745:32 | buffer | |
6651+
| taint.cpp:744:4:744:10 | * ... | taint.cpp:744:3:744:10 | * ... | TAINT |
6652+
| taint.cpp:744:5:744:10 | buffer | taint.cpp:744:4:744:10 | * ... | TAINT |
6653+
| taint.cpp:744:14:744:19 | call to source | taint.cpp:744:3:744:21 | ... = ... | |
6654+
| taint.cpp:745:19:745:25 | call to realloc | taint.cpp:743:40:743:45 | buffer | |
6655+
| taint.cpp:745:19:745:25 | call to realloc | taint.cpp:745:3:745:37 | ... = ... | |
6656+
| taint.cpp:745:19:745:25 | call to realloc | taint.cpp:746:10:746:15 | buffer | |
6657+
| taint.cpp:745:27:745:32 | buffer | taint.cpp:745:19:745:25 | call to realloc | TAINT |
6658+
| taint.cpp:746:9:746:15 | * ... | taint.cpp:746:8:746:15 | * ... | TAINT |
6659+
| taint.cpp:746:10:746:15 | buffer | taint.cpp:746:9:746:15 | * ... | TAINT |
66496660
| vector.cpp:16:43:16:49 | source1 | vector.cpp:17:26:17:32 | source1 | |
66506661
| vector.cpp:16:43:16:49 | source1 | vector.cpp:31:38:31:44 | source1 | |
66516662
| vector.cpp:17:21:17:33 | call to vector | vector.cpp:19:14:19:14 | v | |

cpp/ql/test/library-tests/dataflow/taint-tests/taint.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -738,4 +738,10 @@ void test_realloc() {
738738
char *source = indirect_source();
739739
char *dest = (char*)realloc(source, 16);
740740
sink(dest); // $ ir MISSING: ast
741+
}
742+
743+
void test_realloc_2_indirections(int **buffer) {
744+
**buffer = source();
745+
buffer = (int**)realloc(buffer, 16);
746+
sink(**buffer); // $ ir MISSING: ast
741747
}

csharp/extractor/Semmle.Extraction.CSharp.DependencyFetching/AssemblyCache.cs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,12 +27,18 @@ public AssemblyCache(IEnumerable<string> paths, ProgressMonitor progressMonitor)
2727
if (File.Exists(path))
2828
{
2929
pendingDllsToIndex.Enqueue(path);
30+
continue;
3031
}
31-
else
32+
33+
if (Directory.Exists(path))
3234
{
3335
progressMonitor.FindingFiles(path);
3436
AddReferenceDirectory(path);
3537
}
38+
else
39+
{
40+
progressMonitor.LogInfo("AssemblyCache: Path not found: " + path);
41+
}
3642
}
3743
IndexReferences();
3844
}
Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.IO;
4+
using System.Linq;
5+
using Newtonsoft.Json.Linq;
6+
using Semmle.Util;
7+
8+
namespace Semmle.Extraction.CSharp.DependencyFetching
9+
{
10+
/// <summary>
11+
/// Class for parsing project.assets.json files.
12+
/// </summary>
13+
internal class Assets
14+
{
15+
private readonly ProgressMonitor progressMonitor;
16+
17+
private static readonly string[] netFrameworks = new[] {
18+
"microsoft.aspnetcore.app.ref",
19+
"microsoft.netcore.app.ref",
20+
"microsoft.netframework.referenceassemblies",
21+
"microsoft.windowsdesktop.app.ref",
22+
"netstandard.library.ref"
23+
};
24+
25+
internal Assets(ProgressMonitor progressMonitor)
26+
{
27+
this.progressMonitor = progressMonitor;
28+
}
29+
30+
/// <summary>
31+
/// Class needed for deserializing parts of an assets file.
32+
/// It holds information about a reference.
33+
///
34+
/// Type carries the type of the reference.
35+
/// We are only interested in package references.
36+
///
37+
/// Compile holds information about the files needed for compilation.
38+
/// However, if it is a .NET framework reference we assume that all files in the
39+
/// package are needed for compilation.
40+
/// </summary>
41+
private record class ReferenceInfo(string? Type, Dictionary<string, object>? Compile);
42+
43+
/// <summary>
44+
/// Add the package dependencies from the assets file to dependencies.
45+
///
46+
/// Parse a part of the JSon assets file and add the paths
47+
/// to the dependencies required for compilation (and collect
48+
/// information about used packages).
49+
///
50+
/// Example:
51+
/// {
52+
/// "Castle.Core/4.4.1": {
53+
/// "type": "package",
54+
/// "compile": {
55+
/// "lib/netstandard1.5/Castle.Core.dll": {
56+
/// "related": ".xml"
57+
/// }
58+
/// }
59+
/// },
60+
/// "Json.Net/1.0.33": {
61+
/// "type": "package",
62+
/// "compile": {
63+
/// "lib/netstandard2.0/Json.Net.dll": {}
64+
/// },
65+
/// "runtime": {
66+
/// "lib/netstandard2.0/Json.Net.dll": {}
67+
/// }
68+
/// }
69+
/// }
70+
///
71+
/// Returns dependencies
72+
/// RequiredPaths = {
73+
/// "castle.core/4.4.1/lib/netstandard1.5/Castle.Core.dll",
74+
/// "json.net/1.0.33/lib/netstandard2.0/Json.Net.dll"
75+
/// }
76+
/// UsedPackages = {
77+
/// "castle.core",
78+
/// "json.net"
79+
/// }
80+
/// </summary>
81+
private DependencyContainer AddPackageDependencies(JObject json, DependencyContainer dependencies)
82+
{
83+
// If there are more than one framework we need to pick just one.
84+
// To ensure stability we pick one based on the lexicographic order of
85+
// the framework names.
86+
var references = json
87+
.GetProperty("targets")?
88+
.Properties()?
89+
.MaxBy(p => p.Name)?
90+
.Value
91+
.ToObject<Dictionary<string, ReferenceInfo>>();
92+
93+
if (references is null)
94+
{
95+
progressMonitor.LogDebug("No references found in the targets section in the assets file.");
96+
return dependencies;
97+
}
98+
99+
// Find all the compile dependencies for each reference and
100+
// create the relative path to the dependency.
101+
references
102+
.ForEach(r =>
103+
{
104+
var info = r.Value;
105+
var name = r.Key.ToLowerInvariant();
106+
if (info.Type != "package")
107+
{
108+
return;
109+
}
110+
111+
// If this is a .NET framework reference then include everything.
112+
if (netFrameworks.Any(framework => name.StartsWith(framework)))
113+
{
114+
dependencies.Add(name);
115+
}
116+
else
117+
{
118+
info.Compile?
119+
.ForEach(r => dependencies.Add(name, r.Key));
120+
}
121+
});
122+
123+
return dependencies;
124+
}
125+
126+
/// <summary>
127+
/// Parse `json` as project.assets.json content and add relative paths to the dependencies
128+
/// (together with used package information) required for compilation.
129+
/// </summary>
130+
/// <returns>True if parsing succeeds, otherwise false.</returns>
131+
public bool TryParse(string json, DependencyContainer dependencies)
132+
{
133+
try
134+
{
135+
var obj = JObject.Parse(json);
136+
AddPackageDependencies(obj, dependencies);
137+
return true;
138+
}
139+
catch (Exception e)
140+
{
141+
progressMonitor.LogDebug($"Failed to parse assets file (unexpected error): {e.Message}");
142+
return false;
143+
}
144+
}
145+
146+
public static DependencyContainer GetCompilationDependencies(ProgressMonitor progressMonitor, IEnumerable<string> assets)
147+
{
148+
var parser = new Assets(progressMonitor);
149+
var dependencies = new DependencyContainer();
150+
assets.ForEach(asset =>
151+
{
152+
var json = File.ReadAllText(asset);
153+
parser.TryParse(json, dependencies);
154+
});
155+
return dependencies;
156+
}
157+
}
158+
159+
internal static class JsonExtensions
160+
{
161+
internal static JObject? GetProperty(this JObject json, string property) =>
162+
json[property] as JObject;
163+
}
164+
}
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
using System.Collections.Generic;
2+
using System.IO;
3+
using System.Linq;
4+
5+
namespace Semmle.Extraction.CSharp.DependencyFetching
6+
{
7+
/// <summary>
8+
/// Container class for dependencies found in the assets file.
9+
/// </summary>
10+
internal class DependencyContainer
11+
{
12+
private readonly List<string> requiredPaths = new();
13+
private readonly HashSet<string> usedPackages = new();
14+
15+
/// <summary>
16+
/// In most cases paths in asset files point to dll's or the empty _._ file, which
17+
/// is sometimes there to avoid the directory being empty.
18+
/// That is, if the path specifically adds a .dll we use that, otherwise we as a fallback
19+
/// add the entire directory (which should be fine in case of _._ as well).
20+
/// </summary>
21+
private static string ParseFilePath(string path)
22+
{
23+
if (path.EndsWith(".dll"))
24+
{
25+
return path;
26+
}
27+
return Path.GetDirectoryName(path) ?? path;
28+
}
29+
30+
private static string GetPackageName(string package) =>
31+
package
32+
.Split(Path.DirectorySeparatorChar)
33+
.First();
34+
35+
/// <summary>
36+
/// Paths to dependencies required for compilation.
37+
/// </summary>
38+
public IEnumerable<string> RequiredPaths => requiredPaths;
39+
40+
/// <summary>
41+
/// Packages that are used as a part of the required dependencies.
42+
/// </summary>
43+
public HashSet<string> UsedPackages => usedPackages;
44+
45+
/// <summary>
46+
/// Add a dependency inside a package.
47+
/// </summary>
48+
public void Add(string package, string dependency)
49+
{
50+
var p = package.Replace('/', Path.DirectorySeparatorChar);
51+
var d = dependency.Replace('/', Path.DirectorySeparatorChar);
52+
53+
var path = Path.Combine(p, ParseFilePath(d));
54+
requiredPaths.Add(path);
55+
usedPackages.Add(GetPackageName(p));
56+
}
57+
58+
/// <summary>
59+
/// Add a dependency to an entire package
60+
/// </summary>
61+
public void Add(string package)
62+
{
63+
var p = package.Replace('/', Path.DirectorySeparatorChar);
64+
65+
requiredPaths.Add(p);
66+
usedPackages.Add(GetPackageName(p));
67+
}
68+
}
69+
}

0 commit comments

Comments
 (0)