Unescape strings properly in NsdService.

NativeDaemonEvent.unescapeArgs() was improperly skipping the terminating
quote in cases like "\\", where the char preceding the quote is a
backslash, but the backslash itself is escaped, so the quote is indeed
an unescaped terminator.

unescapeArgs() doesn't unescape "\xxx" decimal escapes used by mDNS, so
fix NsdService to do that sort of unescaping explicitly (which is only
applicable when it receives a "fullname", in SERVICE_RESOLVED).

Bug: 16983542
Bug: 16986203

Change-Id: Idfa79749336c68424d961bc414f984c525b7e5e6
This commit is contained in:
Sreeram Ramachandran
2014-09-03 15:45:59 -07:00
parent eff82e8099
commit a53dd7f9ef
2 changed files with 47 additions and 18 deletions

View File

@@ -201,20 +201,16 @@ public class NativeDaemonEvent {
} }
while (current < length) { while (current < length) {
// find the end of the word // find the end of the word
if (quoted) { char terminator = quoted ? '\"' : ' ';
wordEnd = current; wordEnd = current;
while ((wordEnd = rawEvent.indexOf('\"', wordEnd)) != -1) { while (wordEnd < length && rawEvent.charAt(wordEnd) != terminator) {
if (rawEvent.charAt(wordEnd - 1) != '\\') { if (rawEvent.charAt(wordEnd) == '\\') {
break; // skip the escaped char
} else { ++wordEnd;
wordEnd++; // skip this escaped quote and keep looking
}
} }
} else { ++wordEnd;
wordEnd = rawEvent.indexOf(' ', current);
} }
// if we didn't find the end-o-word token, take the rest of the string if (wordEnd > length) wordEnd = length;
if (wordEnd == -1) wordEnd = length;
String word = rawEvent.substring(current, wordEnd); String word = rawEvent.substring(current, wordEnd);
current += word.length(); current += word.length();
if (!quoted) { if (!quoted) {

View File

@@ -397,8 +397,7 @@ public class NsdService extends INsdManager.Stub {
break; break;
case NsdManager.NATIVE_DAEMON_EVENT: case NsdManager.NATIVE_DAEMON_EVENT:
NativeEvent event = (NativeEvent) msg.obj; NativeEvent event = (NativeEvent) msg.obj;
if (!handleNativeEvent(event.code, event.raw, if (!handleNativeEvent(event.code, event.raw, event.cooked)) {
NativeDaemonEvent.unescapeArgs(event.raw))) {
result = NOT_HANDLED; result = NOT_HANDLED;
} }
break; break;
@@ -474,8 +473,14 @@ public class NsdService extends INsdManager.Stub {
case NativeResponseCode.SERVICE_RESOLVED: case NativeResponseCode.SERVICE_RESOLVED:
/* NNN resolveId fullName hostName port txtlen txtdata */ /* NNN resolveId fullName hostName port txtlen txtdata */
if (DBG) Slog.d(TAG, "SERVICE_RESOLVED Raw: " + raw); if (DBG) Slog.d(TAG, "SERVICE_RESOLVED Raw: " + raw);
int index = cooked[2].indexOf("."); int index = 0;
if (index == -1) { while (index < cooked[2].length() && cooked[2].charAt(index) != '.') {
if (cooked[2].charAt(index) == '\\') {
++index;
}
++index;
}
if (index >= cooked[2].length()) {
Slog.e(TAG, "Invalid service found " + raw); Slog.e(TAG, "Invalid service found " + raw);
break; break;
} }
@@ -483,6 +488,8 @@ public class NsdService extends INsdManager.Stub {
String rest = cooked[2].substring(index); String rest = cooked[2].substring(index);
String type = rest.replace(".local.", ""); String type = rest.replace(".local.", "");
name = unescape(name);
clientInfo.mResolvedService.setServiceName(name); clientInfo.mResolvedService.setServiceName(name);
clientInfo.mResolvedService.setServiceType(type); clientInfo.mResolvedService.setServiceType(type);
clientInfo.mResolvedService.setPort(Integer.parseInt(cooked[4])); clientInfo.mResolvedService.setPort(Integer.parseInt(cooked[4]));
@@ -541,6 +548,30 @@ public class NsdService extends INsdManager.Stub {
} }
} }
private String unescape(String s) {
StringBuilder sb = new StringBuilder(s.length());
for (int i = 0; i < s.length(); ++i) {
char c = s.charAt(i);
if (c == '\\') {
if (++i >= s.length()) {
Slog.e(TAG, "Unexpected end of escape sequence in: " + s);
break;
}
c = s.charAt(i);
if (c != '.' && c != '\\') {
if (i + 2 >= s.length()) {
Slog.e(TAG, "Unexpected end of escape sequence in: " + s);
break;
}
c = (char) ((c-'0') * 100 + (s.charAt(i+1)-'0') * 10 + (s.charAt(i+2)-'0'));
i += 2;
}
}
sb.append(c);
}
return sb.toString();
}
private NativeDaemonConnector mNativeConnector; private NativeDaemonConnector mNativeConnector;
private final CountDownLatch mNativeDaemonConnected = new CountDownLatch(1); private final CountDownLatch mNativeDaemonConnected = new CountDownLatch(1);
@@ -625,10 +656,12 @@ public class NsdService extends INsdManager.Stub {
private class NativeEvent { private class NativeEvent {
final int code; final int code;
final String raw; final String raw;
final String[] cooked;
NativeEvent(int code, String raw) { NativeEvent(int code, String raw, String[] cooked) {
this.code = code; this.code = code;
this.raw = raw; this.raw = raw;
this.cooked = cooked;
} }
} }
@@ -644,7 +677,7 @@ public class NsdService extends INsdManager.Stub {
public boolean onEvent(int code, String raw, String[] cooked) { public boolean onEvent(int code, String raw, String[] cooked) {
// TODO: NDC translates a message to a callback, we could enhance NDC to // TODO: NDC translates a message to a callback, we could enhance NDC to
// directly interact with a state machine through messages // directly interact with a state machine through messages
NativeEvent event = new NativeEvent(code, raw); NativeEvent event = new NativeEvent(code, raw, cooked);
mNsdStateMachine.sendMessage(NsdManager.NATIVE_DAEMON_EVENT, event); mNsdStateMachine.sendMessage(NsdManager.NATIVE_DAEMON_EVENT, event);
return true; return true;
} }