You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
CFStringGetCStringPtr is meant as an optimization to allow users to avoid a copy when the string is known to be valid ASCII, UTF-8 or similar 8-bit encoding.
It has a flaw though: It does not check whether the string contains interior NUL bytes. Consider the following Swift code (tested on macOS 14.7.4) (not specific to Swift, the problem is present in plain Objective-C too):
import CoreFoundation
// All of Swift.String, NSString and CFString support strings with interior NUL bytes.
lets="A string with a \0 <- NUL right there"print(s) // Prints the full string, i.e. preserves the content after the NUL byte.
print(s.count) // Prints 36 as expected.
func cf_roundtrip(_ s:String)->String?{letcfstr= s as!CFStringguardlet ptr =CFStringGetCStringPtr(cfstr,CFStringBuiltInEncodings.UTF8.rawValue)else{returnnil}returnString(cString: ptr)}
// Most strings can be round-tripped through `CFStringGetCStringPtr`, and if it can't, will return `nil`.
print(cf_roundtrip("Hello World!")asAny) // Prints `Optional("Hello World!")`
print(cf_roundtrip("Contains non-ASCII: 😀")asAny) // Prints `nil`
// Round-tripping strings with interior NUL bytes through `CFStringGetCStringPtr` doesn't work correctly though:
print(cf_roundtrip(s)asAny) // Prints `Optional("A string with a ")`
// !!! The string was truncated, should have returned `nil` instead!
That is, CFStringGetCStringPtr ends up returning the string pointer, but because of consumers assuming that the internal NUL byte is the final NUL, it silently truncates the rest of the string. A mitigation here would be to only use ASCII and to check CFStringGetLength as done in 860956a and 8422c1a when Swift.String itself was affected by this bug in the past, but I suspect only the vast minority of people will find that solution.
I actually found this by using CFURLCreateWithBytes with an interior NUL byte, which makes it unexpectedly fail because of this check that was added in newer versions.
CFStringGetCStringPtr
is meant as an optimization to allow users to avoid a copy when the string is known to be valid ASCII, UTF-8 or similar 8-bit encoding.It has a flaw though: It does not check whether the string contains interior NUL bytes. Consider the following Swift code (tested on macOS 14.7.4) (not specific to Swift, the problem is present in plain Objective-C too):
That is,
CFStringGetCStringPtr
ends up returning the string pointer, but because of consumers assuming that the internal NUL byte is the final NUL, it silently truncates the rest of the string. A mitigation here would be to only useASCII
and to checkCFStringGetLength
as done in 860956a and 8422c1a when Swift.String itself was affected by this bug in the past, but I suspect only the vast minority of people will find that solution.I actually found this by using
CFURLCreateWithBytes
with an interior NUL byte, which makes it unexpectedly fail because of this check that was added in newer versions.I suspect this is potentially a security issue (see e.g. CWE-158 / CWE-626 and RUSTSEC-2021-0123). Semi related to #5164.
The text was updated successfully, but these errors were encountered: