首页 > 其他 > 详细

socket与系统调用深度分析

时间:2019-12-20 01:09:41      阅读:95      评论:0      收藏:0      [点我收藏+]

1.什么是系统调用?为什么要有系统调用?

系统调用是操作系统提供给用户的一些列特殊接口,用于访问系统资源,可以方便用户的使用,也可以约束用户的行为。

或由于能力 ,或由于意图,不能完全信任应用程序及其编写者,不允许用户直接控制硬件资源,硬件资源必须由操作系统统一管理,而不允许应用程序直接访问硬件(网络设备也在其列)。

操作系统只允许应用程序调用操作系统中封装的一系列命令,来间接使用硬件资源,这就是系统调用。

2.本次实验说明

  1.实验平台和工具:本次实验基于WSL环境和xfce4,VcXsrvt产生的图形界面,通过gdb工具设置断点并进行调试

  2.前置环境:在前一次实验中搭建的menuOS https://www.cnblogs.com/Miliapus/p/12031824.html(前一次实验使用实验楼虚拟环境,这次在WSL上重复了前一次实验的步骤

  3.简述:带参数启动menuOs,打开gdb监听端口并设置断点,执行replyhi命令后分析执行情况

3.详细流程:

1.修改Makefile文件,加入参数-s -S -apend nokaslr用于调试

技术分享图片

2.启用gdb并设置断点 

先设置start_kernel以检查 断点是否工作

技术分享图片

可见 断点确实起效

技术分享图片

设置断点 break sys_socketcall

允许menuos完成启动

技术分享图片

输入命令replyhi

技术分享图片

到达断点

技术分享图片

继续运行

可以观察到这个断点总计到达了两次

说明replyhi命令中 sys_socketcall运行了两次

我们猜测这两次应该是socket、bind

我们研究这个函数:

SYSCALL_DEFINE2(socketcall, int, call, unsigned long __user *, args)
{
    unsigned long a[AUDITSC_ARGS];
    unsigned long a0, a1;
    int err;
    unsigned int len;

    if (call < 1 || call > SYS_SENDMMSG)
        return -EINVAL;
    call = array_index_nospec(call, SYS_SENDMMSG + 1);

    len = nargs[call];
    if (len > sizeof(a))
        return -EINVAL;

    /* copy_from_user should be SMP safe. */
    if (copy_from_user(a, args, len))
        return -EFAULT;

    err = audit_socketcall(nargs[call] / sizeof(unsigned long), a);
    if (err)
        return err;

    a0 = a[0];
    a1 = a[1];

    switch (call) {
    case SYS_SOCKET:
        err = __sys_socket(a0, a1, a[2]);
        break;
    case SYS_BIND:
        err = __sys_bind(a0, (struct sockaddr __user *)a1, a[2]);
        break;
    case SYS_CONNECT:
        err = __sys_connect(a0, (struct sockaddr __user *)a1, a[2]);
        break;
    case SYS_LISTEN:
        err = __sys_listen(a0, a1);
        break;
    case SYS_ACCEPT:
        err = __sys_accept4(a0, (struct sockaddr __user *)a1,
                    (int __user *)a[2], 0);
        break;
    case SYS_GETSOCKNAME:
        err =
            __sys_getsockname(a0, (struct sockaddr __user *)a1,
                      (int __user *)a[2]);
        break;
    case SYS_GETPEERNAME:
        err =
            __sys_getpeername(a0, (struct sockaddr __user *)a1,
                      (int __user *)a[2]);
        break;
    case SYS_SOCKETPAIR:
        err = __sys_socketpair(a0, a1, a[2], (int __user *)a[3]);
        break;
    case SYS_SEND:
        err = __sys_sendto(a0, (void __user *)a1, a[2], a[3],
                   NULL, 0);
        break;
    case SYS_SENDTO:
        err = __sys_sendto(a0, (void __user *)a1, a[2], a[3],
                   (struct sockaddr __user *)a[4], a[5]);
        break;
    case SYS_RECV:
        err = __sys_recvfrom(a0, (void __user *)a1, a[2], a[3],
                     NULL, NULL);
        break;
    case SYS_RECVFROM:
        err = __sys_recvfrom(a0, (void __user *)a1, a[2], a[3],
                     (struct sockaddr __user *)a[4],
                     (int __user *)a[5]);
        break;
    case SYS_SHUTDOWN:
        err = __sys_shutdown(a0, a1);
        break;
    case SYS_SETSOCKOPT:
        err = __sys_setsockopt(a0, a1, a[2], (char __user *)a[3],
                       a[4]);
        break;
    case SYS_GETSOCKOPT:
        err =
            __sys_getsockopt(a0, a1, a[2], (char __user *)a[3],
                     (int __user *)a[4]);
        break;
    case SYS_SENDMSG:
        err = __sys_sendmsg(a0, (struct user_msghdr __user *)a1,
                    a[2], true);
        break;
    case SYS_SENDMMSG:
        err = __sys_sendmmsg(a0, (struct mmsghdr __user *)a1, a[2],
                     a[3], true);
        break;
    case SYS_RECVMSG:
        err = __sys_recvmsg(a0, (struct user_msghdr __user *)a1,
                    a[2], true);
        break;
    case SYS_RECVMMSG:
        if (IS_ENABLED(CONFIG_64BIT) || !IS_ENABLED(CONFIG_64BIT_TIME))
            err = __sys_recvmmsg(a0, (struct mmsghdr __user *)a1,
                         a[2], a[3],
                         (struct __kernel_timespec __user *)a[4],
                         NULL);
        else
            err = __sys_recvmmsg(a0, (struct mmsghdr __user *)a1,
                         a[2], a[3], NULL,
                         (struct old_timespec32 __user *)a[4]);
        break;
    case SYS_ACCEPT4:
        err = __sys_accept4(a0, (struct sockaddr __user *)a1,
                    (int __user *)a[2], a[3]);
        break;
    default:
        err = -EINVAL;
        break;
    }
    return err;
}

可以观察到 这两个过程分别是由如下两个函数执行的

__sys_socket
__sys_bind
我们不妨来验证这点:

技术分享图片


第一个函数被调用了

我们打上更多断点来检查(12345是区分和上一次内容的分界线):

技术分享图片

可以看到确实是

__sys_socket
__sys_bind

各一次



 

socket与系统调用深度分析

原文:https://www.cnblogs.com/Miliapus/p/12070635.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!