原创作品转载请注明出处 + 《Linux内核分析》MOOC课程http://mooc.study.163.com/course/USTC-1000029000
作者:严哲璟
以shell下执行ls命令为例介绍Linux通过fork()和execve()类函数的执行程序启动过程:
父进程为shell,命令为ls,目录为/bin/ls
当输入ls时,shell进程通过fork()创建一个新的子进程,fork()进程复制代码,以及新建堆栈等之前已经说明,子进程有机会执行的时候,在ret_from_fork()开始,返回到子进程的用户堆栈中,执行其余的子进程的代码.
在这些子进程需要执行的代码中,有execve(/bin/ls,ls,NULL),ls是列出当前路径的目录的一个可执行文件,同理如./a.out等
为加载此可执行文件到内存中执行,关键的地方在于,execve返回之后,执行的代码变成了需要加载的可执行文件的代码,下面详细说明它是如何做到的.
首先 execve()函数是系统调用,陷入内核,调用do_execve_common()函数,此函数的作用是加载需要执行的可执行文件的ELF头,因为后面需要将可执行文件的信息压入代码段以及将PC指向可执行文件的起点
1430static int do_execve_common(struct filename *filename, 1431 struct user_arg_ptr argv, 1432 struct user_arg_ptr envp) 1433{ 1434 struct linux_binprm *bprm; 1435 struct file *file; 1436 struct files_struct *displaced; 1437 int retval; 1438 1439 if (IS_ERR(filename)) 1440 return PTR_ERR(filename); 1441 1442 /* 1443 * We move the actual failure in case of RLIMIT_NPROC excess from 1444 * set*uid() to execve() because too many poorly written programs 1445 * don‘t check setuid() return code. Here we additionally recheck 1446 * whether NPROC limit is still exceeded. 1447 */ 1448 if ((current->flags & PF_NPROC_EXCEEDED) && 1449 atomic_read(¤t_user()->processes) > rlimit(RLIMIT_NPROC)) { 1450 retval = -EAGAIN; 1451 goto out_ret; 1452 } 1453 1454 /* We‘re below the limit (still or again), so we don‘t want to make 1455 * further execve() calls fail. */ 1456 current->flags &= ~PF_NPROC_EXCEEDED; 1457 1458 retval = unshare_files(&displaced); 1459 if (retval) 1460 goto out_ret; 1461 1462 retval = -ENOMEM; 1463 bprm = kzalloc(sizeof(*bprm), GFP_KERNEL); 1464 if (!bprm) 1465 goto out_files; 1466 1467 retval = prepare_bprm_creds(bprm); 1468 if (retval) 1469 goto out_free; 1470 1471 check_unsafe_exec(bprm); 1472 current->in_execve = 1; 1473 1474 file = do_open_exec(filename); 1475 retval = PTR_ERR(file); 1476 if (IS_ERR(file)) 1477 goto out_unmark; 1478 1479 sched_exec(); 1480 1481 bprm->file = file; 1482 bprm->filename = bprm->interp = filename->name; 1483 1484 retval = bprm_mm_init(bprm); 1485 if (retval) 1486 goto out_unmark; 1487 1488 bprm->argc = count(argv, MAX_ARG_STRINGS); 1489 if ((retval = bprm->argc) < 0) 1490 goto out; 1491 1492 bprm->envc = count(envp, MAX_ARG_STRINGS); 1493 if ((retval = bprm->envc) < 0) 1494 goto out; 1495 1496 retval = prepare_binprm(bprm); 1497 if (retval < 0) 1498 goto out; 1499 1500 retval = copy_strings_kernel(1, &bprm->filename, bprm); 1501 if (retval < 0) 1502 goto out; 1503 1504 bprm->exec = bprm->p; 1505 retval = copy_strings(bprm->envc, envp, bprm); 1506 if (retval < 0) 1507 goto out; 1508 1509 retval = copy_strings(bprm->argc, argv, bprm); 1510 if (retval < 0) 1511 goto out; 1512 1513 retval = exec_binprm(bprm)
时间: 2024-10-05 04:34:00