summaryrefslogtreecommitdiffstats
path: root/core
diff options
context:
space:
mode:
authorJeff Sharkey <jsharkey@android.com>2015-06-11 19:13:37 -0700
committerJeff Sharkey <jsharkey@android.com>2015-06-11 19:16:27 -0700
commit4f5e8b3ca489245005b76176ac6d28f5f184f3fe (patch)
tree2b7975f534d07dfc7759cd5461630457b31759f5 /core
parent47b872d9c36347382dd24ad5c3f70490d8fcbb23 (diff)
downloadframeworks_base-4f5e8b3ca489245005b76176ac6d28f5f184f3fe.zip
frameworks_base-4f5e8b3ca489245005b76176ac6d28f5f184f3fe.tar.gz
frameworks_base-4f5e8b3ca489245005b76176ac6d28f5f184f3fe.tar.bz2
Valid filenames have length limits!
ext4 filenames are at most 255 bytes. vfat filenames are bit more lax, but we're often saving them on ext4 through a FUSE daemon, so limit them the same way. Since package names are used as directory names, verify that they're valid filenames. Tests to verify behavior. Bug: 18689171 Change-Id: If7df4c40d352954510b71de4ff05d78259c721ed
Diffstat (limited to 'core')
-rw-r--r--core/java/android/content/pm/PackageParser.java19
-rw-r--r--core/java/android/os/FileUtils.java26
-rw-r--r--core/tests/coretests/src/android/os/FileUtilsTest.java12
3 files changed, 50 insertions, 7 deletions
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 83b0140..c92c256 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -36,6 +36,7 @@ import android.content.res.TypedArray;
import android.content.res.XmlResourceParser;
import android.os.Build;
import android.os.Bundle;
+import android.os.FileUtils;
import android.os.PatternMatcher;
import android.os.UserHandle;
import android.text.TextUtils;
@@ -1194,7 +1195,8 @@ public class PackageParser {
}
}
- private static String validateName(String name, boolean requiresSeparator) {
+ private static String validateName(String name, boolean requireSeparator,
+ boolean requireFilename) {
final int N = name.length();
boolean hasSep = false;
boolean front = true;
@@ -1216,7 +1218,10 @@ public class PackageParser {
}
return "bad character '" + c + "'";
}
- return hasSep || !requiresSeparator
+ if (requireFilename && !FileUtils.isValidExtFilename(name)) {
+ return "Invalid filename";
+ }
+ return hasSep || !requireSeparator
? null : "must have at least one '.' separator";
}
@@ -1240,7 +1245,7 @@ public class PackageParser {
final String packageName = attrs.getAttributeValue(null, "package");
if (!"android".equals(packageName)) {
- final String error = validateName(packageName, true);
+ final String error = validateName(packageName, true, true);
if (error != null) {
throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME,
"Invalid manifest package: " + error);
@@ -1252,7 +1257,7 @@ public class PackageParser {
if (splitName.length() == 0) {
splitName = null;
} else {
- final String error = validateName(splitName, false);
+ final String error = validateName(splitName, false, false);
if (error != null) {
throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME,
"Invalid manifest split: " + error);
@@ -1391,7 +1396,7 @@ public class PackageParser {
String str = sa.getNonConfigurationString(
com.android.internal.R.styleable.AndroidManifest_sharedUserId, 0);
if (str != null && str.length() > 0) {
- String nameError = validateName(str, true);
+ String nameError = validateName(str, true, false);
if (nameError != null && !"android".equals(pkgName)) {
outError[0] = "<manifest> specifies bad sharedUserId name \""
+ str + "\": " + nameError;
@@ -1973,7 +1978,7 @@ public class PackageParser {
return null;
}
String subName = proc.substring(1);
- String nameError = validateName(subName, false);
+ String nameError = validateName(subName, false, false);
if (nameError != null) {
outError[0] = "Invalid " + type + " name " + proc + " in package "
+ pkg + ": " + nameError;
@@ -1981,7 +1986,7 @@ public class PackageParser {
}
return (pkg + proc).intern();
}
- String nameError = validateName(proc, true);
+ String nameError = validateName(proc, true, false);
if (nameError != null && !"system".equals(proc)) {
outError[0] = "Invalid " + type + " name " + proc + " in package "
+ pkg + ": " + nameError;
diff --git a/core/java/android/os/FileUtils.java b/core/java/android/os/FileUtils.java
index 917271d..864225a 100644
--- a/core/java/android/os/FileUtils.java
+++ b/core/java/android/os/FileUtils.java
@@ -24,6 +24,8 @@ import android.util.Log;
import android.util.Slog;
import android.webkit.MimeTypeMap;
+import com.android.internal.annotations.VisibleForTesting;
+
import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
@@ -34,6 +36,7 @@ import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
+import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Objects;
@@ -456,6 +459,7 @@ public class FileUtils {
res.append('_');
}
}
+ trimFilename(res, 255);
return res.toString();
}
@@ -504,9 +508,31 @@ public class FileUtils {
res.append('_');
}
}
+ // Even though vfat allows 255 UCS-2 chars, we might eventually write to
+ // ext4 through a FUSE layer, so use that limit.
+ trimFilename(res, 255);
+ return res.toString();
+ }
+
+ @VisibleForTesting
+ public static String trimFilename(String str, int maxBytes) {
+ final StringBuilder res = new StringBuilder(str);
+ trimFilename(res, maxBytes);
return res.toString();
}
+ private static void trimFilename(StringBuilder res, int maxBytes) {
+ byte[] raw = res.toString().getBytes(StandardCharsets.UTF_8);
+ if (raw.length > maxBytes) {
+ maxBytes -= 3;
+ while (raw.length > maxBytes) {
+ res.deleteCharAt(res.length() / 2);
+ raw = res.toString().getBytes(StandardCharsets.UTF_8);
+ }
+ res.insert(res.length() / 2, "...");
+ }
+ }
+
public static String rewriteAfterRename(File beforeDir, File afterDir, String path) {
if (path == null) return null;
final File result = rewriteAfterRename(beforeDir, afterDir, new File(path));
diff --git a/core/tests/coretests/src/android/os/FileUtilsTest.java b/core/tests/coretests/src/android/os/FileUtilsTest.java
index ee9e2e4..ac5abad 100644
--- a/core/tests/coretests/src/android/os/FileUtilsTest.java
+++ b/core/tests/coretests/src/android/os/FileUtilsTest.java
@@ -232,6 +232,18 @@ public class FileUtilsTest extends AndroidTestCase {
assertEquals("foo_bar__baz", FileUtils.buildValidFatFilename("foo?bar**baz"));
}
+ public void testTrimFilename() throws Exception {
+ assertEquals("short.txt", FileUtils.trimFilename("short.txt", 16));
+ assertEquals("extrem...eme.txt", FileUtils.trimFilename("extremelylongfilename.txt", 16));
+
+ final String unicode = "a\u03C0\u03C0\u03C0\u03C0z";
+ assertEquals("a\u03C0\u03C0\u03C0\u03C0z", FileUtils.trimFilename(unicode, 10));
+ assertEquals("a\u03C0...\u03C0z", FileUtils.trimFilename(unicode, 9));
+ assertEquals("a...\u03C0z", FileUtils.trimFilename(unicode, 8));
+ assertEquals("a...\u03C0z", FileUtils.trimFilename(unicode, 7));
+ assertEquals("a...z", FileUtils.trimFilename(unicode, 6));
+ }
+
public void testBuildUniqueFile_normal() throws Exception {
assertNameEquals("test.jpg", FileUtils.buildUniqueFile(mTarget, "image/jpeg", "test"));
assertNameEquals("test.jpg", FileUtils.buildUniqueFile(mTarget, "image/jpeg", "test.jpg"));