mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
44a8e10bfc
AWS recently launched a new version of the EC2 Instance Metadata Service, which is used to provide credentials to the awslogs driver when running on Amazon EC2. This new version of the IMDS adds defense-in-depth mechanisms against open firewalls, reverse proxies, and SSRF vulnerabilities and is generally an improvement over the previous version. An updated version of the AWS SDK is able to handle the both the previous version and the new version of the IMDS and functions when either is enabled. More information about IMDSv2 is available at the following links: * https://aws.amazon.com/blogs/security/defense-in-depth-open-firewalls-reverse-proxies-ssrf-vulnerabilities-ec2-instance-metadata-service/ * https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/configuring-instance-metadata-service.html Closes https://github.com/moby/moby/issues/40422 Signed-off-by: Samuel Karp <skarp@amazon.com>
324 lines
5.8 KiB
Go
324 lines
5.8 KiB
Go
package ini
|
|
|
|
import (
|
|
"fmt"
|
|
"strconv"
|
|
"strings"
|
|
)
|
|
|
|
var (
|
|
runesTrue = []rune("true")
|
|
runesFalse = []rune("false")
|
|
)
|
|
|
|
var literalValues = [][]rune{
|
|
runesTrue,
|
|
runesFalse,
|
|
}
|
|
|
|
func isBoolValue(b []rune) bool {
|
|
for _, lv := range literalValues {
|
|
if isLitValue(lv, b) {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
func isLitValue(want, have []rune) bool {
|
|
if len(have) < len(want) {
|
|
return false
|
|
}
|
|
|
|
for i := 0; i < len(want); i++ {
|
|
if want[i] != have[i] {
|
|
return false
|
|
}
|
|
}
|
|
|
|
return true
|
|
}
|
|
|
|
// isNumberValue will return whether not the leading characters in
|
|
// a byte slice is a number. A number is delimited by whitespace or
|
|
// the newline token.
|
|
//
|
|
// A number is defined to be in a binary, octal, decimal (int | float), hex format,
|
|
// or in scientific notation.
|
|
func isNumberValue(b []rune) bool {
|
|
negativeIndex := 0
|
|
helper := numberHelper{}
|
|
needDigit := false
|
|
|
|
for i := 0; i < len(b); i++ {
|
|
negativeIndex++
|
|
|
|
switch b[i] {
|
|
case '-':
|
|
if helper.IsNegative() || negativeIndex != 1 {
|
|
return false
|
|
}
|
|
helper.Determine(b[i])
|
|
needDigit = true
|
|
continue
|
|
case 'e', 'E':
|
|
if err := helper.Determine(b[i]); err != nil {
|
|
return false
|
|
}
|
|
negativeIndex = 0
|
|
needDigit = true
|
|
continue
|
|
case 'b':
|
|
if helper.numberFormat == hex {
|
|
break
|
|
}
|
|
fallthrough
|
|
case 'o', 'x':
|
|
needDigit = true
|
|
if i == 0 {
|
|
return false
|
|
}
|
|
|
|
fallthrough
|
|
case '.':
|
|
if err := helper.Determine(b[i]); err != nil {
|
|
return false
|
|
}
|
|
needDigit = true
|
|
continue
|
|
}
|
|
|
|
if i > 0 && (isNewline(b[i:]) || isWhitespace(b[i])) {
|
|
return !needDigit
|
|
}
|
|
|
|
if !helper.CorrectByte(b[i]) {
|
|
return false
|
|
}
|
|
needDigit = false
|
|
}
|
|
|
|
return !needDigit
|
|
}
|
|
|
|
func isValid(b []rune) (bool, int, error) {
|
|
if len(b) == 0 {
|
|
// TODO: should probably return an error
|
|
return false, 0, nil
|
|
}
|
|
|
|
return isValidRune(b[0]), 1, nil
|
|
}
|
|
|
|
func isValidRune(r rune) bool {
|
|
return r != ':' && r != '=' && r != '[' && r != ']' && r != ' ' && r != '\n'
|
|
}
|
|
|
|
// ValueType is an enum that will signify what type
|
|
// the Value is
|
|
type ValueType int
|
|
|
|
func (v ValueType) String() string {
|
|
switch v {
|
|
case NoneType:
|
|
return "NONE"
|
|
case DecimalType:
|
|
return "FLOAT"
|
|
case IntegerType:
|
|
return "INT"
|
|
case StringType:
|
|
return "STRING"
|
|
case BoolType:
|
|
return "BOOL"
|
|
}
|
|
|
|
return ""
|
|
}
|
|
|
|
// ValueType enums
|
|
const (
|
|
NoneType = ValueType(iota)
|
|
DecimalType
|
|
IntegerType
|
|
StringType
|
|
QuotedStringType
|
|
BoolType
|
|
)
|
|
|
|
// Value is a union container
|
|
type Value struct {
|
|
Type ValueType
|
|
raw []rune
|
|
|
|
integer int64
|
|
decimal float64
|
|
boolean bool
|
|
str string
|
|
}
|
|
|
|
func newValue(t ValueType, base int, raw []rune) (Value, error) {
|
|
v := Value{
|
|
Type: t,
|
|
raw: raw,
|
|
}
|
|
var err error
|
|
|
|
switch t {
|
|
case DecimalType:
|
|
v.decimal, err = strconv.ParseFloat(string(raw), 64)
|
|
case IntegerType:
|
|
if base != 10 {
|
|
raw = raw[2:]
|
|
}
|
|
|
|
v.integer, err = strconv.ParseInt(string(raw), base, 64)
|
|
case StringType:
|
|
v.str = string(raw)
|
|
case QuotedStringType:
|
|
v.str = string(raw[1 : len(raw)-1])
|
|
case BoolType:
|
|
v.boolean = runeCompare(v.raw, runesTrue)
|
|
}
|
|
|
|
// issue 2253
|
|
//
|
|
// if the value trying to be parsed is too large, then we will use
|
|
// the 'StringType' and raw value instead.
|
|
if nerr, ok := err.(*strconv.NumError); ok && nerr.Err == strconv.ErrRange {
|
|
v.Type = StringType
|
|
v.str = string(raw)
|
|
err = nil
|
|
}
|
|
|
|
return v, err
|
|
}
|
|
|
|
// Append will append values and change the type to a string
|
|
// type.
|
|
func (v *Value) Append(tok Token) {
|
|
r := tok.Raw()
|
|
if v.Type != QuotedStringType {
|
|
v.Type = StringType
|
|
r = tok.raw[1 : len(tok.raw)-1]
|
|
}
|
|
if tok.Type() != TokenLit {
|
|
v.raw = append(v.raw, tok.Raw()...)
|
|
} else {
|
|
v.raw = append(v.raw, r...)
|
|
}
|
|
}
|
|
|
|
func (v Value) String() string {
|
|
switch v.Type {
|
|
case DecimalType:
|
|
return fmt.Sprintf("decimal: %f", v.decimal)
|
|
case IntegerType:
|
|
return fmt.Sprintf("integer: %d", v.integer)
|
|
case StringType:
|
|
return fmt.Sprintf("string: %s", string(v.raw))
|
|
case QuotedStringType:
|
|
return fmt.Sprintf("quoted string: %s", string(v.raw))
|
|
case BoolType:
|
|
return fmt.Sprintf("bool: %t", v.boolean)
|
|
default:
|
|
return "union not set"
|
|
}
|
|
}
|
|
|
|
func newLitToken(b []rune) (Token, int, error) {
|
|
n := 0
|
|
var err error
|
|
|
|
token := Token{}
|
|
if b[0] == '"' {
|
|
n, err = getStringValue(b)
|
|
if err != nil {
|
|
return token, n, err
|
|
}
|
|
|
|
token = newToken(TokenLit, b[:n], QuotedStringType)
|
|
} else if isNumberValue(b) {
|
|
var base int
|
|
base, n, err = getNumericalValue(b)
|
|
if err != nil {
|
|
return token, 0, err
|
|
}
|
|
|
|
value := b[:n]
|
|
vType := IntegerType
|
|
if contains(value, '.') || hasExponent(value) {
|
|
vType = DecimalType
|
|
}
|
|
token = newToken(TokenLit, value, vType)
|
|
token.base = base
|
|
} else if isBoolValue(b) {
|
|
n, err = getBoolValue(b)
|
|
|
|
token = newToken(TokenLit, b[:n], BoolType)
|
|
} else {
|
|
n, err = getValue(b)
|
|
token = newToken(TokenLit, b[:n], StringType)
|
|
}
|
|
|
|
return token, n, err
|
|
}
|
|
|
|
// IntValue returns an integer value
|
|
func (v Value) IntValue() int64 {
|
|
return v.integer
|
|
}
|
|
|
|
// FloatValue returns a float value
|
|
func (v Value) FloatValue() float64 {
|
|
return v.decimal
|
|
}
|
|
|
|
// BoolValue returns a bool value
|
|
func (v Value) BoolValue() bool {
|
|
return v.boolean
|
|
}
|
|
|
|
func isTrimmable(r rune) bool {
|
|
switch r {
|
|
case '\n', ' ':
|
|
return true
|
|
}
|
|
return false
|
|
}
|
|
|
|
// StringValue returns the string value
|
|
func (v Value) StringValue() string {
|
|
switch v.Type {
|
|
case StringType:
|
|
return strings.TrimFunc(string(v.raw), isTrimmable)
|
|
case QuotedStringType:
|
|
// preserve all characters in the quotes
|
|
return string(removeEscapedCharacters(v.raw[1 : len(v.raw)-1]))
|
|
default:
|
|
return strings.TrimFunc(string(v.raw), isTrimmable)
|
|
}
|
|
}
|
|
|
|
func contains(runes []rune, c rune) bool {
|
|
for i := 0; i < len(runes); i++ {
|
|
if runes[i] == c {
|
|
return true
|
|
}
|
|
}
|
|
|
|
return false
|
|
}
|
|
|
|
func runeCompare(v1 []rune, v2 []rune) bool {
|
|
if len(v1) != len(v2) {
|
|
return false
|
|
}
|
|
|
|
for i := 0; i < len(v1); i++ {
|
|
if v1[i] != v2[i] {
|
|
return false
|
|
}
|
|
}
|
|
|
|
return true
|
|
}
|