[settings] Avoid returning uninitialised data on error in fetch_xxx_setting()
Callers (e.g. usr/autoboot.c) may not check the return values from fetch_xxx_setting(), assuming that in error cases the returned setting value will be "empty" (for some sensible value of "empty"). In particular, if the DHCP server did not specify a next-server address, this would result in gPXE using uninitialised data for the TFTP server IP address.
This commit is contained in:
parent
cbf9003d66
commit
612f4e7a99
@ -333,6 +333,9 @@ int fetch_setting ( struct settings *settings, struct setting *setting,
|
|||||||
struct settings *child;
|
struct settings *child;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
/* Avoid returning uninitialised data on error */
|
||||||
|
memset ( data, 0, len );
|
||||||
|
|
||||||
/* NULL settings implies starting at the global settings root */
|
/* NULL settings implies starting at the global settings root */
|
||||||
if ( ! settings )
|
if ( ! settings )
|
||||||
settings = &settings_root;
|
settings = &settings_root;
|
||||||
@ -381,7 +384,6 @@ int fetch_setting_len ( struct settings *settings, struct setting *setting ) {
|
|||||||
*/
|
*/
|
||||||
int fetch_string_setting ( struct settings *settings, struct setting *setting,
|
int fetch_string_setting ( struct settings *settings, struct setting *setting,
|
||||||
char *data, size_t len ) {
|
char *data, size_t len ) {
|
||||||
memset ( data, 0, len );
|
|
||||||
return fetch_setting ( settings, setting, data,
|
return fetch_setting ( settings, setting, data,
|
||||||
( ( len > 0 ) ? ( len - 1 ) : 0 ) );
|
( ( len > 0 ) ? ( len - 1 ) : 0 ) );
|
||||||
}
|
}
|
||||||
@ -417,20 +419,23 @@ int fetch_ipv4_setting ( struct settings *settings, struct setting *setting,
|
|||||||
int fetch_int_setting ( struct settings *settings, struct setting *setting,
|
int fetch_int_setting ( struct settings *settings, struct setting *setting,
|
||||||
long *value ) {
|
long *value ) {
|
||||||
union {
|
union {
|
||||||
long value;
|
|
||||||
uint8_t u8[ sizeof ( long ) ];
|
uint8_t u8[ sizeof ( long ) ];
|
||||||
int8_t s8[ sizeof ( long ) ];
|
int8_t s8[ sizeof ( long ) ];
|
||||||
} buf;
|
} buf;
|
||||||
int len;
|
int len;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
buf.value = 0;
|
/* Avoid returning uninitialised data on error */
|
||||||
|
*value = 0;
|
||||||
|
|
||||||
|
/* Fetch raw (network-ordered, variable-length) setting */
|
||||||
len = fetch_setting ( settings, setting, &buf, sizeof ( buf ) );
|
len = fetch_setting ( settings, setting, &buf, sizeof ( buf ) );
|
||||||
if ( len < 0 )
|
if ( len < 0 )
|
||||||
return len;
|
return len;
|
||||||
if ( len > ( int ) sizeof ( buf ) )
|
if ( len > ( int ) sizeof ( buf ) )
|
||||||
return -ERANGE;
|
return -ERANGE;
|
||||||
|
|
||||||
|
/* Convert to host-ordered signed long */
|
||||||
*value = ( ( buf.s8[0] >= 0 ) ? 0 : -1L );
|
*value = ( ( buf.s8[0] >= 0 ) ? 0 : -1L );
|
||||||
for ( i = 0 ; i < len ; i++ ) {
|
for ( i = 0 ; i < len ; i++ ) {
|
||||||
*value = ( ( *value << 8 ) | buf.u8[i] );
|
*value = ( ( *value << 8 ) | buf.u8[i] );
|
||||||
@ -452,10 +457,15 @@ int fetch_uint_setting ( struct settings *settings, struct setting *setting,
|
|||||||
long svalue;
|
long svalue;
|
||||||
int len;
|
int len;
|
||||||
|
|
||||||
|
/* Avoid returning uninitialised data on error */
|
||||||
|
*value = 0;
|
||||||
|
|
||||||
|
/* Fetch as a signed long */
|
||||||
len = fetch_int_setting ( settings, setting, &svalue );
|
len = fetch_int_setting ( settings, setting, &svalue );
|
||||||
if ( len < 0 )
|
if ( len < 0 )
|
||||||
return len;
|
return len;
|
||||||
|
|
||||||
|
/* Mask off sign-extended bits */
|
||||||
*value = ( svalue & ( -1UL >> ( sizeof ( long ) - len ) ) );
|
*value = ( svalue & ( -1UL >> ( sizeof ( long ) - len ) ) );
|
||||||
|
|
||||||
return len;
|
return len;
|
||||||
@ -469,7 +479,7 @@ int fetch_uint_setting ( struct settings *settings, struct setting *setting,
|
|||||||
* @ret value Setting value, or zero
|
* @ret value Setting value, or zero
|
||||||
*/
|
*/
|
||||||
long fetch_intz_setting ( struct settings *settings, struct setting *setting ){
|
long fetch_intz_setting ( struct settings *settings, struct setting *setting ){
|
||||||
long value = 0;
|
long value;
|
||||||
|
|
||||||
fetch_int_setting ( settings, setting, &value );
|
fetch_int_setting ( settings, setting, &value );
|
||||||
return value;
|
return value;
|
||||||
@ -484,7 +494,7 @@ long fetch_intz_setting ( struct settings *settings, struct setting *setting ){
|
|||||||
*/
|
*/
|
||||||
unsigned long fetch_uintz_setting ( struct settings *settings,
|
unsigned long fetch_uintz_setting ( struct settings *settings,
|
||||||
struct setting *setting ) {
|
struct setting *setting ) {
|
||||||
unsigned long value = 0;
|
unsigned long value;
|
||||||
|
|
||||||
fetch_uint_setting ( settings, setting, &value );
|
fetch_uint_setting ( settings, setting, &value );
|
||||||
return value;
|
return value;
|
||||||
|
Reference in New Issue
Block a user