snprintf
snprintf()はスタックに積まれた引数のトップアドレスを取得し、第一引数のfmtから動的に、引数タイプを取得することで、関数引数に依存しないsprintfです。
引数のスタックへのアセンブラでの設定は、型に依存せず、acpi_native_intのサイズ単位で行われ、システムによっては4バイト/8バイトとなります。それが8バイトとすると、32ビットカーネルだと、fmtのアドレスにポインタサイズの4加算しても、実際は8バイトで、次の引数のアドレスではありません。_bnd()はポインタサイズにacpi_native_intサイズに応じて、そのサイズ単位で切り上げする事で、システムに依存しない形で、アドレスを取得できるようにしています。
vsnprintf()はfmtから、順に引数タイプを取得し、Tの取得タイプ引数でva_arg()展開し、取得したアドレスをbuffに設定します。同時に次の引数にアドレスを更新します。
va_end()は意味不明です。gccに最適化に影響するのかもしれませんが、実装からするとまったく意味ありません。推測ですが、va_arg()で取得し終えたva_listアドレスは、呼び出し側のスタック領域となり、プログラミング的に、脆弱性とならない旨のコーダへの注意勧告じゃないでしょうか?
#include <linux/module.h>
MODULE_LICENSE("GPL");
int init_module(void)
{
char buff[64];
snprintf(buff, sizeof(buff), "%s:%d\n", "hoge", 1);
printk(buff);
snprintf(buff, sizeof(buff), "%d:%d:%s\n", 1,2,"hoge");
printk(buff);
return -1;
}
[root@localhost lkm]# insmod snprintf.ko
insmod: error inserting 'snprintf.ko': -1 Operation not permitted
[root@localhost lkm]# dmesg
[49779.685782] hoge:1
[49779.685813] 1:2:hoge
va_start()でfmtのアドレスをargsに取得します。引数はスタックの上位に向かって順に配置されていきます。従ってspの配下(最初にpush bpされ、それを考慮してのsp)のアドレスのfmtのアドレスを取得し、そのサイズ分を加算したアドレスが、以降編集対象引数の先頭アドレスとなります。引数のスタックへのアセンブラでの設定は、型に依存せず、acpi_native_intのサイズ単位で行われ、システムによっては4バイト/8バイトとなります。それが8バイトとすると、32ビットカーネルだと、fmtのアドレスにポインタサイズの4加算しても、実際は8バイトで、次の引数のアドレスではありません。_bnd()はポインタサイズにacpi_native_intサイズに応じて、そのサイズ単位で切り上げする事で、システムに依存しない形で、アドレスを取得できるようにしています。
vsnprintf()はfmtから、順に引数タイプを取得し、Tの取得タイプ引数でva_arg()展開し、取得したアドレスをbuffに設定します。同時に次の引数にアドレスを更新します。
va_end()は意味不明です。gccに最適化に影響するのかもしれませんが、実装からするとまったく意味ありません。推測ですが、va_arg()で取得し終えたva_listアドレスは、呼び出し側のスタック領域となり、プログラミング的に、脆弱性とならない旨のコーダへの注意勧告じゃないでしょうか?
typedef unsigned int u32;
typedef unsigned long long u64;
typedef char *va_list;
typedef s32 acpi_native_int;
typedef s64 acpi_native_int;
#define _AUPBND (sizeof (acpi_native_int) - 1)
#define _bnd(X, bnd) (((sizeof (X)) + (bnd)) & (~(bnd)))
#define va_end(ap) (void) 0
#define va_start(ap, A) (void) ((ap) = (((char *) &(A)) + (_bnd (A,_AUPBND))))
#define va_arg(ap, T) (*(T *)(((ap) += (_bnd (T, _AUPBND))) - (_bnd (T,_ADNBND))))
int snprintf(char *buf, size_t size, const char *fmt, ...)
{
va_list args;
int i;
va_start(args, fmt);
i = vsnprintf(buf, size, fmt, args);
va_end(args);
return i;
}





