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:hogeva_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; }