diff options
Diffstat (limited to 'drivers/gpu/drm/drm_modes.c')
| -rw-r--r-- | drivers/gpu/drm/drm_modes.c | 60 | 
1 files changed, 52 insertions, 8 deletions
diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c index 74a5739df506..c814bcef18a4 100644 --- a/drivers/gpu/drm/drm_modes.c +++ b/drivers/gpu/drm/drm_modes.c @@ -1454,6 +1454,7 @@ static int drm_mode_parse_cmdline_refresh(const char *str, char **end_ptr,  }  static int drm_mode_parse_cmdline_extra(const char *str, int length, +					bool freestanding,  					const struct drm_connector *connector,  					struct drm_cmdline_mode *mode)  { @@ -1462,9 +1463,15 @@ static int drm_mode_parse_cmdline_extra(const char *str, int length,  	for (i = 0; i < length; i++) {  		switch (str[i]) {  		case 'i': +			if (freestanding) +				return -EINVAL; +  			mode->interlace = true;  			break;  		case 'm': +			if (freestanding) +				return -EINVAL; +  			mode->margins = true;  			break;  		case 'D': @@ -1542,6 +1549,7 @@ static int drm_mode_parse_cmdline_res_mode(const char *str, unsigned int length,  			if (extras) {  				int ret = drm_mode_parse_cmdline_extra(end_ptr + i,  								       1, +								       false,  								       connector,  								       mode);  				if (ret) @@ -1669,6 +1677,22 @@ static int drm_mode_parse_cmdline_options(char *str, size_t len,  	return 0;  } +static const char * const drm_named_modes_whitelist[] = { +	"NTSC", +	"PAL", +}; + +static bool drm_named_mode_is_in_whitelist(const char *mode, unsigned int size) +{ +	int i; + +	for (i = 0; i < ARRAY_SIZE(drm_named_modes_whitelist); i++) +		if (!strncmp(mode, drm_named_modes_whitelist[i], size)) +			return true; + +	return false; +} +  /**   * drm_mode_parse_command_line_for_connector - parse command line modeline for connector   * @mode_option: optional per connector mode option @@ -1686,7 +1710,7 @@ static int drm_mode_parse_cmdline_options(char *str, size_t len,   *   * Additionals options can be provided following the mode, using a comma to   * separate each option. Valid options can be found in - * Documentation/fb/modedb.txt. + * Documentation/fb/modedb.rst.   *   * The intermediate drm_cmdline_mode structure is required to store additional   * options from the command line modline like the force-enable/disable flag. @@ -1725,16 +1749,30 @@ bool drm_mode_parse_command_line_for_connector(const char *mode_option,  	 * bunch of things:  	 *   - We need to make sure that the first character (which  	 *     would be our resolution in X) is a digit. -	 *   - However, if the X resolution is missing, then we end up -	 *     with something like x<yres>, with our first character -	 *     being an alpha-numerical character, which would be -	 *     considered a named mode. +	 *   - If not, then it's either a named mode or a force on/off. +	 *     To distinguish between the two, we need to run the +	 *     extra parsing function, and if not, then we consider it +	 *     a named mode.  	 *  	 * If this isn't enough, we should add more heuristics here,  	 * and matching unit-tests.  	 */ -	if (!isdigit(name[0]) && name[0] != 'x') +	if (!isdigit(name[0]) && name[0] != 'x') { +		unsigned int namelen = strlen(name); + +		/* +		 * Only the force on/off options can be in that case, +		 * and they all take a single character. +		 */ +		if (namelen == 1) { +			ret = drm_mode_parse_cmdline_extra(name, namelen, true, +							   connector, mode); +			if (!ret) +				return true; +		} +  		named_mode = true; +	}  	/* Try to locate the bpp and refresh specifiers, if any */  	bpp_ptr = strchr(name, '-'); @@ -1770,7 +1808,13 @@ bool drm_mode_parse_command_line_for_connector(const char *mode_option,  	}  	if (named_mode) { -		strncpy(mode->name, name, mode_end); +		if (mode_end + 1 > DRM_DISPLAY_MODE_LEN) +			return false; + +		if (!drm_named_mode_is_in_whitelist(name, mode_end)) +			return false; + +		strscpy(mode->name, name, mode_end + 1);  	} else {  		ret = drm_mode_parse_cmdline_res_mode(name, mode_end,  						      parse_extras, @@ -1809,7 +1853,7 @@ bool drm_mode_parse_command_line_for_connector(const char *mode_option,  	    extra_ptr != options_ptr) {  		int len = strlen(name) - (extra_ptr - name); -		ret = drm_mode_parse_cmdline_extra(extra_ptr, len, +		ret = drm_mode_parse_cmdline_extra(extra_ptr, len, false,  						   connector, mode);  		if (ret)  			return false;  | 
