In the Linux kernel source scenario analysis-from the pathname to the target node, the Path_walk code in the article, err = permission (Inode, may_exec) whether the current process can access the node, the code is as follows:
int permission (struct inode * Inode,int mask) {if (inode->i_op && inode->i_op->permission) {int retval; Lock_kernel (); retval = Inode->i_op->permission (inode, mask); Unlock_kernel (); return retval;} Return Vfs_permission (Inode, mask);}
In Ext2_read_inode, I_op can be set to Ext2_file_inode_operations,ext2_dir_inode_operations,ext2_fast_symlink_inode_ Operations,page_symlink_inode_operations, there are no permission pointers. So execute the Vfs_permission code as follows:
int vfs_permission (struct inode * Inode,int mask) {int mode = INODE->I_MODE;IF (Mask & s_iwoth) && is_rdonl Y (inode) && (s_isreg (mode) | | S_isdir (mode) | | S_islnk (mode)) Return-erofs; If the required write file is a read-only system, and is a regular file, directory, or link, return-erofs, indicating that the IF ((Mask & S_iwoth) && is_immutable (inode) is not accessible//nobody Gets write access to an immutable filereturn-eacces; if (Current->fsuid = = inode->i_uid)//If the fsuid of the current process and the i_uid of the inode structure are equal, then the S_IRUSR, S_IWUSR, and s_ixusr bits in mode should be compared >>= 6;else if (in_group_p (Inode->i_gid))//If the fsgid of the current process and the i_gid of the inode structure are equal, then you should compare mode S_irgrp, S_IWGRP, S_ Ixgrp bit mode >>= 3;if (((Mode & mask & s_irwxo) = = mask) | | capable (cap_dac_override))//mask equivalent to the requirement, mode is the existing current The user can access the permissions, and returns 0 if they are equal. If not equal, if the current process is authorized to allow its cap_dac_override, it can override the file system's access control mechanism on the DAC. Return 0;/* Read and search access */if (mask = = S_iroth) | | (S_isdir (inode->i_mode) &&! (Mask & ~ (S_iroth | S_ixoth))) if (capable (cap_dac_read_search)) return 0;return-eacces;}
where Mask is:
#define MAY_EXEC 1#define may_write 2#define may_read 4
Inode->i_mode is:
For access to three different types of users:
#define S_IRWXU 00700#define s_irusr 00400#define s_iwusr 00200#define s_ixusr 00100#define S_IRWXG 00070#define S_IRGRP 0 0040#define s_iwgrp 00020#define s_ixgrp 00010#define s_irwxo 00007#define s_iroth 00004#define S_IWOTH 00002#define S_IX OTH 00001
It's a good idea to refer to this picture.
There are also three flag bits, which are a status of one bit:
#define S_ISUID 0004000#define s_isgid 0002000#define s_isvtx 0001000
Now that 16 bits are left with only 4 bits, representing the file type, it is not enough to assign a flag bit to each file type, so the 4 bits representing the type of the file are encoded.
#define S_IFMT 00170000#define s_ifsock 0140000#define s_iflnk 0120000#define s_ifreg 0100000#define S_IFBLK 0060000#define s_ifdir 0040000#define s_ifchr 0020000#define s_ififo 0010000
Capable, the code is as follows:
static inline int capable (int cap) {#if 1/* OK now */if (cap_raised (current->cap_effective, CAP)) #elseif (Cap_is_fs_cap (CAP)? Current->fsuid = = 0:current->euid = 0) #endif {current->flags |= Pf_superpriv;return 1;} return 0;}
#define CAP_RAISED (c, Flag) (cap_t (c) & Cap_to_mask (flag))
#define CAP_T (x) (x)
#define CAP_TO_MASK (x) (1 << (x))
The current->cap_effective is initially set in SYS_EXECVE->DO_EXECVE->PREPARE_BINPRM.
int PREPARE_BINPRM (struct LINUX_BINPRM *bprm) {int mode;struct inode * inode = bprm->file->f_dentry->d_inode; mode = inode->i_mode;/* Huh? We had already checked for may_exec, WTF does we check this? */IF (! ( Mode & 0111))/* With at least _one_ execute bit set */return-eacces;if (bprm->file->f_op = = NULL) return-eacces ; bprm->e_uid = Current->euid;bprm->e_gid = Current->egid;if (!is_nosuid (inode)) {/* set-uid? */if (Mode & s_isuid) Bprm->e_uid = inode->i_uid;/* Set-gid? *//* * If Setgid is set and no group execute bit then this * was a candidate for mandatory locking, not a setgid * executab Le. */if (Mode & (S_isgid | S_IXGRP) = = (S_isgid | S_IXGRP)) Bprm->e_gid = Inode->i_gid;} /* We have the VFS support for capabilities yet */cap_clear (bprm->cap_inheritable); Cap_clear (BPRM->CAP_ permitted); Cap_clear (bprm->cap_effective);/* To support inheritance of root-permissions and Suid-root * EXECU Tables under Compatibility Mode,We raise all three * capability sets for the file. * If only the real uid was 0, we only raise the inheritable * and permitted sets of the executable file . */if (!issecure (secure_noroot)) {if (Bprm->e_uid = = 0 | | current->uid = = 0) {cap_set_full (bprm->cap_inheritable ); Cap_set_full (bprm->cap_permitted);} if (Bprm->e_uid = = 0) cap_set_full (bprm->cap_effective);//}memset set here (bprm->buf,0,binprm_buf_size); Return Kernel_read (bprm->file,0,bprm->buf,binprm_buf_size);}
Linux kernel Source-code scenario analysis-access rights and file security