summaryrefslogtreecommitdiffstats
path: root/fs/btrfs/acl.c
diff options
context:
space:
mode:
authorEduard Zingerman <eddyz87@gmail.com>2026-09-04 17:05:56 -0700
committerAlexei Starovoitov <ast@kernel.org>2026-09-04 18:17:30 -0700
commit506ada89629ec7059b96ecfb0dc7d33ece0103ca (patch)
tree0b07297409b68d2333fb4f0eae7f3b072eb68d4c /fs/btrfs/acl.c
downloadlinux-stable-506ada89629ec7059b96ecfb0dc7d33ece0103ca.tar.gz
linux-stable-506ada89629ec7059b96ecfb0dc7d33ece0103ca.zip
bpf: mark a NULL kfunc argument precisegrafted
check_kfunc_arg() allows bpf_register_is_null() for nullable arguments w/o marking the underlying scalar register precise. Hence a checkpoint created on such a path would prune against arbitrary scalar value. Fixes: 3bda08b63670 ("bpf: Allow NULL buffers in bpf_dynptr_slice(_rw)") Signed-off-by: Eduard Zingerman <eddyz87@gmail.com> Link: https://lore.kernel.org/r/20260904-register-is-null-precise-fixes-v1-5-0f5a360ff15d@gmail.com Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Diffstat (limited to 'fs/btrfs/acl.c')
-rw-r--r--fs/btrfs/acl.c120
1 files changed, 120 insertions, 0 deletions
diff --git a/fs/btrfs/acl.c b/fs/btrfs/acl.c
new file mode 100644
index 000000000..e55b686fe
--- /dev/null
+++ b/fs/btrfs/acl.c
@@ -0,0 +1,120 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2007 Red Hat. All rights reserved.
+ */
+
+#include <linux/fs.h>
+#include <linux/string.h>
+#include <linux/xattr.h>
+#include <linux/posix_acl_xattr.h>
+#include <linux/posix_acl.h>
+#include <linux/sched.h>
+#include <linux/sched/mm.h>
+#include <linux/slab.h>
+#include "ctree.h"
+#include "xattr.h"
+#include "acl.h"
+#include "misc.h"
+
+struct posix_acl *btrfs_get_acl(struct inode *inode, int type, bool rcu)
+{
+ int size;
+ const char *name;
+ char AUTO_KFREE(value);
+ struct posix_acl *acl;
+
+ if (rcu)
+ return ERR_PTR(-ECHILD);
+
+ switch (type) {
+ case ACL_TYPE_ACCESS:
+ name = XATTR_NAME_POSIX_ACL_ACCESS;
+ break;
+ case ACL_TYPE_DEFAULT:
+ name = XATTR_NAME_POSIX_ACL_DEFAULT;
+ break;
+ default:
+ return ERR_PTR(-EINVAL);
+ }
+
+ size = btrfs_getxattr(inode, name, NULL, 0);
+ if (size > 0) {
+ value = kzalloc(size, GFP_KERNEL);
+ if (!value)
+ return ERR_PTR(-ENOMEM);
+ size = btrfs_getxattr(inode, name, value, size);
+ }
+ if (size > 0)
+ acl = posix_acl_from_xattr(&init_user_ns, value, size);
+ else if (size == -ENODATA || size == 0)
+ acl = NULL;
+ else
+ acl = ERR_PTR(size);
+
+ return acl;
+}
+
+int __btrfs_set_acl(struct btrfs_trans_handle *trans, struct inode *inode,
+ struct posix_acl *acl, int type)
+{
+ int ret;
+ size_t size = 0;
+ const char *name;
+ char AUTO_KFREE(value);
+
+ switch (type) {
+ case ACL_TYPE_ACCESS:
+ name = XATTR_NAME_POSIX_ACL_ACCESS;
+ break;
+ case ACL_TYPE_DEFAULT:
+ if (!S_ISDIR(inode->i_mode))
+ return acl ? -EINVAL : 0;
+ name = XATTR_NAME_POSIX_ACL_DEFAULT;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (acl) {
+ unsigned int nofs_flag;
+
+ /*
+ * We're holding a transaction handle, so use a NOFS memory
+ * allocation context to avoid deadlock if reclaim happens.
+ */
+ nofs_flag = memalloc_nofs_save();
+ value = posix_acl_to_xattr(&init_user_ns, acl, &size, GFP_KERNEL);
+ memalloc_nofs_restore(nofs_flag);
+ if (!value)
+ return -ENOMEM;
+ }
+
+ if (trans)
+ ret = btrfs_setxattr(trans, inode, name, value, size, 0);
+ else
+ ret = btrfs_setxattr_trans(inode, name, value, size, 0);
+ if (ret < 0)
+ return ret;
+
+ set_cached_acl(inode, type, acl);
+ return 0;
+}
+
+int btrfs_set_acl(struct mnt_idmap *idmap, struct dentry *dentry,
+ struct posix_acl *acl, int type)
+{
+ int ret;
+ struct inode *inode = d_inode(dentry);
+ umode_t old_mode = inode->i_mode;
+
+ if (type == ACL_TYPE_ACCESS && acl) {
+ ret = posix_acl_update_mode(idmap, inode,
+ &inode->i_mode, &acl);
+ if (ret)
+ return ret;
+ }
+ ret = __btrfs_set_acl(NULL, inode, acl, type);
+ if (ret)
+ inode->i_mode = old_mode;
+ return ret;
+}