memo.log

技術情報の雑なメモ

setsocopt探訪のメモ(5)

前回までは、 setsocopt 関数はOSのシステムコールを呼んでいるらしいというところまで確認した。 今回は、カーネルシステムコールの実装を覗いてみたいと思います。(確認した時のカーネルのバージョンは linux-4.19.172 kernel/git/stable/linux.git - Linux kernel stable tree

setsocopt で検索すると、以下のファイルにそれっぽい定義がありました。 linux-4.19.172/net/packet/af_packet.c

すると以下の箇所に今回焦点を当てているオプションの PACKET_ADD_MEMBERSHIP に関する処理の定義があります。

以下の copy_from_user はメモリ空間からカーネル空間に変数のメモリをコピーする関数です。 ここで (copy_from_user(&mreq, optval, len)) では文字列のポインタ optval を packet_mreq_max 構造体にコピーしています。 つまり、ここでデータを指定の構造体に入れ直していると考えて良さそうです。 したがって、 copy_from_user において文字列データとしてユーザー空間からデータを取得するため、ユーザー空間のプログラムでは構造体でも文字列データでも同じように処理が出来たと考えられます。 これで一旦最初の疑問は解消できたように思います!

static int
packet_setsockopt(struct socket *sock, int level, int optname, char __user *optval, unsigned int optlen)
{
    struct sock *sk = sock->sk;
    struct packet_sock *po = pkt_sk(sk);
    int ret;

    if (level != SOL_PACKET)
        return -ENOPROTOOPT;

    switch (optname) {
    case PACKET_ADD_MEMBERSHIP:
    case PACKET_DROP_MEMBERSHIP:
    {
        struct packet_mreq_max mreq;
        int len = optlen;
        memset(&mreq, 0, sizeof(mreq));
        if (len < sizeof(struct packet_mreq))
            return -EINVAL;
        if (len > sizeof(mreq))
            len = sizeof(mreq);
        if (copy_from_user(&mreq, optval, len))
            return -EFAULT;

amzn.to