18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci#include "reiserfs.h"
38c2ecf20Sopenharmony_ci#include <linux/errno.h>
48c2ecf20Sopenharmony_ci#include <linux/fs.h>
58c2ecf20Sopenharmony_ci#include <linux/pagemap.h>
68c2ecf20Sopenharmony_ci#include <linux/xattr.h>
78c2ecf20Sopenharmony_ci#include <linux/slab.h>
88c2ecf20Sopenharmony_ci#include "xattr.h"
98c2ecf20Sopenharmony_ci#include <linux/security.h>
108c2ecf20Sopenharmony_ci#include <linux/uaccess.h>
118c2ecf20Sopenharmony_ci
128c2ecf20Sopenharmony_cistatic int
138c2ecf20Sopenharmony_cisecurity_get(const struct xattr_handler *handler, struct dentry *unused,
148c2ecf20Sopenharmony_ci	     struct inode *inode, const char *name, void *buffer, size_t size)
158c2ecf20Sopenharmony_ci{
168c2ecf20Sopenharmony_ci	if (IS_PRIVATE(inode))
178c2ecf20Sopenharmony_ci		return -EPERM;
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ci	return reiserfs_xattr_get(inode, xattr_full_name(handler, name),
208c2ecf20Sopenharmony_ci				  buffer, size);
218c2ecf20Sopenharmony_ci}
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_cistatic int
248c2ecf20Sopenharmony_cisecurity_set(const struct xattr_handler *handler, struct dentry *unused,
258c2ecf20Sopenharmony_ci	     struct inode *inode, const char *name, const void *buffer,
268c2ecf20Sopenharmony_ci	     size_t size, int flags)
278c2ecf20Sopenharmony_ci{
288c2ecf20Sopenharmony_ci	if (IS_PRIVATE(inode))
298c2ecf20Sopenharmony_ci		return -EPERM;
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_ci	return reiserfs_xattr_set(inode,
328c2ecf20Sopenharmony_ci				  xattr_full_name(handler, name),
338c2ecf20Sopenharmony_ci				  buffer, size, flags);
348c2ecf20Sopenharmony_ci}
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_cistatic bool security_list(struct dentry *dentry)
378c2ecf20Sopenharmony_ci{
388c2ecf20Sopenharmony_ci	return !IS_PRIVATE(d_inode(dentry));
398c2ecf20Sopenharmony_ci}
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_ci/* Initializes the security context for a new inode and returns the number
428c2ecf20Sopenharmony_ci * of blocks needed for the transaction. If successful, reiserfs_security
438c2ecf20Sopenharmony_ci * must be released using reiserfs_security_free when the caller is done. */
448c2ecf20Sopenharmony_ciint reiserfs_security_init(struct inode *dir, struct inode *inode,
458c2ecf20Sopenharmony_ci			   const struct qstr *qstr,
468c2ecf20Sopenharmony_ci			   struct reiserfs_security_handle *sec)
478c2ecf20Sopenharmony_ci{
488c2ecf20Sopenharmony_ci	int blocks = 0;
498c2ecf20Sopenharmony_ci	int error;
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_ci	sec->name = NULL;
528c2ecf20Sopenharmony_ci	sec->value = NULL;
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_ci	/* Don't add selinux attributes on xattrs - they'll never get used */
558c2ecf20Sopenharmony_ci	if (IS_PRIVATE(dir))
568c2ecf20Sopenharmony_ci		return 0;
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_ci	error = security_old_inode_init_security(inode, dir, qstr, &sec->name,
598c2ecf20Sopenharmony_ci						 &sec->value, &sec->length);
608c2ecf20Sopenharmony_ci	if (error) {
618c2ecf20Sopenharmony_ci		if (error == -EOPNOTSUPP)
628c2ecf20Sopenharmony_ci			error = 0;
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_ci		sec->name = NULL;
658c2ecf20Sopenharmony_ci		sec->value = NULL;
668c2ecf20Sopenharmony_ci		sec->length = 0;
678c2ecf20Sopenharmony_ci		return error;
688c2ecf20Sopenharmony_ci	}
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_ci	if (sec->length && reiserfs_xattrs_initialized(inode->i_sb)) {
718c2ecf20Sopenharmony_ci		blocks = reiserfs_xattr_jcreate_nblocks(inode) +
728c2ecf20Sopenharmony_ci			 reiserfs_xattr_nblocks(inode, sec->length);
738c2ecf20Sopenharmony_ci		/* We don't want to count the directories twice if we have
748c2ecf20Sopenharmony_ci		 * a default ACL. */
758c2ecf20Sopenharmony_ci		REISERFS_I(inode)->i_flags |= i_has_xattr_dir;
768c2ecf20Sopenharmony_ci	}
778c2ecf20Sopenharmony_ci	return blocks;
788c2ecf20Sopenharmony_ci}
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_ciint reiserfs_security_write(struct reiserfs_transaction_handle *th,
818c2ecf20Sopenharmony_ci			    struct inode *inode,
828c2ecf20Sopenharmony_ci			    struct reiserfs_security_handle *sec)
838c2ecf20Sopenharmony_ci{
848c2ecf20Sopenharmony_ci	char xattr_name[XATTR_NAME_MAX + 1] = XATTR_SECURITY_PREFIX;
858c2ecf20Sopenharmony_ci	int error;
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_ci	if (XATTR_SECURITY_PREFIX_LEN + strlen(sec->name) > XATTR_NAME_MAX)
888c2ecf20Sopenharmony_ci		return -EINVAL;
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_ci	strlcat(xattr_name, sec->name, sizeof(xattr_name));
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_ci	error = reiserfs_xattr_set_handle(th, inode, xattr_name, sec->value,
938c2ecf20Sopenharmony_ci					  sec->length, XATTR_CREATE);
948c2ecf20Sopenharmony_ci	if (error == -ENODATA || error == -EOPNOTSUPP)
958c2ecf20Sopenharmony_ci		error = 0;
968c2ecf20Sopenharmony_ci
978c2ecf20Sopenharmony_ci	return error;
988c2ecf20Sopenharmony_ci}
998c2ecf20Sopenharmony_ci
1008c2ecf20Sopenharmony_civoid reiserfs_security_free(struct reiserfs_security_handle *sec)
1018c2ecf20Sopenharmony_ci{
1028c2ecf20Sopenharmony_ci	kfree(sec->value);
1038c2ecf20Sopenharmony_ci	sec->name = NULL;
1048c2ecf20Sopenharmony_ci	sec->value = NULL;
1058c2ecf20Sopenharmony_ci}
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_ciconst struct xattr_handler reiserfs_xattr_security_handler = {
1088c2ecf20Sopenharmony_ci	.prefix = XATTR_SECURITY_PREFIX,
1098c2ecf20Sopenharmony_ci	.get = security_get,
1108c2ecf20Sopenharmony_ci	.set = security_set,
1118c2ecf20Sopenharmony_ci	.list = security_list,
1128c2ecf20Sopenharmony_ci};
113