ratbagd: make sure the profile name is ascii-only

Strings on DBus need to be valid UTF8, some of the default profile names on
the G700 include the degree character (" Profile n° 1"), the whole string ends
up being invalid UTF8.

This results in two issues:
- ratbagd gets quietly kicked off the bus when it sends that string
- ratbag-command throws an exception because Python is unhappy about the
  non-UTF8 string:
  UnicodeEncodeError: 'utf-8' codec can't encode character '\udcb0' in position 3: surrogates not allowed

The quick workaround here is to strip anything that's not ASCII from the
profile name. The same may be necessary for some device names too, but let's
wait until we see that.

For ratbag-command we convert the string to bytes and back using the 'ignore'
argument, this way we should see the original profile string without the
printf errors.

This is an incomplete fix, we'll have the same issue if a user tries to set a
non-ASCII name. The long-term fix is to convert whatever we have (probably ISO
8859-1, but can we detect that?) into UTF8 before passing it around. That
would also mean converting it back before writing to the device.

Fixes #617

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
This commit is contained in:
Peter Hutterer
2019-02-18 08:38:01 +10:00
parent a7f44211df
commit caa75d170d
3 changed files with 34 additions and 2 deletions

View File

@@ -382,8 +382,15 @@ ratbagd_profile_get_name(sd_bus *bus,
{
struct ratbagd_profile *profile = userdata;
const char *name = ratbag_profile_get_name(profile->lib_profile);
_cleanup_free_ char *asciiname;
CHECK_CALL(sd_bus_message_append(reply, "s", name));
/* This should really be a UTF8 check and it should really be in
* libratbag, but for now this will do to at least not kick us off
* the bus. https://github.com/libratbag/libratbag/issues/617
*/
asciiname = strdup_ascii_only(name);
CHECK_CALL(sd_bus_message_append(reply, "s", asciiname));
return 0;
}

View File

@@ -116,6 +116,27 @@ snprintf_safe(char *buf, size_t n, const char *fmt, ...)
return rc;
}
/**
* Returns a strdup'd string with all non-ascii characters replaced with a
* space.
*/
static inline char *
strdup_ascii_only(const char *str_in)
{
char *str, *ascii_only;
ascii_only = strdup_safe(str_in);
str = ascii_only;
while (str && *str) {
unsigned char c = *str;
if (c > 127)
*str = ' ';
str++;
}
return ascii_only;
}
#define sprintf_safe(buf, fmt, ...) \
snprintf_safe(buf, ARRAY_LENGTH(buf), fmt, __VA_ARGS__)

View File

@@ -522,7 +522,11 @@ def func_profile_get(r, args):
def func_profile_name_get(r, args):
p, d = find_profile(r, args)
print(p.name)
# See https://github.com/libratbag/libratbag/issues/617
# ratbag converts to ascii, so this has no real effect there, but
# ratbag-command may still have a non-ascii string.
string = bytes(p.name, 'utf-8', 'ignore')
print(string.decode('utf-8'))
def func_profile_name_set(r, args):