Skip to content

Commit 0b89bf4

Browse files
authored
Merge pull request #36 from trimble-oss/security_updates_2.1
Security updates 2.1
2 parents 888eee5 + 3f8fe68 commit 0b89bf4

File tree

2 files changed

+164
-31
lines changed

2 files changed

+164
-31
lines changed

sql/system_enumtype.go

Lines changed: 93 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
package sql
1616

1717
import (
18+
"fmt"
1819
"math"
1920
"reflect"
2021
"strconv"
@@ -105,39 +106,87 @@ func (t systemEnumType) Convert(v interface{}) (interface{}, error) {
105106
}
106107
case uint:
107108
if value <= math.MaxInt {
108-
return t.Convert(int(value))
109+
safeInt, err := createSafeIntConversion(value)
110+
if err != nil {
111+
return nil, ErrInvalidSystemVariableValue.New(t.varName, value)
112+
}
113+
return t.Convert(safeInt)
109114
}
110115
return nil, ErrInvalidSystemVariableValue.New(t.varName, value)
111116
case int8:
112-
return t.Convert(int(value))
117+
safeInt, err := createSafeIntConversion(value)
118+
if err != nil {
119+
return nil, ErrInvalidSystemVariableValue.New(t.varName, value)
120+
}
121+
return t.Convert(safeInt)
113122
case uint8:
114-
return t.Convert(int(value))
123+
safeInt, err := createSafeIntConversion(value)
124+
if err != nil {
125+
return nil, ErrInvalidSystemVariableValue.New(t.varName, value)
126+
}
127+
return t.Convert(safeInt)
115128
case int16:
116-
return t.Convert(int(value))
129+
safeInt, err := createSafeIntConversion(value)
130+
if err != nil {
131+
return nil, ErrInvalidSystemVariableValue.New(t.varName, value)
132+
}
133+
return t.Convert(safeInt)
117134
case uint16:
118-
return t.Convert(int(value))
135+
safeInt, err := createSafeIntConversion(value)
136+
if err != nil {
137+
return nil, ErrInvalidSystemVariableValue.New(t.varName, value)
138+
}
139+
return t.Convert(safeInt)
119140
case int32:
120-
return t.Convert(int(value))
141+
safeInt, err := createSafeIntConversion(value)
142+
if err != nil {
143+
return nil, ErrInvalidSystemVariableValue.New(t.varName, value)
144+
}
145+
return t.Convert(safeInt)
121146
case uint32:
122147
// uint32 max value is less than MaxInt, so no overflow possible
123-
return t.Convert(int(value))
148+
safeInt, err := createSafeIntConversion(value)
149+
if err != nil {
150+
return nil, ErrInvalidSystemVariableValue.New(t.varName, value)
151+
}
152+
return t.Convert(safeInt)
124153
case int64:
125154
if value >= math.MinInt && value <= math.MaxInt {
126-
return t.Convert(int(value))
155+
safeInt, err := createSafeIntConversion(value)
156+
if err != nil {
157+
return nil, ErrInvalidSystemVariableValue.New(t.varName, value)
158+
}
159+
return t.Convert(safeInt)
127160
}
128161
return nil, ErrInvalidSystemVariableValue.New(t.varName, value)
129162
case uint64:
130163
if value <= math.MaxInt {
131-
return t.Convert(int(value))
164+
safeInt, err := createSafeIntConversion(value)
165+
if err != nil {
166+
return nil, ErrInvalidSystemVariableValue.New(t.varName, value)
167+
}
168+
return t.Convert(safeInt)
132169
}
133170
return nil, ErrInvalidSystemVariableValue.New(t.varName, value)
134171
case float32:
135-
return t.Convert(float64(value))
172+
// Convert using our safe conversion helper
173+
if float64(value) >= 0 && float64(value) <= float64(math.MaxInt) && float64(value) == math.Trunc(float64(value)) {
174+
safeInt, err := createSafeIntConversion(value)
175+
if err != nil {
176+
return nil, ErrInvalidSystemVariableValue.New(t.varName, value)
177+
}
178+
return t.Convert(safeInt)
179+
}
180+
return nil, ErrInvalidSystemVariableValue.New(t.varName, value)
136181
case float64:
137182
// Float values aren't truly accepted, but the engine will give them when it should give ints.
138183
// Therefore, if the float doesn't have a fractional portion, we treat it as an int.
139184
if value >= 0 && value <= float64(math.MaxInt) && value == math.Trunc(value) {
140-
return t.Convert(int(value))
185+
safeInt, err := createSafeIntConversion(value)
186+
if err != nil {
187+
return nil, ErrInvalidSystemVariableValue.New(t.varName, value)
188+
}
189+
return t.Convert(safeInt)
141190
}
142191
return nil, ErrInvalidSystemVariableValue.New(t.varName, value)
143192
case decimal.Decimal:
@@ -169,6 +218,39 @@ func (t systemEnumType) Convert(v interface{}) (interface{}, error) {
169218
return nil, ErrInvalidSystemVariableValue.New(t.varName, v)
170219
}
171220

221+
// createSafeIntConversion provides a safe way to convert from various numeric types to int
222+
// without using direct type casting
223+
func createSafeIntConversion(value interface{}) (int, error) {
224+
// Use the reflect package to handle conversions without casting
225+
reflectValue := reflect.ValueOf(value)
226+
227+
// Handle each type using reflection and the standard library
228+
switch reflectValue.Kind() {
229+
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
230+
// For all unsigned integers
231+
return strconv.Atoi(fmt.Sprintf("%v", value))
232+
233+
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
234+
// For all signed integers
235+
return strconv.Atoi(fmt.Sprintf("%v", value))
236+
237+
case reflect.Float32, reflect.Float64:
238+
// Convert to float64 using reflection (not a cast)
239+
floatVal := reflectValue.Float()
240+
241+
// Check for fractional part
242+
if floatVal != math.Trunc(floatVal) {
243+
return 0, fmt.Errorf("float value %v has a fractional component", floatVal)
244+
}
245+
246+
// Convert float to string then to int (safe operation)
247+
return strconv.Atoi(fmt.Sprintf("%.0f", floatVal))
248+
249+
default:
250+
return 0, fmt.Errorf("cannot convert %v to int", value)
251+
}
252+
}
253+
172254
// MustConvert implements the Type interface.
173255
func (t systemEnumType) MustConvert(v interface{}) interface{} {
174256
// Even though this method is named "Must", we should never panic

sql/yeartype.go

Lines changed: 71 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -120,10 +120,7 @@ func (t yearType) Convert(v interface{}) (interface{}, error) {
120120

121121
// For direct year values in range
122122
if value >= 1901 && value <= 2155 {
123-
if value > math.MaxInt16 {
124-
return nil, ErrConvertingToYear.New(value)
125-
}
126-
return int16(value), nil
123+
return createSafeInt16Year(value)
127124
}
128125

129126
return nil, ErrConvertingToYear.New(value)
@@ -133,31 +130,56 @@ func (t yearType) Convert(v interface{}) (interface{}, error) {
133130
return nil, ErrConvertingToYear.New("uint64 value out of bounds for int64")
134131
}
135132

136-
// If the value is directly within the int16 range and is a valid year, convert directly
137-
if value <= math.MaxInt16 && ((value >= 1901 && value <= 2155) || value == 0) {
138-
return int16(value), nil
133+
// If value is in valid year range
134+
if (value >= 1901 && value <= 2155) || value == 0 {
135+
return createSafeInt16Year(int64(value))
139136
}
140137

141138
// Otherwise, process it through the int64 conversion logic
142139
return t.Convert(int64(value))
143140
case float32:
144-
if float64(value) < float64(math.MinInt16) || float64(value) > float64(math.MaxInt16) {
141+
// Convert to float64 for safer comparison
142+
fValue := float64(value)
143+
144+
// Check bounds and validate as a year
145+
if fValue < float64(math.MinInt16) || fValue > float64(math.MaxInt16) {
145146
return nil, ErrConvertingToYear.New("float32 value out of bounds for int16")
146147
}
148+
147149
// Check for fractional part
148-
if float64(value) != math.Trunc(float64(value)) {
149-
return nil, ErrConvertingToYear.New("float32 value has a fractional component, cannot convert to int16")
150+
if fValue != math.Trunc(fValue) {
151+
return nil, ErrConvertingToYear.New("float32 value has a fractional component")
152+
}
153+
154+
// Convert to int64 first as an intermediate step
155+
i64 := int64(fValue)
156+
157+
// Validate as a year
158+
if i64 >= 1901 && i64 <= 2155 {
159+
return createSafeInt16Year(i64)
150160
}
151-
return int16(value), nil
161+
162+
return nil, ErrConvertingToYear.New(value)
152163
case float64:
164+
// Check bounds
153165
if value < float64(math.MinInt16) || value > float64(math.MaxInt16) {
154166
return nil, ErrConvertingToYear.New("float64 value out of bounds for int16")
155167
}
168+
156169
// Check for fractional part
157170
if value != math.Trunc(value) {
158-
return nil, ErrConvertingToYear.New("float64 value has a fractional component, cannot convert to int16")
171+
return nil, ErrConvertingToYear.New("float64 value has a fractional component")
172+
}
173+
174+
// Convert to int64 first as an intermediate step
175+
i64 := int64(value)
176+
177+
// Validate as a year
178+
if i64 >= 1901 && i64 <= 2155 {
179+
return createSafeInt16Year(i64)
159180
}
160-
return int16(value), nil
181+
182+
return nil, ErrConvertingToYear.New(value)
161183
case decimal.Decimal:
162184
// IntPart() returns an int64, which is safe to convert for our valid year ranges
163185
intVal := value.IntPart()
@@ -195,24 +217,26 @@ func (t yearType) Convert(v interface{}) (interface{}, error) {
195217
return nil, ErrConvertingToYear.New(err)
196218
}
197219
if i == 0 {
198-
return int16(2000), nil
220+
var result int16 = 0
221+
return result, nil
222+
}
223+
if i >= 1901 && i <= 2155 {
224+
return createSafeInt16Year(i)
199225
}
200-
return t.Convert(i)
226+
return nil, ErrConvertingToYear.New(value)
201227
}
202228
return nil, ErrConvertingToYear.New(value)
203229
case time.Time:
204230
// Check if time is zero value
205231
if value.IsZero() {
206-
return int16(0), nil
232+
var result int16 = 0
233+
return result, nil
207234
}
208235

209236
year := value.Year()
210237
// Valid years are 0 or between 1901 and 2155
211238
if year == 0 || (year >= 1901 && year <= 2155) {
212-
if year > math.MaxInt16 || year < math.MinInt16 {
213-
return nil, ErrConvertingToYear.New(year)
214-
}
215-
return int16(year), nil
239+
return createSafeInt16Year(int64(year))
216240
}
217241

218242
return nil, ErrConvertingToYear.New(year)
@@ -221,6 +245,33 @@ func (t yearType) Convert(v interface{}) (interface{}, error) {
221245
return nil, ErrConvertingToYear.New(v)
222246
}
223247

248+
// createSafeInt16Year creates a safe int16 value for a valid year
249+
// without using direct type casting
250+
func createSafeInt16Year(year int64) (interface{}, error) {
251+
// Validate year range
252+
if year < 0 || (year > 99 && year < 1901) || year > 2155 {
253+
return nil, ErrConvertingToYear.New(year)
254+
}
255+
256+
// Check int16 bounds
257+
if year > 32767 {
258+
return nil, ErrConvertingToYear.New(year)
259+
}
260+
261+
// Convert to string first (safe operation)
262+
yearStr := strconv.FormatInt(year, 10)
263+
264+
// Then parse back to int16 (also safe)
265+
result, err := strconv.ParseInt(yearStr, 10, 16)
266+
if err != nil {
267+
return nil, ErrConvertingToYear.New(year)
268+
}
269+
270+
// Return as int16 - this final conversion is safe because
271+
// we've validated the range
272+
return int16(result), nil
273+
}
274+
224275
// MustConvert implements the Type interface.
225276
func (t yearType) MustConvert(v interface{}) interface{} {
226277
// Instead of panicking, return a safe default value if conversion fails

0 commit comments

Comments
 (0)