Bug 252730 - Linuxulator: The symbol link file permissions returned by stat are inconsistent with linux
Summary: Linuxulator: The symbol link file permissions returned by stat are inconsiste...
Status: New
Alias: None
Product: Base System
Classification: Unclassified
Component: kern (show other bugs)
Version: CURRENT
Hardware: Any Any
: --- Affects Only Me
Assignee: freebsd-emulation (Nobody)
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2021-01-16 04:09 UTC by shu
Modified: 2021-01-29 16:54 UTC (History)
2 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description shu 2021-01-16 04:09:20 UTC
According to the POSIX standard,symbolic links can always be read, except that the value of the file mode bits returned in the st_mode field of the stat structure is unspecified.

Linux implemented like this: stat() always returns st_mode 0777 for almost symbolic link files, but on FreeBSD returns its own real permission.
Some linux programs do obtain the symbol link file permissions in proc/sys and check whether it is equal to 777, so I think maybe linux_stat return 0777 better at this time.

BTW. 
I found two exceptions on Linux, I don’t know if there are any other exceptions.

1. lr-x------ /proc/xxx/fd/yyy
If file is open for reading, mode is S_IRUSR | S_IXUSR.
If file is open for writing, mode is S_IWUSR | S_IXUSR.
linux code 5.7-rc1:                                                                               static void tid_fd_update_inode(struct task_struct *task, struct inode *inode,   
                fmode_t f_mode)                                                  
{                                                                                
    task_dump_owner(task, 0, &inode->i_uid, &inode->i_gid);                      
                                                                                 
    if (S_ISLNK(inode->i_mode)) {                                                
        unsigned i_mode = S_IFLNK;                                               
        if (f_mode & FMODE_READ)                                                 
            i_mode |= S_IRUSR | S_IXUSR;                                         
        if (f_mode & FMODE_WRITE)                                                
            i_mode |= S_IWUSR | S_IXUSR;                                         
        inode->i_mode = i_mode;                                                  
    }                                                                            
    security_task_to_inode(task, inode);                                         
}                                                                                
In this case, we let fdescfs handle it.

2. lr-------- /proc/aaa/map_files/bbb-ccc
If file is open for reading, mode is S_IRUSR.
If file is open for writing, mode is S_IWUSR.
linux code 5.7-rc1:                                                                                     
static struct dentry *                                                               
proc_map_files_instantiate(struct dentry *dentry,                                    
               struct task_struct *task, const void *ptr)                            
{                                                                                    
    fmode_t mode = (fmode_t)(unsigned long)ptr;                                      
    struct proc_inode *ei;                                                           
    struct inode *inode;                                                             
                                                                                     
    inode = proc_pid_make_inode(dentry->d_sb, task, S_IFLNK |                        
                    ((mode & FMODE_READ ) ? S_IRUSR : 0) |                           
                    ((mode & FMODE_WRITE) ? S_IWUSR : 0));                           
    if (!inode)                                                                      
        return ERR_PTR(-ENOENT);                                                     
                                                                                     
    ei = PROC_I(inode);                                                              
    ei->op.proc_get_link = map_files_get_link;                                       
                                                                                     
    inode->i_op = &proc_map_files_link_inode_operations;                             
    inode->i_size = 64;                                                              
                                                                                     
    d_set_d_op(dentry, &tid_map_files_dentry_operations);                            
    return d_splice_alias(inode, dentry);                                            
}                                                                                    
In this case, we don't have such files and just skip.
Comment 1 shu 2021-01-16 04:20:14 UTC
https://reviews.freebsd.org/D28191