4. Creation and Execution of Process 2 165
4.3 Load the Shell Program
4.3.2 Detect the Shell File
4.3.2.1 Detect the Attribute of the i node
The do_execve() function calls the namei() function to get the i node of the shell first, the procedure of get inode is similar with the process of get inode in Section 4.1.1, and the system checks the attribute of the i node to determine whether the shell program can be loaded. The code is as follows:
int do_execve(unsigned long * eip,long tmp,char * filename, char ** argv, char ** envp)
{
struct m_inode * inode;
struct buffer_head * bh;
struct exec ex;
unsigned long page[MAX_ARG_PAGES];
int i,argc,envc;
int e_uid, e_gid;
int retval;
int sh_bang = 0;
unsigned long p=PAGE_SIZE*MAX_ARG_PAGES-4;
ROM BIOS and VGA
f_mode f_flags f_count f_inode f_pos Kernel
Enable interrupt
0x00000 0x9FFFF 0xFFFFF 0x3FFFFF 0x5FFFFF 0xFFFFFF
Kernel code area Kernel data area
i node_table[32] file_table[64]
The i node pointing to /etc/rc Process status
Process 0 Process 1 Process 2
Interruptible Interruptible Ready
Current process
Figure 4.19 Open/etc/rc.
The procedure on how to get the i node is shown in Figure 4.20.
The procedure on how to detect the i node is shown in Figure 4.21.
By detecting the attribute of the i node of the shell file, we know that process 2 can execute the program in this context.
4.3.2.2 Test File Header’s Attributes
Through the information of the device id and block id provided by the i node, the system will load the file header to the buffer and get its information. The code is as follows:
if ((0xffff & eip[1]) !=0x000f //checks whether the kernel calls //do_execve() by checking privilege level
panic(“execve called from supervisor mode”);//if yes, the //kernel will crash, obviously, it is not true in this case.
for (i=0 ; i<MAX_ARG_PAGES ; i++)
page[i]=0; //clear the page pointer management table, which //used to parameter and environmental variables
if (!(inode = namei(filename)))//get the inode of shell program file return -ENOENT;
argc = count(argv);//count the parameters
envc = count(envp);//count the environment variables restart_interp:
if (!S_ISREG(inode->i_mode)) { /* must be regular file */
retval = -EACCES;
goto exec_error2;
}
i = inode->i_mode;//check process 2 through checking uid and gid in inode e_uid = (i & S_ISUID) ? inode->i_uid : current->euid;//whether has the
//authority to execute shell program e_gid = (i & S_ISGID) ? inode->i_gid : current->egid;
if (current->euid == inode->i_uid)
i >>= 6; //adjust the permission bits in //inode by analyzing the owner //relationship between file and //current process
else if (current->egid == inode->i_gid) i >>= 3;
if (!(i & 1) && //exit the loading work, if user has no //permission to execute shell program
!((inode->i_mode & 0111) && suser())) { retval = -ENOEXEC;
goto exec_error2;
} }
……
int do_execve(unsigned long * eip,long tmp,char * filename, char ** argv, char ** envp)/*system_call.s*/
{
……
if (!(i & 1) &&//If user don’t have permission to perform the //program,the shell will exit the loading work
!((inode->i_mode & 0111) && suser())) { retval = -ENOEXEC;
goto exec_error2;
}
if (!(bh = bread(inode->i_dev,inode->i_zone[0]))) {
//Through the i_nodes to make sure the device id and block //id(i_zone[0]) of shell file and get the file header
retval = -EACCES;
goto exec_error2;
}
ex = *((struct exec *) bh->b_data); //Get the information of file header //
from buffer block
if ((bh->b_data[0] == ‘#’) && (bh->b_data[1] == ‘!’) && (!sh_bang)) {
……
brelse(bh);
if (N_MAGIC(ex) != ZMAGIC || ex.a_trsize || ex.a_drsize ||
ex.a_text+ex.a_data+ex.a_bss>0x3000000 ||
inode->i_size < ex.a_text+ex.a_data+ex.a_syms+N_TXTOFF(ex)) { retval = -ENOEXEC;
goto exec_error2;
}
if (N_TXTOFF(ex) != BLOCK_SIZE) {
printk(“%s: N_TXTOFF != BLOCK_SIZE. See a.out.h.”, filename);
retval = -ENOEXEC;
goto exec_error2;
}
if (!sh_bang) {
p = copy_strings(envc,envp,page,p,0);
p = copy_strings(argc,argv,page,p,0);
if (!p) {
retval = -ENOMEM;
goto exec_error2;
} }
}
……
Kernel
Enable interrupt
0x00000 0x9FFFF 0xFFFFF 0x3FFFFF 0x5FFFFF 0xFFFFFF
Kernel code area Kernel data area
i node_table[32]
Buffer block
Get i node Process status
Process 0 Process 1 Process 2
Interruptible Interruptible Ready
Current process
ROM BIOS and VGA
Figure 4.20 Get the i node of shell.
The procedure of obtaining the file header is shown in Figures 4.22 and 4.23.
The system will check the information of the file header to confirm the content of the shell file and judge whether it is fit for the rule of loading. The code is as follows:
int do_execve(unsigned long * eip,long tmp,char * filename, char ** argv, char ** envp)/*system_call.s*/
{
……
if (!(i & 1) &&//If user don’t have permission to perform the //program,the shell will exit the loading work
!((inode->i_mode & 0111) && suser())) { retval = -ENOEXEC;
goto exec_error2;
}
if (!(bh = bread(inode->i_dev,inode->i_zone[0]))) {
//Through the i_nodes to make sure the device id and block //id(i_zone[0]) of shell file and get the file header
retval = -EACCES;
goto exec_error2;
}
ex = *((struct exec *) bh->b_data);//Get the information of file header //from buffer block
if ((bh->b_data[0] == ‘#’) && (bh->b_data[1] = = ‘!’) && (!sh_bang)) { //Test file header, learned that shell file is not script file,so the //contents of if don’t execute
……
brelse(bh);
Kernel
Enable interrupt
0x00000 0x9FFFF 0xFFFFF 0x3FFFFF 0x5FFFFF 0xFFFFFF
Kernel code area Kernel data area
i node_table[32]
Process status
Process 0 Process 1 Process 2
Interruptible Interruptible Ready
Current process
ROM BIOS and VGA
Figure 4.21 Detect the i node of shell.
Figure 4.23 shows an incidence of testing the file header.
After checking the header attributes of the shell file, we find that the program in the shell file is ready to run.
if (N_MAGIC(ex) ! = ZMAGIC || ex.a_trsize || ex.a_drsize ||
ex.a_text+ex.a_data+ex.a_bss>0x3000000 ||
inode->i_size < ex.a_text+ex.a_data+ex.a_syms+N_TXTOFF(ex)) { //Test the information of file header to make sure the content of shell //file and judge it whether fit for the rule of loading
retval = -ENOEXEC;
goto exec_error2;
}
if (N_TXTOFF(ex) ! = BLOCK_SIZE) {
//If the file header size is not equal to 1024, the program might not //be executed
printk(“%s: N_TXTOFF ! = BLOCK_SIZE. See a.out.h.”, filename);
retval = -ENOEXEC;
goto exec_error2;
}
if (!sh_bang) {
p = copy_strings(envc,envp,page,p,0);
p = copy_strings(argc,argv,page,p,0);
if (!p) {
retval = -ENOMEM;
goto exec_error2;
} } }
……
ROM BIOS
and VGA Enable
interrupt
0x00000 0x9FFFF 0xFFFFF 0x3FFFFF 0x5FFFFF 0xFFFFFF
Read the shell file header into buffer Kernel
Process status
Process 0 Process 1 Process 2
Interruptible Interruptible Ready
Current process
\0\0\0
Figure 4.22 Read the shell file header into the buffer.