]> git.ipfire.org Git - thirdparty/openldap.git/commitdiff
ITS#9815 slapd-sql: escape filter values
authorHoward Chu <hyc@openldap.org>
Wed, 23 Mar 2022 12:43:31 +0000 (12:43 +0000)
committerQuanah Gibson-Mount <quanah@openldap.org>
Wed, 4 May 2022 14:50:58 +0000 (14:50 +0000)
Escape filter values to slapd-sql (CVE-2022-29155)

servers/slapd/back-sql/search.c

index 2168a1553b208317501796004e4d64a3f9ec5076..d4177f62926f177a8399a5bdd7432c2c683a4cd1 100644 (file)
@@ -63,6 +63,38 @@ static void send_paged_response(
        ID  *lastid );
 #endif /* ! BACKSQL_ARBITRARY_KEY */
 
+/* Look for chars that need to be escaped, return count of them.
+ * If out is non-NULL, copy escape'd val to it.
+ */
+static int
+backsql_val_escape( Operation *op, struct berval *in, struct berval *out )
+{
+       char *ptr, *end;
+       int q = 0;
+
+       ptr = in->bv_val;
+       end = ptr + in->bv_len;
+       while (ptr < end) {
+               if ( *ptr == '\'' )
+                       q++;
+               ptr++;
+       }
+       if ( q && out ) {
+               char *dst;
+               out->bv_len = in->bv_len + q;
+               out->bv_val = op->o_tmpalloc( out->bv_len + 1, op->o_tmpmemctx );
+               ptr = in->bv_val;
+               dst = out->bv_val;
+               while (ptr < end ) {
+                       if ( *ptr == '\'' )
+                               *dst++ = '\'';
+                       *dst++ = *ptr++;
+               }
+               *dst = '\0';
+       }
+       return q;
+}
+
 static int
 backsql_attrlist_add( backsql_srch_info *bsi, AttributeDescription *ad )
 {
@@ -429,6 +461,8 @@ backsql_process_sub_filter( backsql_srch_info *bsi, Filter *f,
        backsql_info            *bi = (backsql_info *)bsi->bsi_op->o_bd->be_private;
        int                     i;
        int                     casefold = 0;
+       int                     escaped = 0;
+       struct berval   escval, *fvalue;
 
        if ( !f ) {
                return 0;
@@ -462,50 +496,68 @@ backsql_process_sub_filter( backsql_srch_info *bsi, Filter *f,
 
                BER_BVZERO( &bv );
                if ( f->f_sub_initial.bv_val ) {
-                       bv.bv_len += f->f_sub_initial.bv_len;
+                       bv.bv_len += f->f_sub_initial.bv_len + backsql_val_escape( NULL, &f->f_sub_initial, NULL );
                }
                if ( f->f_sub_any != NULL ) {
                        for ( a = 0; f->f_sub_any[ a ].bv_val != NULL; a++ ) {
-                               bv.bv_len += f->f_sub_any[ a ].bv_len;
+                               bv.bv_len += f->f_sub_any[ a ].bv_len + backsql_val_escape( NULL, &f->f_sub_any[ a ], NULL );
                        }
                }
                if ( f->f_sub_final.bv_val ) {
-                       bv.bv_len += f->f_sub_final.bv_len;
+                       bv.bv_len += f->f_sub_final.bv_len + backsql_val_escape( NULL, &f->f_sub_final, NULL );
                }
                bv.bv_len = 2 * bv.bv_len - 1;
                bv.bv_val = ch_malloc( bv.bv_len + 1 );
 
                s = 0;
                if ( !BER_BVISNULL( &f->f_sub_initial ) ) {
-                       bv.bv_val[ s ] = f->f_sub_initial.bv_val[ 0 ];
-                       for ( i = 1; i < f->f_sub_initial.bv_len; i++ ) {
+                       fvalue = &f->f_sub_initial;
+                       escaped = backsql_val_escape( bsi->bsi_op, fvalue, &escval );
+                       if ( escaped )
+                               fvalue = &escval;
+                       bv.bv_val[ s ] = fvalue->bv_val[ 0 ];
+                       for ( i = 1; i < fvalue->bv_len; i++ ) {
                                bv.bv_val[ s + 2 * i - 1 ] = '%';
-                               bv.bv_val[ s + 2 * i ] = f->f_sub_initial.bv_val[ i ];
+                               bv.bv_val[ s + 2 * i ] = fvalue->bv_val[ i ];
                        }
                        bv.bv_val[ s + 2 * i - 1 ] = '%';
                        s += 2 * i;
+                       if ( escaped )
+                               bsi->bsi_op->o_tmpfree( escval.bv_val, bsi->bsi_op->o_tmpmemctx );
                }
 
                if ( f->f_sub_any != NULL ) {
                        for ( a = 0; !BER_BVISNULL( &f->f_sub_any[ a ] ); a++ ) {
-                               bv.bv_val[ s ] = f->f_sub_any[ a ].bv_val[ 0 ];
-                               for ( i = 1; i < f->f_sub_any[ a ].bv_len; i++ ) {
+                               fvalue = &f->f_sub_any[ a ];
+                               escaped = backsql_val_escape( bsi->bsi_op, fvalue, &escval );
+                               if ( escaped )
+                                       fvalue = &escval;
+                               bv.bv_val[ s ] = fvalue->bv_val[ 0 ];
+                               for ( i = 1; i < fvalue->bv_len; i++ ) {
                                        bv.bv_val[ s + 2 * i - 1 ] = '%';
-                                       bv.bv_val[ s + 2 * i ] = f->f_sub_any[ a ].bv_val[ i ];
+                                       bv.bv_val[ s + 2 * i ] = fvalue->bv_val[ i ];
                                }
                                bv.bv_val[ s + 2 * i - 1 ] = '%';
                                s += 2 * i;
+                               if ( escaped )
+                                       bsi->bsi_op->o_tmpfree( escval.bv_val, bsi->bsi_op->o_tmpmemctx );
                        }
                }
 
                if ( !BER_BVISNULL( &f->f_sub_final ) ) {
-                       bv.bv_val[ s ] = f->f_sub_final.bv_val[ 0 ];
-                       for ( i = 1; i < f->f_sub_final.bv_len; i++ ) {
+                       fvalue = &f->f_sub_final;
+                       escaped = backsql_val_escape( bsi->bsi_op, fvalue, &escval );
+                       if ( escaped )
+                               fvalue = &escval;
+                       bv.bv_val[ s ] = fvalue->bv_val[ 0 ];
+                       for ( i = 1; i < fvalue->bv_len; i++ ) {
                                bv.bv_val[ s + 2 * i - 1 ] = '%';
-                               bv.bv_val[ s + 2 * i ] = f->f_sub_final.bv_val[ i ];
+                               bv.bv_val[ s + 2 * i ] = fvalue->bv_val[ i ];
                        }
-                               bv.bv_val[ s + 2 * i - 1 ] = '%';
+                       bv.bv_val[ s + 2 * i - 1 ] = '%';
                        s += 2 * i;
+                       if ( escaped )
+                               bsi->bsi_op->o_tmpfree( escval.bv_val, bsi->bsi_op->o_tmpmemctx );
                }
 
                bv.bv_val[ s - 1 ] = '\0';
@@ -561,11 +613,17 @@ backsql_process_sub_filter( backsql_srch_info *bsi, Filter *f,
                        f->f_sub_initial.bv_val );
 #endif /* BACKSQL_TRACE */
 
+               fvalue = &f->f_sub_initial;
+               escaped = backsql_val_escape( bsi->bsi_op, fvalue, &escval );
+               if ( escaped )
+                       fvalue = &escval;
                start = bsi->bsi_flt_where.bb_val.bv_len;
                backsql_strfcat_x( &bsi->bsi_flt_where,
                                bsi->bsi_op->o_tmpmemctx,
                                "b",
-                               &f->f_sub_initial );
+                               fvalue );
+               if ( escaped )
+                       bsi->bsi_op->o_tmpfree( escval.bv_val, bsi->bsi_op->o_tmpmemctx );
                if ( casefold && BACKSQL_AT_CANUPPERCASE( at ) ) {
                        ldap_pvt_str2upper( &bsi->bsi_flt_where.bb_val.bv_val[ start ] );
                }
@@ -586,12 +644,18 @@ backsql_process_sub_filter( backsql_srch_info *bsi, Filter *f,
                                i, f->f_sub_any[ i ].bv_val );
 #endif /* BACKSQL_TRACE */
 
+                       fvalue = &f->f_sub_any[ i ];
+                       escaped = backsql_val_escape( bsi->bsi_op, fvalue, &escval );
+                       if ( escaped )
+                               fvalue = &escval;
                        start = bsi->bsi_flt_where.bb_val.bv_len;
                        backsql_strfcat_x( &bsi->bsi_flt_where,
                                        bsi->bsi_op->o_tmpmemctx,
                                        "bc",
-                                       &f->f_sub_any[ i ],
+                                       fvalue,
                                        '%' );
+                       if ( escaped )
+                               bsi->bsi_op->o_tmpfree( escval.bv_val, bsi->bsi_op->o_tmpmemctx );
                        if ( casefold && BACKSQL_AT_CANUPPERCASE( at ) ) {
                                /*
                                 * Note: toupper('%') = '%'
@@ -611,11 +675,17 @@ backsql_process_sub_filter( backsql_srch_info *bsi, Filter *f,
                        f->f_sub_final.bv_val );
 #endif /* BACKSQL_TRACE */
 
+               fvalue = &f->f_sub_final;
+               escaped = backsql_val_escape( bsi->bsi_op, fvalue, &escval );
+               if ( escaped )
+                       fvalue = &escval;
                start = bsi->bsi_flt_where.bb_val.bv_len;
                backsql_strfcat_x( &bsi->bsi_flt_where,
                                bsi->bsi_op->o_tmpmemctx,
                                "b",
-                               &f->f_sub_final );
+                               fvalue );
+               if ( escaped )
+                       bsi->bsi_op->o_tmpfree( escval.bv_val, bsi->bsi_op->o_tmpmemctx );
                if ( casefold && BACKSQL_AT_CANUPPERCASE( at ) ) {
                        ldap_pvt_str2upper( &bsi->bsi_flt_where.bb_val.bv_val[ start ] );
                }
@@ -1182,6 +1252,8 @@ backsql_process_filter_attr( backsql_srch_info *bsi, Filter *f, backsql_at_map_r
        struct berval           *filter_value = NULL;
        MatchingRule            *matching_rule = NULL;
        struct berval           ordering = BER_BVC("<=");
+       struct berval           escval;
+       int                                     escaped = 0;
 
        Debug( LDAP_DEBUG_TRACE, "==>backsql_process_filter_attr(%s)\n",
                at->bam_ad->ad_cname.bv_val );
@@ -1236,6 +1308,10 @@ equality_match:;
                        casefold = 1;
                }
 
+               escaped = backsql_val_escape( bsi->bsi_op, filter_value, &escval );
+               if ( escaped )
+                       filter_value = &escval;
+
                /* FIXME: directoryString filtering should use a similar
                 * approach to deal with non-prettified values like
                 * " A  non    prettified   value  ", by using a LIKE
@@ -1316,6 +1392,10 @@ equality_match:;
                        casefold = 1;
                }
 
+               escaped = backsql_val_escape( bsi->bsi_op, filter_value, &escval );
+               if ( escaped )
+                       filter_value = &escval;
+
                /*
                 * FIXME: should we uppercase the operands?
                 */
@@ -1349,7 +1429,7 @@ equality_match:;
                                        &at->bam_sel_expr,
                                        &ordering,
                                        '\'',
-                                       &f->f_av_value,
+                                       filter_value,
                                        (ber_len_t)STRLENOF( /* (' */ "')" ),
                                                /* ( */ "')" );
                }
@@ -1373,13 +1453,17 @@ equality_match:;
        case LDAP_FILTER_APPROX:
                /* we do our best */
 
+               filter_value = &f->f_av_value;
+               escaped = backsql_val_escape( bsi->bsi_op, filter_value, &escval );
+               if ( escaped )
+                       filter_value = &escval;
                /*
                 * maybe we should check type of at->sel_expr here somehow,
                 * to know whether upper_func is applicable, but for now
                 * upper_func stuff is made for Oracle, where UPPER is
                 * safely applicable to NUMBER etc.
                 */
-               (void)backsql_process_filter_like( bsi, at, 1, &f->f_av_value );
+               (void)backsql_process_filter_like( bsi, at, 1, filter_value );
                break;
 
        default:
@@ -1393,6 +1477,9 @@ equality_match:;
 
        }
 
+       if ( escaped )
+               bsi->bsi_op->o_tmpfree( escval.bv_val, bsi->bsi_op->o_tmpmemctx );
+
        Debug( LDAP_DEBUG_TRACE, "<==backsql_process_filter_attr(%s)\n",
                at->bam_ad->ad_cname.bv_val );