1
Fork 0
mirror of git://git.sv.gnu.org/emacs.git synced 2025-12-07 23:10:28 -08:00

Improve efficiency of checking for access to authority documents

* java/org/gnu/emacs/EmacsService.java (checkContentUri): Take a
string instead of a byte array.  Then, use
checkCallingUriPermission, in lieu of opening the file.
* src/android.c (android_check_content_access): Delete unused
function.
(android_init_emacs_service): Adjust for changes to
checkContentUri's signature.
* src/androidvfs.c (android_get_content_name): Return the file
name in a new buffer.
(android_check_content_access): Adjust correspondingly.
(android_authority_name): Verify NAME is a valid JNI string.
This commit is contained in:
Po Lu 2023-08-14 13:15:08 +08:00
parent 3895f88233
commit 9fb00904f9
3 changed files with 51 additions and 89 deletions

View file

@ -960,44 +960,30 @@ public final class EmacsService extends Service
} }
} }
/* Return whether Emacs is directly permitted to access the
content:// URI NAME. This is not a suitable test for files which
Emacs can access by virtue of their containing document
trees. */
public boolean public boolean
checkContentUri (byte[] string, boolean readable, boolean writable) checkContentUri (String name, boolean readable, boolean writable)
{ {
String mode, name; String mode;
ParcelFileDescriptor fd; ParcelFileDescriptor fd;
Uri uri;
int rc, flags;
/* Decode this into a URI. */ uri = Uri.parse (name);
flags = 0;
try if (readable)
{ flags |= Intent.FLAG_GRANT_READ_URI_PERMISSION;
/* The usual file name encoding question rears its ugly head
again. */
name = new String (string, "UTF-8");
}
catch (UnsupportedEncodingException exception)
{
name = null;
throw new RuntimeException (exception);
}
mode = "r";
if (writable) if (writable)
mode += "w"; flags |= Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
try rc = checkCallingUriPermission (uri, flags);
{ return rc == PackageManager.PERMISSION_GRANTED;
fd = resolver.openFileDescriptor (Uri.parse (name), mode);
fd.close ();
return true;
}
catch (Exception exception)
{
/* Fall through. */
}
return false;
} }
/* Build a content file name for URI. /* Build a content file name for URI.

View file

@ -1107,41 +1107,6 @@ android_get_content_name (const char *filename)
return NULL; return NULL;
} }
/* Return whether or not the specified FILENAME is an accessible
content URI. MODE specifies what to check. */
static bool
android_check_content_access (const char *filename, int mode)
{
const char *name;
jobject string;
size_t length;
jboolean rc;
name = android_get_content_name (filename);
length = strlen (name);
string = (*android_java_env)->NewByteArray (android_java_env,
length);
android_exception_check ();
(*android_java_env)->SetByteArrayRegion (android_java_env,
string, 0, length,
(jbyte *) name);
rc = (*android_java_env)->CallBooleanMethod (android_java_env,
emacs_service,
service_class.check_content_uri,
string,
(jboolean) ((mode & R_OK)
!= 0),
(jboolean) ((mode & W_OK)
!= 0));
android_exception_check_1 (string);
ANDROID_DELETE_LOCAL_REF (string);
return rc;
}
#endif /* 0 */ #endif /* 0 */
/* Return the current user's ``home'' directory, which is actually the /* Return the current user's ``home'' directory, which is actually the
@ -1549,7 +1514,7 @@ android_init_emacs_service (void)
FIND_METHOD (open_content_uri, "openContentUri", FIND_METHOD (open_content_uri, "openContentUri",
"([BZZZ)I"); "([BZZZ)I");
FIND_METHOD (check_content_uri, "checkContentUri", FIND_METHOD (check_content_uri, "checkContentUri",
"([BZZ)Z"); "(Ljava/lang/String;ZZ)Z");
FIND_METHOD (query_battery, "queryBattery", "()[J"); FIND_METHOD (query_battery, "queryBattery", "()[J");
FIND_METHOD (update_extracted_text, "updateExtractedText", FIND_METHOD (update_extracted_text, "updateExtractedText",
"(Lorg/gnu/emacs/EmacsWindow;" "(Lorg/gnu/emacs/EmacsWindow;"

View file

@ -2765,14 +2765,13 @@ android_content_initial (char *name, size_t length)
/* Return the content URI corresponding to a `/content/by-authority' /* Return the content URI corresponding to a `/content/by-authority'
file name, or NULL if it is invalid for some reason. FILENAME file name, or NULL if it is invalid for some reason. FILENAME
should be relative to /content/by-authority, with no leading should be relative to /content/by-authority, with no leading
directory separator character. directory separator character. */
This function is not reentrant. */ static char *
static const char *
android_get_content_name (const char *filename) android_get_content_name (const char *filename)
{ {
static char buffer[PATH_MAX + 1], *fill; char *fill, *buffer;
size_t length;
/* Make sure FILENAME isn't obviously invalid: it must contain an /* Make sure FILENAME isn't obviously invalid: it must contain an
authority name and a file name component. */ authority name and a file name component. */
@ -2784,48 +2783,53 @@ android_get_content_name (const char *filename)
return NULL; return NULL;
} }
/* FILENAME must also not be a directory. */ /* FILENAME must also not be a directory. Accessing content
provider directories is not supported by this interface. */
if (filename[strlen (filename)] == '/') length = strlen (filename);
if (filename[length] == '/')
{ {
errno = ENOTDIR; errno = ENOTDIR;
return NULL; return NULL;
} }
snprintf (buffer, PATH_MAX + 1, "content://%s", filename); /* Prefix FILENAME with content:// and return the buffer containing
that URI. */
buffer = xmalloc (sizeof "content://" + length);
sprintf (buffer, "content://%s", filename);
return buffer; return buffer;
} }
/* Return whether or not the specified URI is an accessible content /* Return whether or not the specified URI is an accessible content
URI. MODE specifies what to check. */ URI. MODE specifies what to check.
URI must be a string in the JVM's extended UTF-8 format. */
static bool static bool
android_check_content_access (const char *uri, int mode) android_check_content_access (const char *uri, int mode)
{ {
jobject string; jobject string;
size_t length; size_t length;
jboolean rc; jboolean rc, read, write;
length = strlen (uri); length = strlen (uri);
string = (*android_java_env)->NewByteArray (android_java_env, string = (*android_java_env)->NewStringUTF (android_java_env, uri);
length);
android_exception_check (); android_exception_check ();
(*android_java_env)->SetByteArrayRegion (android_java_env, /* Establish what is being checked. Checking for read access is
string, 0, length, identical to checking if the file exists. */
(jbyte *) uri);
read = (bool) (mode & R_OK || (mode == F_OK));
write = (bool) (mode & W_OK);
rc = (*android_java_env)->CallBooleanMethod (android_java_env, rc = (*android_java_env)->CallBooleanMethod (android_java_env,
emacs_service, emacs_service,
service_class.check_content_uri, service_class.check_content_uri,
string, string, read, write);
(jboolean) ((mode & R_OK)
!= 0),
(jboolean) ((mode & W_OK)
!= 0));
android_exception_check_1 (string); android_exception_check_1 (string);
ANDROID_DELETE_LOCAL_REF (string); ANDROID_DELETE_LOCAL_REF (string);
return rc; return rc;
} }
@ -2889,7 +2893,7 @@ android_authority_name (struct android_vnode *vnode, char *name,
size_t length) size_t length)
{ {
struct android_authority_vnode *vp; struct android_authority_vnode *vp;
const char *uri_name; char *uri_name;
if (!android_init_gui) if (!android_init_gui)
{ {
@ -2922,6 +2926,12 @@ android_authority_name (struct android_vnode *vnode, char *name,
if (*name == '/') if (*name == '/')
name++, length -= 1; name++, length -= 1;
/* NAME must be a valid JNI string, so that it can be encoded
properly. */
if (android_verify_jni_string (name))
goto no_entry;
uri_name = android_get_content_name (name); uri_name = android_get_content_name (name);
if (!uri_name) if (!uri_name)
goto error; goto error;
@ -2931,11 +2941,12 @@ android_authority_name (struct android_vnode *vnode, char *name,
vp->vnode.ops = &authority_vfs_ops; vp->vnode.ops = &authority_vfs_ops;
vp->vnode.type = ANDROID_VNODE_CONTENT_AUTHORITY; vp->vnode.type = ANDROID_VNODE_CONTENT_AUTHORITY;
vp->vnode.flags = 0; vp->vnode.flags = 0;
vp->uri = xstrdup (uri_name); vp->uri = uri_name;
return &vp->vnode; return &vp->vnode;
} }
/* Content files can't have children. */ /* Content files can't have children. */
no_entry:
errno = ENOENT; errno = ENOENT;
error: error:
return NULL; return NULL;