# Unless explicitly stated otherwise all files in this repository are licensed
# under the Apache License Version 2.0.
# This product includes software developed at Datadog (https://www.datadoghq.com/).
# Copyright 2023-present Datadog, Inc.
---
# yaml-language-server: $schema=https://datadoghq.dev/orchestrion/schema.json
meta:
  name: github.com/DataDog/dd-trace-go/v2/contrib/os
  description: |-
    Protection from Local File Inclusion (LFI) Attacks

    All known functions that open files are susceptible to Local File Inclusion (LFI) attacks. This aspect protects
    against LFI attacks by wrapping the `os.OpenFile` function with a security operation that will block the operation if
    it is deemed unsafe.

    Instrumenting only the `os.OpenFile` function is sufficient to protect against LFI attacks, as all other functions in
    the `os` package that open files ultimately call `os.OpenFile` (as of Go 1.23).

aspects:
  - id: OpenFile
    join-point:
      all-of:
        - import-path: os
        - function-body:
            function:
              - name: OpenFile
    advice:
      - prepend-statements:
          imports:
            ossec: github.com/DataDog/dd-trace-go/v2/instrumentation/appsec/emitter/ossec
            dyngo: github.com/DataDog/dd-trace-go/v2/instrumentation/appsec/dyngo
            events: github.com/DataDog/dd-trace-go/v2/appsec/events
          template: |-
            __dd_parent_op, _ := dyngo.FromContext(nil)
            if __dd_parent_op != nil {
                __dd_op := &ossec.OpenOperation{
                    Operation: dyngo.NewOperation(__dd_parent_op),
                }

                var __dd_block bool
                dyngo.OnData(__dd_op, func(_ *events.BlockingSecurityEvent) {
                    __dd_block = true
                })

                dyngo.StartOperation(__dd_op, ossec.OpenOperationArgs{
                    Path: {{ .Function.Argument 0 }},
                    Flags: {{ .Function.Argument 1 }},
                    Perms: {{ .Function.Argument 2 }},
                })

                defer dyngo.FinishOperation(__dd_op, ossec.OpenOperationRes[*File]{
                    File: &{{ .Function.Result 0 }},
                    Err: &{{ .Function.Result 1 }},
                })

                if __dd_block {
                    return
                }
            }
