1 /*
   2  * Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 #include <assert.h>
  27 #include <limits.h>
  28 #include <setjmp.h>
  29 #include <stdlib.h>
  30 #include <string.h>
  31 
  32 #include "jni.h"
  33 #include "jvm.h"
  34 #include "check_classname.h"
  35 
  36 typedef unsigned short unicode;
  37 
  38 static char *
  39 skip_over_fieldname(char *name, jboolean slash_okay,
  40                     unsigned int len);
  41 static char *
  42 skip_over_field_signature(char *name, jboolean void_okay,
  43                           unsigned int len);
  44 
  45 /*
  46  * Return non-zero if the character is a valid in JVM class name, zero
  47  * otherwise.  The only characters currently disallowed from JVM class
  48  * names are given in the table below:
  49  *
  50  * Character    Hex     Decimal
  51  * '.'          0x2e    46
  52  * '/'          0x2f    47
  53  * ';'          0x3b    59
  54  * '['          0x5b    91
  55  *
  56  * (Method names have further restrictions dealing with the '<' and
  57  * '>' characters.)
  58  */
  59 static int isJvmIdentifier(unicode ch) {
  60   if( ch > 91 || ch < 46 )
  61     return 1;   /* Lowercase ASCII letters are > 91 */
  62   else { /* 46 <= ch <= 91 */
  63     if (ch <= 90 && ch >= 60) {
  64       return 1; /* Uppercase ASCII recognized here */
  65     } else { /* ch == 91 || 46 <= ch <= 59 */
  66       if (ch == 91 || ch == 59 || ch <= 47)
  67         return 0;
  68       else
  69         return 1;
  70     }
  71   }
  72 }
  73 
  74 static unicode
  75 next_utf2unicode(char **utfstring_ptr, int * valid)
  76 {
  77     unsigned char *ptr = (unsigned char *)(*utfstring_ptr);
  78     unsigned char ch, ch2, ch3;
  79     int length = 1;             /* default length */
  80     unicode result = 0x80;      /* default bad result; */
  81     *valid = 1;
  82     switch ((ch = ptr[0]) >> 4) {
  83         default:
  84             result = ch;
  85             break;
  86 
  87         case 0x8: case 0x9: case 0xA: case 0xB: case 0xF:
  88             /* Shouldn't happen. */
  89             *valid = 0;
  90             break;
  91 
  92         case 0xC: case 0xD:
  93             /* 110xxxxx  10xxxxxx */
  94             if (((ch2 = ptr[1]) & 0xC0) == 0x80) {
  95                 unsigned char high_five = ch & 0x1F;
  96                 unsigned char low_six = ch2 & 0x3F;
  97                 result = (high_five << 6) + low_six;
  98                 length = 2;
  99             }
 100             break;
 101 
 102         case 0xE:
 103             /* 1110xxxx 10xxxxxx 10xxxxxx */
 104             if (((ch2 = ptr[1]) & 0xC0) == 0x80) {
 105                 if (((ch3 = ptr[2]) & 0xC0) == 0x80) {
 106                     unsigned char high_four = ch & 0x0f;
 107                     unsigned char mid_six = ch2 & 0x3f;
 108                     unsigned char low_six = ch3 & 0x3f;
 109                     result = (((high_four << 6) + mid_six) << 6) + low_six;
 110                     length = 3;
 111                 } else {
 112                     length = 2;
 113                 }
 114             }
 115             break;
 116         } /* end of switch */
 117 
 118     *utfstring_ptr = (char *)(ptr + length);
 119     return result;
 120 }
 121 
 122 /* Take pointer to a string.  Skip over the longest part of the string that
 123  * could be taken as a fieldname.  Allow '/' if slash_okay is JNI_TRUE.
 124  *
 125  * Return a pointer to just past the fieldname.  Return NULL if no fieldname
 126  * at all was found, or in the case of slash_okay being true, we saw
 127  * consecutive slashes (meaning we were looking for a qualified path but
 128  * found something that was badly-formed).
 129  */
 130 static char *
 131 skip_over_fieldname(char *name, jboolean slash_okay,
 132                     unsigned int length)
 133 {
 134     char *p;
 135     unicode ch;
 136     unicode last_ch = 0;
 137     int valid = 1;
 138     /* last_ch == 0 implies we are looking at the first char. */
 139     for (p = name; p != name + length; last_ch = ch) {
 140         char *old_p = p;
 141         ch = *p;
 142         if (ch < 128) {
 143             p++;
 144             if (isJvmIdentifier(ch)) {
 145                 continue;
 146             }
 147         } else {
 148             char *tmp_p = p;
 149             ch = next_utf2unicode(&tmp_p, &valid);
 150             if (valid == 0)
 151               return 0;
 152             p = tmp_p;
 153             if (isJvmIdentifier(ch)) {
 154                         continue;
 155             }
 156         }
 157 
 158         if (slash_okay && ch == '/' && last_ch) {
 159             if (last_ch == '/') {
 160                 return 0;       /* Don't permit consecutive slashes */
 161             }
 162         } else if (ch == '_' || ch == '$') {
 163         } else {
 164             return last_ch ? old_p : 0;
 165         }
 166     }
 167     return last_ch ? p : 0;
 168 }
 169 
 170 /* Take pointer to a string.  Skip over the longest part of the string that
 171  * could be taken as a field signature.  Allow "void" if void_okay.
 172  *
 173  * Return a pointer to just past the signature.  Return NULL if no legal
 174  * signature is found.
 175  */
 176 
 177 static char *
 178 skip_over_field_signature(char *name, jboolean void_okay,
 179                           unsigned int length)
 180 {
 181     unsigned int array_dim = 0;
 182     for (;length > 0;) {
 183         switch (name[0]) {
 184             case JVM_SIGNATURE_VOID:
 185                 if (!void_okay) return 0;
 186                 /* FALL THROUGH */
 187             case JVM_SIGNATURE_BOOLEAN:
 188             case JVM_SIGNATURE_BYTE:
 189             case JVM_SIGNATURE_CHAR:
 190             case JVM_SIGNATURE_SHORT:
 191             case JVM_SIGNATURE_INT:
 192             case JVM_SIGNATURE_FLOAT:
 193             case JVM_SIGNATURE_LONG:
 194             case JVM_SIGNATURE_DOUBLE:
 195                 return name + 1;
 196 
 197             case JVM_SIGNATURE_CLASS: {
 198                 /* Skip over the classname, if one is there. */
 199                 char *p =
 200                     skip_over_fieldname(name + 1, JNI_TRUE, --length);
 201                 /* The next character better be a semicolon. */
 202                 if (p && p - name - 1 > 0 && p[0] == ';')
 203                     return p + 1;
 204                 return 0;
 205             }
 206 
 207             case JVM_SIGNATURE_ARRAY:
 208                 array_dim++;
 209                 /* JVMS 2nd ed. 4.10 */
 210                 /*   The number of dimensions in an array is limited to 255 ... */
 211                 if (array_dim > 255) {
 212                     return 0;
 213                 }
 214                 /* The rest of what's there better be a legal signature.  */
 215                 name++;
 216                 length--;
 217                 void_okay = JNI_FALSE;
 218                 break;
 219 
 220             default:
 221                 return 0;
 222         }
 223     }
 224     return 0;
 225 }
 226 
 227 /* Determine if the specified name is legal
 228  * UTF name for a classname.
 229  *
 230  * Note that this routine expects the internal form of qualified classes:
 231  * the dots should have been replaced by slashes.
 232  */
 233 jboolean verifyClassname(char *name, jboolean allowArrayClass)
 234 {
 235     size_t s = strlen(name);
 236     assert(s <= UINT_MAX);
 237     unsigned int length = (unsigned int)s;
 238     char *p;
 239 
 240     if (length > 0 && name[0] == JVM_SIGNATURE_ARRAY) {
 241         if (!allowArrayClass) {
 242             return JNI_FALSE;
 243         } else {
 244             /* Everything that's left better be a field signature */
 245             p = skip_over_field_signature(name, JNI_FALSE, length);
 246         }
 247     } else {
 248         /* skip over the fieldname.  Slashes are okay */
 249         p = skip_over_fieldname(name, JNI_TRUE, length);
 250     }
 251     return (p != 0 && p - name == (ptrdiff_t)length);
 252 }
 253 
 254 /*
 255  * Translates '.' to '/'.  Returns JNI_TRUE if any / were present.
 256  */
 257 jboolean verifyFixClassname(char *name)
 258 {
 259     char *p = name;
 260     jboolean slashesFound = JNI_FALSE;
 261     int valid = 1;
 262 
 263     while (valid != 0 && *p != '\0') {
 264         if (*p == '/') {
 265             slashesFound = JNI_TRUE;
 266             p++;
 267         } else if (*p == '.') {
 268             *p++ = '/';
 269         } else {
 270             next_utf2unicode(&p, &valid);
 271         }
 272     }
 273 
 274     return slashesFound && valid != 0;
 275 }
 276 
 277 /*
 278  * Translates '.' to '/'.
 279  */
 280 void fixClassname(char *name)
 281 {
 282     char *p = name;
 283     int valid = 1;
 284 
 285     while (valid != 0 && *p != '\0') {
 286         if (*p == '.') {
 287             *p++ = '/';
 288         } else {
 289             next_utf2unicode(&p, &valid);
 290         }
 291     }
 292 }