Merge tag 'apparmor-pr-2022-12-14' of git://git.kernel.org/pub/scm/linux/kernel/git...
[platform/kernel/linux-rpi.git] / security / apparmor / lsm.c
index 2511473..c6728a6 100644 (file)
@@ -228,8 +228,10 @@ static int common_perm(const char *op, const struct path *path, u32 mask,
 static int common_perm_cond(const char *op, const struct path *path, u32 mask)
 {
        struct user_namespace *mnt_userns = mnt_user_ns(path->mnt);
+       vfsuid_t vfsuid = i_uid_into_vfsuid(mnt_userns,
+                                           d_backing_inode(path->dentry));
        struct path_cond cond = {
-               i_uid_into_mnt(mnt_userns, d_backing_inode(path->dentry)),
+               vfsuid_into_kuid(vfsuid),
                d_backing_inode(path->dentry)->i_mode
        };
 
@@ -273,11 +275,13 @@ static int common_perm_rm(const char *op, const struct path *dir,
        struct inode *inode = d_backing_inode(dentry);
        struct user_namespace *mnt_userns = mnt_user_ns(dir->mnt);
        struct path_cond cond = { };
+       vfsuid_t vfsuid;
 
        if (!inode || !path_mediated_fs(dentry))
                return 0;
 
-       cond.uid = i_uid_into_mnt(mnt_userns, inode);
+       vfsuid = i_uid_into_vfsuid(mnt_userns, inode);
+       cond.uid = vfsuid_into_kuid(vfsuid);
        cond.mode = inode->i_mode;
 
        return common_perm_dir_dentry(op, dir, dentry, mask, &cond);
@@ -332,6 +336,11 @@ static int apparmor_path_truncate(const struct path *path)
        return common_perm_cond(OP_TRUNC, path, MAY_WRITE | AA_MAY_SETATTR);
 }
 
+static int apparmor_file_truncate(struct file *file)
+{
+       return apparmor_path_truncate(&file->f_path);
+}
+
 static int apparmor_path_symlink(const struct path *dir, struct dentry *dentry,
                                 const char *old_name)
 {
@@ -371,20 +380,23 @@ static int apparmor_path_rename(const struct path *old_dir, struct dentry *old_d
        label = begin_current_label_crit_section();
        if (!unconfined(label)) {
                struct user_namespace *mnt_userns = mnt_user_ns(old_dir->mnt);
+               vfsuid_t vfsuid;
                struct path old_path = { .mnt = old_dir->mnt,
                                         .dentry = old_dentry };
                struct path new_path = { .mnt = new_dir->mnt,
                                         .dentry = new_dentry };
                struct path_cond cond = {
-                       i_uid_into_mnt(mnt_userns, d_backing_inode(old_dentry)),
-                       d_backing_inode(old_dentry)->i_mode
+                       .mode = d_backing_inode(old_dentry)->i_mode
                };
+               vfsuid = i_uid_into_vfsuid(mnt_userns, d_backing_inode(old_dentry));
+               cond.uid = vfsuid_into_kuid(vfsuid);
 
                if (flags & RENAME_EXCHANGE) {
                        struct path_cond cond_exchange = {
-                               i_uid_into_mnt(mnt_userns, d_backing_inode(new_dentry)),
-                               d_backing_inode(new_dentry)->i_mode
+                               .mode = d_backing_inode(new_dentry)->i_mode,
                        };
+                       vfsuid = i_uid_into_vfsuid(mnt_userns, d_backing_inode(old_dentry));
+                       cond_exchange.uid = vfsuid_into_kuid(vfsuid);
 
                        error = aa_path_perm(OP_RENAME_SRC, label, &new_path, 0,
                                             MAY_READ | AA_MAY_GETATTR | MAY_WRITE |
@@ -450,10 +462,12 @@ static int apparmor_file_open(struct file *file)
        if (!unconfined(label)) {
                struct user_namespace *mnt_userns = file_mnt_user_ns(file);
                struct inode *inode = file_inode(file);
+               vfsuid_t vfsuid;
                struct path_cond cond = {
-                       i_uid_into_mnt(mnt_userns, inode),
-                       inode->i_mode
+                       .mode = inode->i_mode,
                };
+               vfsuid = i_uid_into_vfsuid(mnt_userns, inode);
+               cond.uid = vfsuid_into_kuid(vfsuid);
 
                error = aa_path_perm(OP_OPEN, label, &file->f_path, 0,
                                     aa_map_file_to_perms(file), &cond);
@@ -617,7 +631,7 @@ static int apparmor_sb_pivotroot(const struct path *old_path,
        return error;
 }
 
-static int apparmor_getprocattr(struct task_struct *task, char *name,
+static int apparmor_getprocattr(struct task_struct *task, const char *name,
                                char **value)
 {
        int error = -ENOENT;
@@ -1107,11 +1121,10 @@ static struct aa_label *sk_peer_label(struct sock *sk)
  * Note: for tcp only valid if using ipsec or cipso on lan
  */
 static int apparmor_socket_getpeersec_stream(struct socket *sock,
-                                            char __user *optval,
-                                            int __user *optlen,
+                                            sockptr_t optval, sockptr_t optlen,
                                             unsigned int len)
 {
-       char *name;
+       char *name = NULL;
        int slen, error = 0;
        struct aa_label *label;
        struct aa_label *peer;
@@ -1128,23 +1141,21 @@ static int apparmor_socket_getpeersec_stream(struct socket *sock,
        /* don't include terminating \0 in slen, it breaks some apps */
        if (slen < 0) {
                error = -ENOMEM;
-       } else {
-               if (slen > len) {
-                       error = -ERANGE;
-               } else if (copy_to_user(optval, name, slen)) {
-                       error = -EFAULT;
-                       goto out;
-               }
-               if (put_user(slen, optlen))
-                       error = -EFAULT;
-out:
-               kfree(name);
-
+               goto done;
+       }
+       if (slen > len) {
+               error = -ERANGE;
+               goto done_len;
        }
 
+       if (copy_to_sockptr(optval, name, slen))
+               error = -EFAULT;
+done_len:
+       if (copy_to_sockptr(optlen, &slen, sizeof(slen)))
+               error = -EFAULT;
 done:
        end_current_label_crit_section(label);
-
+       kfree(name);
        return error;
 }
 
@@ -1236,6 +1247,7 @@ static struct security_hook_list apparmor_hooks[] __lsm_ro_after_init = {
        LSM_HOOK_INIT(mmap_file, apparmor_mmap_file),
        LSM_HOOK_INIT(file_mprotect, apparmor_file_mprotect),
        LSM_HOOK_INIT(file_lock, apparmor_file_lock),
+       LSM_HOOK_INIT(file_truncate, apparmor_file_truncate),
 
        LSM_HOOK_INIT(getprocattr, apparmor_getprocattr),
        LSM_HOOK_INIT(setprocattr, apparmor_setprocattr),