miwarin / netbsd-gnats-memo

0 stars 0 forks source link

bin/32358 inetd.conf sndbuf/rcvbuf parser is fragile #23

Open miwarin opened 9 years ago

miwarin commented 9 years ago

http://gnats.netbsd.org/32358

再現する

inetd.conf 編集

echo            stream  tcp,sndbuf=262144,rcvbuf=32768      nowait  nobody  internal

HUP 送る

sudo kill -HUP `cat /var/run/inetd.pid`

ログ(コンソールにも印字される)

% tail /var/log/messages
Jan  3 14:27:41 mogu inetd[717]: echo: malformed buffer size option `262144'
miwarin commented 9 years ago

ログメッセージはマクロ MALFORMED

http://nxr.netbsd.org/xref/src/usr.sbin/inetd/inetd.c#1415

1413 #define    MALFORMED(arg) \
1414 do { \
1415    syslog(LOG_ERR, "%s: malformed buffer size option `%s'", \
1416        sep->se_service, (arg)); \
1417    goto more; \
1418    /*NOTREACHED*/ \
1419 } while (/*CONSTCOND*/0)

MALFORMED を呼び出してるところいくつか

http://nxr.netbsd.org/source/xref/src/usr.sbin/inetd/inetd.c#1421

1421 #define    GETVAL(arg) \
1422 do { \
1423    if (!isdigit((unsigned char)*(arg))) \
1424        MALFORMED(arg); \
1425    val = (int)strtol((arg), &cp0, 10); \
1426    if (cp0 != NULL) { \
1427        if (cp0[1] != '\0') \
1428            MALFORMED((arg)); \
1429        if (cp0[0] == 'k') \
1430            val *= 1024; \
1431        if (cp0[0] == 'm') \
1432            val *= 1024 * 1024; \
1433    } \
1434    if (val < 1) { \
1435        syslog(LOG_ERR, "%s: invalid buffer size `%s'", \
1436            sep->se_service, (arg)); \
1437        goto more; \
1438    } \
1439    /*NOTREACHED*/ \
1440 } while (/*CONSTCOND*/0)

http://nxr.netbsd.org/source/xref/src/usr.sbin/inetd/inetd.c#1442

1442 #define    ASSIGN(arg) \
1443 do { \
1444    if (strcmp((arg), "sndbuf") == 0) \
1445        sep->se_sndbuf = val; \
1446    else if (strcmp((arg), "rcvbuf") == 0) \
1447        sep->se_rcvbuf = val; \
1448    else \
1449        MALFORMED((arg)); \
1450 } while (/*CONSTCOND*/0)

http://nxr.netbsd.org/source/xref/src/usr.sbin/inetd/inetd.c#1483

1481            /* Locate the size. */
1482            if ((sz1 = strchr(buf1, '=')) == NULL)
1483                MALFORMED(buf1)

http://nxr.netbsd.org/source/xref/src/usr.sbin/inetd/inetd.c#1491

1489        /* Locate the size. */
1490        if ((sz0 = strchr(buf0, '=')) == NULL)
1491            MALFORMED(buf0);
miwarin commented 9 years ago

GETVAL での処理か?

GETVAL の呼び出し元

http://nxr.netbsd.org/source/xref/src/usr.sbin/inetd/inetd.c#1496

1496        GETVAL(sz0);
1497        ASSIGN(buf0);
1498 
1499        if (buf1 != NULL) {
1500            GETVAL(sz1);
1501            ASSIGN(buf1);
1502        }
miwarin commented 9 years ago

GETVAL の整数チェックに引っかかってる。

1423    if (!isdigit((unsigned char)*(arg))) \
1424        MALFORMED(arg); \

sdigit には結局 arg の先頭の1文字だけ与えている。意図は不明。 しかし isdigit で「整数ではない」と判定されてる。 エラーになるときは sndbuf=262144,rcvbuf=32768 を与えた。arg は "262144" だ

miwarin commented 9 years ago

GETVAL を日本語にすると

  1. 整数かチェック (問題ではここで引っかかってる)
  2. strtol で val に整数部を格納
  3. k が与えられてれば val *= 1024
  4. m が与えられてれば val = 1024 1024

val は int

int argc, val;
miwarin commented 9 years ago

strtol の endp が何やっても NULL にならん。

#include <stdio.h>
#include <ctype.h>

void conv( char* arg )
{
    int val, isd;
    char* cp0;

    val = (int)strtol((arg), &cp0, 10);
    isd = isdigit((unsigned char)*(arg));

    printf("arg:%-10s isdigit:%d val:%10d ", arg, isd, val);
    if( cp0 != NULL )
        printf("cp0:%-10s\n", cp0);
    else
        printf("\n");
}

int main(int ac, char** av)
{
    conv("262144");
    conv("128k");
    conv("128ab");
    conv("255");
    conv("+255");
    conv("-255");
    conv("abcd");
    conv("abc123def");
    return 0;
}

実行

% gcc a.c
% ./a.out
arg:262144     isdigit:4 val:    262144 cp0:
arg:128k       isdigit:4 val:       128 cp0:k
arg:128ab      isdigit:4 val:       128 cp0:ab
arg:255        isdigit:4 val:       255 cp0:
arg:+255       isdigit:0 val:       255 cp0:
arg:-255       isdigit:0 val:      -255 cp0:
arg:abcd       isdigit:0 val:         0 cp0:abcd
arg:abc123def  isdigit:0 val:         0 cp0:abc123def
miwarin commented 9 years ago

strtoq(3) - NetBSD Manual Pages On-line Manual of "strtol" INT06-C. 文字列トークンを整数に変換するには strtol() 系の関数を使う c++ - C: using strtol endptr is never NULL, cannot check if value is integer only? - Stack Overflow

miwarin commented 9 years ago

パッチ投げた。反応なし