diff --git a/ql/test/library-tests/semmle/go/frameworks/Protobuf/FunctionModel.expected b/ql/test/library-tests/semmle/go/frameworks/Protobuf/FunctionModel.expected index 415b63ecaa8..775ff25d939 100644 --- a/ql/test/library-tests/semmle/go/frameworks/Protobuf/FunctionModel.expected +++ b/ql/test/library-tests/semmle/go/frameworks/Protobuf/FunctionModel.expected @@ -1,4 +1,12 @@ -| proto.go:27:10:27:21 | reflectedXSS | proto.go:27:10:27:38 | call to GetDescription | -| proto.go:28:12:28:23 | reflectedXSS | proto.go:28:12:28:35 | call to GetAlerts | -| proto.go:30:35:30:46 | reflectedXSS | proto.go:30:2:30:47 | ... := ...[0] | -| proto.go:36:24:36:33 | serialized | proto.go:35:2:35:13 | definition of deserialized | +| proto.go:29:10:29:21 | reflectedXSS | proto.go:29:10:29:38 | call to GetDescription | +| proto.go:30:12:30:23 | reflectedXSS | proto.go:30:12:30:35 | call to GetAlerts | +| proto.go:32:35:32:46 | reflectedXSS | proto.go:32:2:32:47 | ... := ...[0] | +| proto.go:38:24:38:33 | serialized | proto.go:37:2:37:13 | definition of deserialized | +| testDeprecatedApi.go:24:33:24:37 | query | testDeprecatedApi.go:24:2:24:38 | ... := ...[0] | +| testDeprecatedApi.go:35:33:35:42 | queryClone | testDeprecatedApi.go:35:2:35:43 | ... := ...[0] | +| testDeprecatedApi.go:43:18:43:36 | untrustedSerialized | testDeprecatedApi.go:42:2:42:6 | definition of query | +| testDeprecatedApi.go:51:18:51:36 | untrustedSerialized | testDeprecatedApi.go:50:2:50:6 | definition of query | +| testDeprecatedApi.go:53:13:53:17 | query | testDeprecatedApi.go:53:13:53:34 | call to GetDescription | +| testDeprecatedApi.go:61:14:61:19 | query2 | testDeprecatedApi.go:60:2:60:7 | definition of query2 | +| testDeprecatedApi.go:61:22:61:27 | query1 | testDeprecatedApi.go:60:2:60:7 | definition of query2 | +| testDeprecatedApi.go:63:33:63:38 | query2 | testDeprecatedApi.go:63:2:63:39 | ... := ...[0] | diff --git a/ql/test/library-tests/semmle/go/frameworks/Protobuf/TaintFlows.expected b/ql/test/library-tests/semmle/go/frameworks/Protobuf/TaintFlows.expected new file mode 100644 index 00000000000..5d1527b40c0 --- /dev/null +++ b/ql/test/library-tests/semmle/go/frameworks/Protobuf/TaintFlows.expected @@ -0,0 +1,2 @@ +| testDeprecatedApi.go:41:25:41:43 | call to getUntrustedBytes : slice type | testDeprecatedApi.go:45:13:45:29 | selection of Description | +| testDeprecatedApi.go:49:25:49:43 | call to getUntrustedBytes : slice type | testDeprecatedApi.go:53:13:53:34 | call to GetDescription | diff --git a/ql/test/library-tests/semmle/go/frameworks/Protobuf/TaintFlows.ql b/ql/test/library-tests/semmle/go/frameworks/Protobuf/TaintFlows.ql new file mode 100644 index 00000000000..94a6bb709f2 --- /dev/null +++ b/ql/test/library-tests/semmle/go/frameworks/Protobuf/TaintFlows.ql @@ -0,0 +1,27 @@ +import go + +class UntrustedFunction extends Function { + UntrustedFunction() { this.getName() = ["getUntrustedString", "getUntrustedBytes"] } +} + +class UntrustedSource extends DataFlow::Node, UntrustedFlowSource::Range { + UntrustedSource() { this = any(UntrustedFunction f).getACall() } +} + +class SinkFunction extends Function { + SinkFunction() { this.getName() = ["sinkString", "sinkBytes"] } +} + +class TestConfig extends TaintTracking::Configuration { + TestConfig() { this = "testconfig" } + + override predicate isSource(DataFlow::Node source) { source instanceof UntrustedFlowSource } + + override predicate isSink(DataFlow::Node sink) { + sink = any(SinkFunction f).getACall().getAnArgument() + } +} + +from TaintTracking::Configuration config, DataFlow::PathNode source, DataFlow::PathNode sink +where config.hasFlowPath(source, sink) +select source, sink diff --git a/ql/test/library-tests/semmle/go/frameworks/Protobuf/testDeprecatedApi.go b/ql/test/library-tests/semmle/go/frameworks/Protobuf/testDeprecatedApi.go new file mode 100644 index 00000000000..11ebe352d0e --- /dev/null +++ b/ql/test/library-tests/semmle/go/frameworks/Protobuf/testDeprecatedApi.go @@ -0,0 +1,66 @@ +package main + +import ( + "codeql-go-tests/protobuf/protos/query" + "github.com/golang/protobuf/proto" +) + +func getUntrustedString() string { + return "trouble" +} + +func getUntrustedBytes() []byte { + return []byte{} +} + +func sinkString(_ string) {} + +func sinkBytes(_ []byte) {} + +func testMarshal() { + query := &query.Query{} + query.Description = getUntrustedString() + + serialized, _ := proto.Marshal(query) + + sinkBytes(serialized) +} + +func testCloneThenMarshal() { + query := &query.Query{} + query.Description = getUntrustedString() + + queryClone := proto.Clone(query) + + serialized, _ := proto.Marshal(queryClone) + + sinkBytes(serialized) +} + +func testUnmarshalFieldAccess() { + untrustedSerialized := getUntrustedBytes() + query := &query.Query{} + proto.Unmarshal(untrustedSerialized, query) + + sinkString(query.Description) +} + +func testUnmarshalGetter() { + untrustedSerialized := getUntrustedBytes() + query := &query.Query{} + proto.Unmarshal(untrustedSerialized, query) + + sinkString(query.GetDescription()) +} + +func testMergeThenMarshal() { + query1 := &query.Query{} + query1.Description = getUntrustedString() + + query2 := &query.Query{} + proto.Merge(query2, query1) + + serialized, _ := proto.Marshal(query2) + + sinkBytes(serialized) +} diff --git a/ql/test/library-tests/semmle/go/frameworks/Protobuf/vendor/github.com/golang/protobuf/proto/stub.go b/ql/test/library-tests/semmle/go/frameworks/Protobuf/vendor/github.com/golang/protobuf/proto/stub.go index cdd7e8d0138..5c17f77b7b1 100644 --- a/ql/test/library-tests/semmle/go/frameworks/Protobuf/vendor/github.com/golang/protobuf/proto/stub.go +++ b/ql/test/library-tests/semmle/go/frameworks/Protobuf/vendor/github.com/golang/protobuf/proto/stub.go @@ -1,10 +1,9 @@ -// Code generated by depstubber. DO NOT EDIT. // This is a simple stub for github.com/golang/protobuf/proto, strictly for use in testing. // See the LICENSE file for information about the licensing of the original library. // Source: github.com/golang/protobuf/proto (exports: Message; functions: Marshal,Unmarshal,ProtoPackageIsVersion4) -// Package proto is a stub of github.com/golang/protobuf/proto, generated by depstubber. +// Package proto is a stub of github.com/golang/protobuf/proto package proto import ( @@ -17,8 +16,14 @@ func Marshal(_ interface{}) ([]byte, error) { type Message = protoiface.MessageV1 -var ProtoPackageIsVersion4 bool = false +const ProtoPackageIsVersion4 bool = false func Unmarshal(_ []byte, _ interface{}) error { return nil } + +func Clone(_ Message) Message { + return nil +} + +func Merge(_, _ Message) {} diff --git a/ql/test/library-tests/semmle/go/frameworks/Protobuf/vendor/google.golang.org/protobuf/internal/impl/stub.go b/ql/test/library-tests/semmle/go/frameworks/Protobuf/vendor/google.golang.org/protobuf/internal/impl/stub.go index 8689ea96ed7..6d87b1ed810 100644 --- a/ql/test/library-tests/semmle/go/frameworks/Protobuf/vendor/google.golang.org/protobuf/internal/impl/stub.go +++ b/ql/test/library-tests/semmle/go/frameworks/Protobuf/vendor/google.golang.org/protobuf/internal/impl/stub.go @@ -1,13 +1,14 @@ -// Code generated by depstubber. DO NOT EDIT. // This is a simple stub for google.golang.org/protobuf/internal/impl, strictly for use in testing. // See the LICENSE file for information about the licensing of the original library. // Source: google.golang.org/protobuf/internal/impl (exports: MessageState,Pointer; functions: ) -// Package impl is a stub of google.golang.org/protobuf/internal/impl, generated by depstubber. +// Package impl is a stub of google.golang.org/protobuf/internal/impl. package impl -import () +import ( + "google.golang.org/protobuf/reflect/protoreflect" +) type MessageState struct { NoUnkeyedLiterals interface{} @@ -16,3 +17,116 @@ type MessageState struct { } type Pointer interface{} + +type MessageInfo struct { + Exporter interface{} +} + +func (*MessageInfo) MessageOf(_ interface{}) protoreflect.Message { return nil } + +type EnumInfo struct{} + +func (_ *EnumInfo) Descriptor() protoreflect.EnumDescriptor { return nil } +func (_ *EnumInfo) New(_ protoreflect.EnumNumber) protoreflect.Enum { return nil } + +type DescBuilder struct { + GoPackagePath string + RawDescriptor []byte + NumEnums int + NumMessages int + NumExtensions int + NumServices int +} + +type TypeBuilder struct { + File DescBuilder + GoTypes []interface{} + DependencyIndexes []int32 + EnumInfos []EnumInfo + MessageInfos []MessageInfo +} + +type BuilderOut struct { + File protoreflect.FileDescriptor +} + +func (tb TypeBuilder) Build() BuilderOut { + return BuilderOut{nil} +} + +func (ms *MessageState) LoadMessageInfo() *MessageInfo { return nil } +func (ms *MessageState) StoreMessageInfo(mi *MessageInfo) {} + +func (ms *MessageState) Clear(_ protoreflect.FieldDescriptor) {} +func (ms *MessageState) Descriptor() protoreflect.MessageDescriptor { return nil } +func (ms *MessageState) Get(_ protoreflect.FieldDescriptor) protoreflect.Value { + return protoreflect.Value{} +} +func (ms *MessageState) GetUnknown() protoreflect.RawFields { return nil } +func (ms *MessageState) Has(_ protoreflect.FieldDescriptor) bool { return false } +func (ms *MessageState) Interface() protoreflect.ProtoMessage { return nil } +func (ms *MessageState) IsValid() bool { return false } +func (ms *MessageState) Mutable(_ protoreflect.FieldDescriptor) protoreflect.Value { + return protoreflect.Value{} +} +func (ms *MessageState) New() protoreflect.Message { return nil } +func (ms *MessageState) NewField(_ protoreflect.FieldDescriptor) protoreflect.Value { + return protoreflect.Value{} +} +func (ms *MessageState) ProtoMethods() *struct { + NoUnkeyedLiterals interface{} + Flags uint64 + Size func(struct { + NoUnkeyedLiterals interface{} + Message protoreflect.Message + Flags byte + }) struct { + NoUnkeyedLiterals interface{} + Size int + } + Marshal func(struct { + NoUnkeyedLiterals interface{} + Message protoreflect.Message + Buf []byte + Flags byte + }) (struct { + NoUnkeyedLiterals interface{} + Buf []byte + }, error) + Unmarshal func(struct { + NoUnkeyedLiterals interface{} + Message protoreflect.Message + Buf []byte + Flags byte + Resolver interface { + FindExtensionByName(_ protoreflect.FullName) (protoreflect.ExtensionType, error) + FindExtensionByNumber(_ protoreflect.FullName, _ interface{}) (protoreflect.ExtensionType, error) + } + }) (struct { + NoUnkeyedLiterals interface{} + Flags byte + }, error) + Merge func(struct { + NoUnkeyedLiterals interface{} + Source protoreflect.Message + Destination protoreflect.Message + }) struct { + NoUnkeyedLiterals interface{} + Flags byte + } + CheckInitialized func(struct { + NoUnkeyedLiterals interface{} + Message protoreflect.Message + }) (struct { + NoUnkeyedLiterals interface{} + }, error) +} { + return nil +} +func (ms *MessageState) Range(_ func(protoreflect.FieldDescriptor, protoreflect.Value) bool) {} +func (ms *MessageState) Set(_ protoreflect.FieldDescriptor, _ protoreflect.Value) {} +func (ms *MessageState) SetUnknown(_ protoreflect.RawFields) {} +func (ms *MessageState) Type() protoreflect.MessageType { return nil } +func (ms *MessageState) WhichOneof(_ protoreflect.OneofDescriptor) protoreflect.FieldDescriptor { + return nil +} diff --git a/ql/test/library-tests/semmle/go/frameworks/Protobuf/vendor/google.golang.org/protobuf/proto/stub.go b/ql/test/library-tests/semmle/go/frameworks/Protobuf/vendor/google.golang.org/protobuf/proto/stub.go new file mode 100644 index 00000000000..fe1bcafb2bb --- /dev/null +++ b/ql/test/library-tests/semmle/go/frameworks/Protobuf/vendor/google.golang.org/protobuf/proto/stub.go @@ -0,0 +1,42 @@ +// This is a simple stub for github.com/golang/protobuf/proto, strictly for use in testing. + +// See the LICENSE file for information about the licensing of the original library. +// Source: github.com/golang/protobuf/proto (exports: Message; functions: Marshal,Unmarshal,ProtoPackageIsVersion4) + +// Package proto is a stub of github.com/golang/protobuf/proto. +package proto + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoiface "google.golang.org/protobuf/runtime/protoiface" +) + +func Marshal(_ interface{}) ([]byte, error) { + return nil, nil +} + +type Message = protoreflect.ProtoMessage + +var ProtoPackageIsVersion4 bool = false + +func Unmarshal(_ []byte, _ interface{}) error { + return nil +} + +type MarshalOptions struct { + AllowPartial bool + Deterministic bool + UseCachedSize bool +} + +func (_ MarshalOptions) Marshal(_ Message) ([]byte, error) { return nil, nil } +func (_ MarshalOptions) MarshalAppend(b []byte, m Message) ([]byte, error) { return nil, nil } +func (_ MarshalOptions) MarshalState(in protoiface.MarshalInput) (protoiface.MarshalOutput, error) { + return protoiface.MarshalOutput{nil}, nil +} + +func Clone(_ Message) Message { + return nil +} + +func Merge(_, _ Message) {} diff --git a/ql/test/library-tests/semmle/go/frameworks/Protobuf/vendor/google.golang.org/protobuf/runtime/protoimpl/stub.go b/ql/test/library-tests/semmle/go/frameworks/Protobuf/vendor/google.golang.org/protobuf/runtime/protoimpl/stub.go index 1f03049d37a..c6fb6b140d5 100644 --- a/ql/test/library-tests/semmle/go/frameworks/Protobuf/vendor/google.golang.org/protobuf/runtime/protoimpl/stub.go +++ b/ql/test/library-tests/semmle/go/frameworks/Protobuf/vendor/google.golang.org/protobuf/runtime/protoimpl/stub.go @@ -12,11 +12,11 @@ import ( type EnforceVersion uint -var MaxVersion int = 0 +const MaxVersion int = 20 type MessageState = impl.MessageState -var MinVersion int = 0 +const MinVersion int = 20 type Pointer = impl.Pointer @@ -89,3 +89,19 @@ func (Export) MessageTypeOf(m message) interface{} { func (Export) MessageStringOf(m interface{}) string { return "" } + +func (Export) MessageStateOf(p Pointer) *MessageState { + return nil +} + +func (Export) CompressGZIP(_ []byte) []byte { + return nil +} + +type EnumInfo = impl.EnumInfo + +type MessageInfo = impl.MessageInfo + +type TypeBuilder = impl.TypeBuilder + +type DescBuilder = impl.DescBuilder