5

開示:私はCにかなり慣れていません。回答を詳細に説明していただければ幸いです。

私は Linux カーネル モジュールを作成しています。作成中の関数の 1 つで、次のような構造をユーザー空間にコピーする必要があります。

typedef struct
{
    uint32_t  someProperty;
    uint32_t  numOfFruits;
    uint32_t  *arrayOfFruits;
} ObjectCapabilities;

私が実装している API には、メンバーを「各要素が FRUIT_TYPE 定数であるarrayOfFruitsサイズの配列」と説明するドキュメントがあります。numOfFruitsarrayOfFruits がポインターであることを考えると、これを行う方法がわかりません。構造体を作成するとcopy_to_userポインターがユーザー空間にObjectCapabilitiesコピーされるだけです。 arrayOfFruits

ユーザー空間はどのようにして配列の要素に継続的にアクセスできますか? これが私の試みです:

ObjectCapabilities caps;
caps.someProperty = 1024;
caps.numOfFruits  = 3;
uint32_t localArray[] = {
        FRUIT_TYPE_APPLE,
        FRUIT_TYPE_ORANGE,
        FRUIT_TYPE_BANANA
};
caps.arrayOfFruits = localArray;

そして、コピーのために... これだけできますか?

copy_to_user((void *)destination, &caps, (sizeof(caps) + (sizeof(localArray) / sizeof((localArray)[0]))));
4

3 に答える 3

3

カーネル空間へのポインターはユーザー空間にとって意味がないため、生のポインターをコピーすることはできません (逆参照するとセグメンテーション違反が発生します)。

このようなことを行う一般的な方法は、ユーザー空間コードにメモリを割り当てて、そのメモリへのポインタをシステム コールに渡すように要求することです。プログラムが十分な大きさのバッファーを渡さない場合、エラーで失敗します (例: EFAULT)。プログラムが必要とするメモリ量をアプリオリに事前に知る方法がない場合は、通常、NULLポインターを渡したときに必要なデータ量を返します。

ユーザー空間からの使用例:

// Fixed-size data
typedef struct
{
    uint32_t  someProperty;
    uint32_t  numOfFruits;
} ObjectCapabilities;

// First query the number of fruits we need
ObjectCapabilities caps;
int r = sys_get_fruit(&caps, NULL, 0);
if (r != 0) { /* Handle error */ }

// Now allocate memory and query the fruit
uint32_t *arrayOfFruits = malloc(caps.numOfFruits * sizeof(uint32_t));
r = sys_get_fruit(&caps, arrayOfFruits, caps.numOfFruits);
if (r != 0) { /* Handle error */ }

そして、対応するコードがシステム コールの反対側のカーネル空間でどのように見えるかを次に示します。

int sys_get_fruit(ObjectCapabilities __user *userCaps, uint32_t __user *userFruit, uint32_t numFruits)
{
    ObjectCapabilities caps;
    caps.someProperty = 1024;
    caps.numOfFruits  = 3;

    // Copy out fixed-size data
    int r = copy_to_user(userCaps, &caps, sizeof(caps));
    if (r != 0)
        return r;

    uint32_t localArray[] = {
        FRUIT_TYPE_APPLE,
        FRUIT_TYPE_ORANGE,
        FRUIT_TYPE_BANANA
    };

    // Attempt to copy variable-sized data.  Check the size first.
    if (numFruits * sizeof(uint32_t) < sizeof(localArray))
        return -EFAULT;
    return copy_to_user(userFruit, localArray, sizeof(localArray));
}
于 2013-08-29T20:58:49.133 に答える
2

copy_to_userあなたはユーザーに2つのコピーを行うでしょう.

//copy the struct
copy_to_user((void *)destination, &caps, sizeof(caps));
//copy the array.
copy_to_user((void *)destination->array, localArray, sizeof(localArray);
于 2013-08-29T20:14:06.963 に答える