check file owner when attaching files or using them as avatar

This commit is contained in:
Daniel Gultsch 2016-04-07 20:29:40 +02:00
parent 290f0a123e
commit 0460702710
4 changed files with 55 additions and 2 deletions

View file

@ -1,5 +1,7 @@
package eu.siacs.conversations.persistance; package eu.siacs.conversations.persistance;
import android.annotation.TargetApi;
import android.content.ContentResolver;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.database.Cursor; import android.database.Cursor;
@ -9,8 +11,13 @@ import android.graphics.Canvas;
import android.graphics.Matrix; import android.graphics.Matrix;
import android.graphics.RectF; import android.graphics.RectF;
import android.net.Uri; import android.net.Uri;
import android.os.Build;
import android.os.Environment; import android.os.Environment;
import android.os.ParcelFileDescriptor;
import android.provider.OpenableColumns; import android.provider.OpenableColumns;
import android.system.ErrnoException;
import android.system.Os;
import android.system.StructStat;
import android.util.Base64; import android.util.Base64;
import android.util.Base64OutputStream; import android.util.Base64OutputStream;
import android.util.Log; import android.util.Log;
@ -19,6 +26,7 @@ import android.webkit.MimeTypeMap;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.Closeable; import java.io.Closeable;
import java.io.File; import java.io.File;
import java.io.FileDescriptor;
import java.io.FileNotFoundException; import java.io.FileNotFoundException;
import java.io.FileOutputStream; import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
@ -646,4 +654,29 @@ public class FileBackend {
} }
} }
} }
public static boolean weOwnFile(Uri uri) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
return false;
} else {
return uri != null
&& ContentResolver.SCHEME_FILE.equals(uri.getScheme())
&& weOwnFileLollipop(uri);
}
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
private static boolean weOwnFileLollipop(Uri uri) {
try {
File file = new File(uri.getPath());
FileDescriptor fd = ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_ONLY).getFileDescriptor();
StructStat st = Os.fstat(fd);
return st.st_uid == android.os.Process.myUid();
} catch (ErrnoException e) {
return true;
} catch (FileNotFoundException e) {
return false;
}
}
} }

View file

@ -403,6 +403,11 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
public void attachFileToConversation(final Conversation conversation, public void attachFileToConversation(final Conversation conversation,
final Uri uri, final Uri uri,
final UiCallback<Message> callback) { final UiCallback<Message> callback) {
if (FileBackend.weOwnFile(uri)) {
Log.d(Config.LOGTAG,"trying to attach file that belonged to us");
callback.error(R.string.security_error_invalid_file_access, null);
return;
}
final Message message; final Message message;
if (conversation.getNextEncryption() == Message.ENCRYPTION_PGP) { if (conversation.getNextEncryption() == Message.ENCRYPTION_PGP) {
message = new Message(conversation, "", Message.ENCRYPTION_DECRYPTED); message = new Message(conversation, "", Message.ENCRYPTION_DECRYPTED);
@ -441,6 +446,11 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
} }
public void attachImageToConversation(final Conversation conversation, final Uri uri, final UiCallback<Message> callback) { public void attachImageToConversation(final Conversation conversation, final Uri uri, final UiCallback<Message> callback) {
if (FileBackend.weOwnFile(uri)) {
Log.d(Config.LOGTAG,"trying to attach file that belonged to us");
callback.error(R.string.security_error_invalid_file_access, null);
return;
}
final String compressPictures = getCompressPicturesPreference(); final String compressPictures = getCompressPicturesPreference();
if ("never".equals(compressPictures) if ("never".equals(compressPictures)
|| ("auto".equals(compressPictures) && getFileBackend().useImageAsIs(uri))) { || ("auto".equals(compressPictures) && getFileBackend().useImageAsIs(uri))) {

View file

@ -23,6 +23,7 @@ import java.io.File;
import eu.siacs.conversations.Config; import eu.siacs.conversations.Config;
import eu.siacs.conversations.R; import eu.siacs.conversations.R;
import eu.siacs.conversations.entities.Account; import eu.siacs.conversations.entities.Account;
import eu.siacs.conversations.persistance.FileBackend;
import eu.siacs.conversations.utils.FileUtils; import eu.siacs.conversations.utils.FileUtils;
import eu.siacs.conversations.utils.PhoneHelper; import eu.siacs.conversations.utils.PhoneHelper;
import eu.siacs.conversations.xmpp.pep.Avatar; import eu.siacs.conversations.xmpp.pep.Avatar;
@ -187,9 +188,13 @@ public class PublishProfilePictureActivity extends XmppActivity {
protected void onActivityResult(int requestCode, int resultCode, final Intent data) { protected void onActivityResult(int requestCode, int resultCode, final Intent data) {
super.onActivityResult(requestCode, resultCode, data); super.onActivityResult(requestCode, resultCode, data);
if (resultCode == RESULT_OK) { if (resultCode == RESULT_OK) {
Uri source = data.getData();
switch (requestCode) { switch (requestCode) {
case REQUEST_CHOOSE_FILE_AND_CROP: case REQUEST_CHOOSE_FILE_AND_CROP:
Uri source = data.getData(); if (FileBackend.weOwnFile(source)) {
Toast.makeText(this,R.string.security_error_invalid_file_access,Toast.LENGTH_SHORT).show();
return;
}
String original = FileUtils.getPath(this, source); String original = FileUtils.getPath(this, source);
if (original != null) { if (original != null) {
source = Uri.parse("file://"+original); source = Uri.parse("file://"+original);
@ -199,7 +204,11 @@ public class PublishProfilePictureActivity extends XmppActivity {
Crop.of(source, destination).asSquare().withMaxSize(size, size).start(this); Crop.of(source, destination).asSquare().withMaxSize(size, size).start(this);
break; break;
case REQUEST_CHOOSE_FILE: case REQUEST_CHOOSE_FILE:
this.avatarUri = data.getData(); if (FileBackend.weOwnFile(source)) {
Toast.makeText(this,R.string.security_error_invalid_file_access,Toast.LENGTH_SHORT).show();
return;
}
this.avatarUri = source;
if (xmppConnectionServiceBound) { if (xmppConnectionServiceBound) {
loadImageIntoPreview(this.avatarUri); loadImageIntoPreview(this.avatarUri);
} }

View file

@ -609,4 +609,5 @@
<string name="no_keys_just_confirm">You already trust this contact. By selecting \'done\' you are just confirming that %s is part of this conference.</string> <string name="no_keys_just_confirm">You already trust this contact. By selecting \'done\' you are just confirming that %s is part of this conference.</string>
<string name="select_image_and_crop">Select image and crop</string> <string name="select_image_and_crop">Select image and crop</string>
<string name="this_account_is_disabled">You have disabled this account</string> <string name="this_account_is_disabled">You have disabled this account</string>
<string name="security_error_invalid_file_access">Security error: Invalid file access</string>
</resources> </resources>