Commit c76ff350 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'lsm-pr-20221212' of git://git.kernel.org/pub/scm/linux/kernel/git/pcmoore/lsm

Pull lsm updates from Paul Moore:

 - Improve the error handling in the device cgroup such that memory
   allocation failures when updating the access policy do not
   potentially alter the policy.

 - Some minor fixes to reiserfs to ensure that it properly releases
   LSM-related xattr values.

 - Update the security_socket_getpeersec_stream() LSM hook to take
   sockptr_t values.

   Previously the net/BPF folks updated the getsockopt code in the
   network stack to leverage the sockptr_t type to make it easier to
   pass both kernel and __user pointers, but unfortunately when they did
   so they didn't convert the LSM hook.

   While there was/is no immediate risk by not converting the LSM hook,
   it seems like this is a mistake waiting to happen so this patch
   proactively does the LSM hook conversion.

 - Convert vfs_getxattr_alloc() to return an int instead of a ssize_t
   and cleanup the callers. Internally the function was never going to
   return anything larger than an int and the callers were doing some
   very odd things casting the return value; this patch fixes all that
   and helps bring a bit of sanity to vfs_getxattr_alloc() and its
   callers.

 - More verbose, and helpful, LSM debug output when the system is booted
   with "lsm.debug" on the command line. There are examples in the
   commit description, but the quick summary is that this patch provides
   better information about which LSMs are enabled and the ordering in
   which they are processed.

 - General comment and kernel-doc fixes and cleanups.

* tag 'lsm-pr-20221212' of git://git.kernel.org/pub/scm/linux/kernel/git/pcmoore/lsm:
  lsm: Fix description of fs_context_parse_param
  lsm: Add/fix return values in lsm_hooks.h and fix formatting
  lsm: Clarify documentation of vm_enough_memory hook
  reiserfs: Add missing calls to reiserfs_security_free()
  lsm,fs: fix vfs_getxattr_alloc() return type and caller error paths
  device_cgroup: Roll back to original exceptions after copy failure
  LSM: Better reporting of actual LSMs at boot
  lsm: make security_socket_getpeersec_stream() sockptr_t safe
  audit: Fix some kernel-doc warnings
  lsm: remove obsoleted comments for security hooks
  fs: edit a comment made in bad taste
parents 57888f7b 577cc143
......@@ -696,6 +696,7 @@ static int reiserfs_create(struct user_namespace *mnt_userns, struct inode *dir,
out_failed:
reiserfs_write_unlock(dir->i_sb);
reiserfs_security_free(&security);
return retval;
}
......@@ -779,6 +780,7 @@ static int reiserfs_mknod(struct user_namespace *mnt_userns, struct inode *dir,
out_failed:
reiserfs_write_unlock(dir->i_sb);
reiserfs_security_free(&security);
return retval;
}
......@@ -878,6 +880,7 @@ static int reiserfs_mkdir(struct user_namespace *mnt_userns, struct inode *dir,
retval = journal_end(&th);
out_failed:
reiserfs_write_unlock(dir->i_sb);
reiserfs_security_free(&security);
return retval;
}
......@@ -1194,6 +1197,7 @@ static int reiserfs_symlink(struct user_namespace *mnt_userns,
retval = journal_end(&th);
out_failed:
reiserfs_write_unlock(parent_dir->i_sb);
reiserfs_security_free(&security);
return retval;
}
......
......@@ -50,6 +50,7 @@ int reiserfs_security_init(struct inode *dir, struct inode *inode,
int error;
sec->name = NULL;
sec->value = NULL;
/* Don't add selinux attributes on xattrs - they'll never get used */
if (IS_PRIVATE(dir))
......@@ -95,7 +96,6 @@ int reiserfs_security_write(struct reiserfs_transaction_handle *th,
void reiserfs_security_free(struct reiserfs_security_handle *sec)
{
kfree(sec->name);
kfree(sec->value);
sec->name = NULL;
sec->value = NULL;
......
......@@ -368,11 +368,12 @@ xattr_getsecurity(struct user_namespace *mnt_userns, struct inode *inode,
* vfs_getxattr_alloc - allocate memory, if necessary, before calling getxattr
*
* Allocate memory, if not already allocated, or re-allocate correct size,
* before retrieving the extended attribute.
* before retrieving the extended attribute. The xattr value buffer should
* always be freed by the caller, even on error.
*
* Returns the result of alloc, if failed, or the getxattr operation.
*/
ssize_t
int
vfs_getxattr_alloc(struct user_namespace *mnt_userns, struct dentry *dentry,
const char *name, char **xattr_value, size_t xattr_size,
gfp_t flags)
......
......@@ -99,7 +99,7 @@ struct fs_context {
const struct cred *cred; /* The mounter's credentials */
struct p_log log; /* Logging buffer */
const char *source; /* The source name (eg. dev path) */
void *security; /* Linux S&M options */
void *security; /* LSM options */
void *s_fs_info; /* Proposed s_fs_info */
unsigned int sb_flags; /* Proposed superblock flags (SB_*) */
unsigned int sb_flags_mask; /* Superblock flags that were changed */
......
......@@ -309,7 +309,7 @@ LSM_HOOK(int, 0, socket_setsockopt, struct socket *sock, int level, int optname)
LSM_HOOK(int, 0, socket_shutdown, struct socket *sock, int how)
LSM_HOOK(int, 0, socket_sock_rcv_skb, struct sock *sk, struct sk_buff *skb)
LSM_HOOK(int, 0, socket_getpeersec_stream, struct socket *sock,
char __user *optval, int __user *optlen, unsigned len)
sockptr_t optval, sockptr_t optlen, unsigned int len)
LSM_HOOK(int, 0, socket_getpeersec_dgram, struct socket *sock,
struct sk_buff *skb, u32 *secid)
LSM_HOOK(int, 0, sk_alloc_security, struct sock *sk, int family, gfp_t priority)
......
This diff is collapsed.
......@@ -31,6 +31,7 @@
#include <linux/err.h>
#include <linux/string.h>
#include <linux/mm.h>
#include <linux/sockptr.h>
struct linux_binprm;
struct cred;
......@@ -1446,8 +1447,8 @@ int security_socket_getsockopt(struct socket *sock, int level, int optname);
int security_socket_setsockopt(struct socket *sock, int level, int optname);
int security_socket_shutdown(struct socket *sock, int how);
int security_sock_rcv_skb(struct sock *sk, struct sk_buff *skb);
int security_socket_getpeersec_stream(struct socket *sock, char __user *optval,
int __user *optlen, unsigned len);
int security_socket_getpeersec_stream(struct socket *sock, sockptr_t optval,
sockptr_t optlen, unsigned int len);
int security_socket_getpeersec_dgram(struct socket *sock, struct sk_buff *skb, u32 *secid);
int security_sk_alloc(struct sock *sk, int family, gfp_t priority);
void security_sk_free(struct sock *sk);
......@@ -1583,8 +1584,10 @@ static inline int security_sock_rcv_skb(struct sock *sk,
return 0;
}
static inline int security_socket_getpeersec_stream(struct socket *sock, char __user *optval,
int __user *optlen, unsigned len)
static inline int security_socket_getpeersec_stream(struct socket *sock,
sockptr_t optval,
sockptr_t optlen,
unsigned int len)
{
return -ENOPROTOOPT;
}
......
......@@ -74,7 +74,7 @@ int __vfs_removexattr_locked(struct user_namespace *, struct dentry *,
int vfs_removexattr(struct user_namespace *, struct dentry *, const char *);
ssize_t generic_listxattr(struct dentry *dentry, char *buffer, size_t buffer_size);
ssize_t vfs_getxattr_alloc(struct user_namespace *mnt_userns,
int vfs_getxattr_alloc(struct user_namespace *mnt_userns,
struct dentry *dentry, const char *name,
char **xattr_value, size_t size, gfp_t flags);
......
......@@ -1793,7 +1793,8 @@ int sk_getsockopt(struct sock *sk, int level, int optname,
break;
case SO_PEERSEC:
return security_socket_getpeersec_stream(sock, optval.user, optlen.user, len);
return security_socket_getpeersec_stream(sock,
optval, optlen, len);
case SO_MARK:
v.val = sk->sk_mark;
......
......@@ -311,10 +311,9 @@ static int aa_xattrs_match(const struct linux_binprm *bprm,
struct aa_profile *profile, unsigned int state)
{
int i;
ssize_t size;
struct dentry *d;
char *value = NULL;
int value_size = 0, ret = profile->xattr_count;
int size, value_size = 0, ret = profile->xattr_count;
if (!bprm || !profile->xattr_count)
return 0;
......
......@@ -1117,11 +1117,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;
......@@ -1138,23 +1137,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 {
goto done;
}
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_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;
}
......
......@@ -352,14 +352,14 @@ static __u32 sansflags(__u32 m)
return m & ~VFS_CAP_FLAGS_EFFECTIVE;
}
static bool is_v2header(size_t size, const struct vfs_cap_data *cap)
static bool is_v2header(int size, const struct vfs_cap_data *cap)
{
if (size != XATTR_CAPS_SZ_2)
return false;
return sansflags(le32_to_cpu(cap->magic_etc)) == VFS_CAP_REVISION_2;
}
static bool is_v3header(size_t size, const struct vfs_cap_data *cap)
static bool is_v3header(int size, const struct vfs_cap_data *cap)
{
if (size != XATTR_CAPS_SZ_3)
return false;
......@@ -381,7 +381,7 @@ int cap_inode_getsecurity(struct user_namespace *mnt_userns,
struct inode *inode, const char *name, void **buffer,
bool alloc)
{
int size, ret;
int size;
kuid_t kroot;
vfsuid_t vfsroot;
u32 nsmagic, magic;
......@@ -398,22 +398,18 @@ int cap_inode_getsecurity(struct user_namespace *mnt_userns,
dentry = d_find_any_alias(inode);
if (!dentry)
return -EINVAL;
size = sizeof(struct vfs_ns_cap_data);
ret = (int)vfs_getxattr_alloc(mnt_userns, dentry, XATTR_NAME_CAPS,
&tmpbuf, size, GFP_NOFS);
size = vfs_getxattr_alloc(mnt_userns, dentry, XATTR_NAME_CAPS, &tmpbuf,
sizeof(struct vfs_ns_cap_data), GFP_NOFS);
dput(dentry);
if (ret < 0 || !tmpbuf) {
size = ret;
/* gcc11 complains if we don't check for !tmpbuf */
if (size < 0 || !tmpbuf)
goto out_free;
}
fs_ns = inode->i_sb->s_user_ns;
cap = (struct vfs_cap_data *) tmpbuf;
if (is_v2header((size_t) ret, cap)) {
if (is_v2header(size, cap)) {
root = 0;
} else if (is_v3header((size_t) ret, cap)) {
} else if (is_v3header(size, cap)) {
nscap = (struct vfs_ns_cap_data *) tmpbuf;
root = le32_to_cpu(nscap->rootid);
} else {
......
......@@ -82,6 +82,17 @@ static int dev_exceptions_copy(struct list_head *dest, struct list_head *orig)
return -ENOMEM;
}
static void dev_exceptions_move(struct list_head *dest, struct list_head *orig)
{
struct dev_exception_item *ex, *tmp;
lockdep_assert_held(&devcgroup_mutex);
list_for_each_entry_safe(ex, tmp, orig, list) {
list_move_tail(&ex->list, dest);
}
}
/*
* called under devcgroup_mutex
*/
......@@ -604,11 +615,13 @@ static int devcgroup_update_access(struct dev_cgroup *devcgroup,
int count, rc = 0;
struct dev_exception_item ex;
struct dev_cgroup *parent = css_to_devcgroup(devcgroup->css.parent);
struct dev_cgroup tmp_devcgrp;
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
memset(&ex, 0, sizeof(ex));
memset(&tmp_devcgrp, 0, sizeof(tmp_devcgrp));
b = buffer;
switch (*b) {
......@@ -620,15 +633,27 @@ static int devcgroup_update_access(struct dev_cgroup *devcgroup,
if (!may_allow_all(parent))
return -EPERM;
dev_exception_clean(devcgroup);
if (!parent) {
devcgroup->behavior = DEVCG_DEFAULT_ALLOW;
if (!parent)
dev_exception_clean(devcgroup);
break;
}
INIT_LIST_HEAD(&tmp_devcgrp.exceptions);
rc = dev_exceptions_copy(&tmp_devcgrp.exceptions,
&devcgroup->exceptions);
if (rc)
return rc;
dev_exception_clean(devcgroup);
rc = dev_exceptions_copy(&devcgroup->exceptions,
&parent->exceptions);
if (rc)
if (rc) {
dev_exceptions_move(&devcgroup->exceptions,
&tmp_devcgrp.exceptions);
return rc;
}
devcgroup->behavior = DEVCG_DEFAULT_ALLOW;
dev_exception_clean(&tmp_devcgrp);
break;
case DEVCG_DENY:
if (css_has_online_children(&devcgroup->css))
......
......@@ -335,14 +335,15 @@ static int evm_is_immutable(struct dentry *dentry, struct inode *inode)
(char **)&xattr_data, 0, GFP_NOFS);
if (rc <= 0) {
if (rc == -ENODATA)
return 0;
return rc;
rc = 0;
goto out;
}
if (xattr_data->type == EVM_XATTR_PORTABLE_DIGSIG)
rc = 1;
else
rc = 0;
out:
kfree(xattr_data);
return rc;
}
......
......@@ -455,14 +455,17 @@ static int evm_xattr_change(struct user_namespace *mnt_userns,
rc = vfs_getxattr_alloc(&init_user_ns, dentry, xattr_name, &xattr_data,
0, GFP_NOFS);
if (rc < 0)
return 1;
if (rc < 0) {
rc = 1;
goto out;
}
if (rc == xattr_value_len)
rc = !!memcmp(xattr_value, xattr_data, rc);
else
rc = 1;
out:
kfree(xattr_data);
return rc;
}
......
......@@ -326,7 +326,7 @@ enum integrity_status ima_get_cache_status(struct integrity_iint_cache *iint,
enum hash_algo ima_get_hash_algo(const struct evm_ima_xattr_data *xattr_value,
int xattr_len);
int ima_read_xattr(struct dentry *dentry,
struct evm_ima_xattr_data **xattr_value);
struct evm_ima_xattr_data **xattr_value, int xattr_len);
#else
static inline int ima_check_blacklist(struct integrity_iint_cache *iint,
......@@ -372,7 +372,8 @@ ima_get_hash_algo(struct evm_ima_xattr_data *xattr_value, int xattr_len)
}
static inline int ima_read_xattr(struct dentry *dentry,
struct evm_ima_xattr_data **xattr_value)
struct evm_ima_xattr_data **xattr_value,
int xattr_len)
{
return 0;
}
......
......@@ -221,12 +221,12 @@ enum hash_algo ima_get_hash_algo(const struct evm_ima_xattr_data *xattr_value,
}
int ima_read_xattr(struct dentry *dentry,
struct evm_ima_xattr_data **xattr_value)
struct evm_ima_xattr_data **xattr_value, int xattr_len)
{
ssize_t ret;
int ret;
ret = vfs_getxattr_alloc(&init_user_ns, dentry, XATTR_NAME_IMA,
(char **)xattr_value, 0, GFP_NOFS);
(char **)xattr_value, xattr_len, GFP_NOFS);
if (ret == -EOPNOTSUPP)
ret = 0;
return ret;
......
......@@ -293,7 +293,8 @@ static int process_measurement(struct file *file, const struct cred *cred,
/* HASH sets the digital signature and update flags, nothing else */
if ((action & IMA_HASH) &&
!(test_bit(IMA_DIGSIG, &iint->atomic_flags))) {
xattr_len = ima_read_xattr(file_dentry(file), &xattr_value);
xattr_len = ima_read_xattr(file_dentry(file),
&xattr_value, xattr_len);
if ((xattr_value && xattr_len > 2) &&
(xattr_value->type == EVM_IMA_XATTR_DIGSIG))
set_bit(IMA_DIGSIG, &iint->atomic_flags);
......@@ -316,7 +317,8 @@ static int process_measurement(struct file *file, const struct cred *cred,
if ((action & IMA_APPRAISE_SUBMASK) ||
strcmp(template_desc->name, IMA_TEMPLATE_IMA_NAME) != 0) {
/* read 'security.ima' */
xattr_len = ima_read_xattr(file_dentry(file), &xattr_value);
xattr_len = ima_read_xattr(file_dentry(file),
&xattr_value, xattr_len);
/*
* Read the appended modsig if allowed by the policy, and allow
......
......@@ -601,16 +601,15 @@ int ima_eventevmsig_init(struct ima_event_data *event_data,
rc = vfs_getxattr_alloc(&init_user_ns, file_dentry(event_data->file),
XATTR_NAME_EVM, (char **)&xattr_data, 0,
GFP_NOFS);
if (rc <= 0)
return 0;
if (xattr_data->type != EVM_XATTR_PORTABLE_DIGSIG) {
kfree(xattr_data);
return 0;
if (rc <= 0 || xattr_data->type != EVM_XATTR_PORTABLE_DIGSIG) {
rc = 0;
goto out;
}
rc = ima_write_template_field_data((char *)xattr_data, rc, DATA_FMT_HEX,
field_data);
out:
kfree(xattr_data);
return rc;
}
......
......@@ -190,6 +190,7 @@ static inline void print_ipv4_addr(struct audit_buffer *ab, __be32 addr,
/**
* dump_common_audit_data - helper to dump common audit data
* @ab : the audit buffer
* @a : common audit data
*
*/
......
......@@ -161,8 +161,8 @@ static void __init append_ordered_lsm(struct lsm_info *lsm, const char *from)
lsm->enabled = &lsm_enabled_true;
ordered_lsms[last_lsm++] = lsm;
init_debug("%s ordering: %s (%sabled)\n", from, lsm->name,
is_enabled(lsm) ? "en" : "dis");
init_debug("%s ordered: %s (%s)\n", from, lsm->name,
is_enabled(lsm) ? "enabled" : "disabled");
}
/* Is an LSM allowed to be initialized? */
......@@ -253,7 +253,7 @@ static void __init ordered_lsm_parse(const char *order, const char *origin)
/* LSM_ORDER_FIRST is always first. */
for (lsm = __start_lsm_info; lsm < __end_lsm_info; lsm++) {
if (lsm->order == LSM_ORDER_FIRST)
append_ordered_lsm(lsm, "first");
append_ordered_lsm(lsm, " first");
}
/* Process "security=", if given. */
......@@ -271,7 +271,7 @@ static void __init ordered_lsm_parse(const char *order, const char *origin)
if ((major->flags & LSM_FLAG_LEGACY_MAJOR) &&
strcmp(major->name, chosen_major_lsm) != 0) {
set_enabled(major, false);
init_debug("security=%s disabled: %s\n",
init_debug("security=%s disabled: %s (only one legacy major LSM)\n",
chosen_major_lsm, major->name);
}
}
......@@ -292,7 +292,8 @@ static void __init ordered_lsm_parse(const char *order, const char *origin)
}
if (!found)
init_debug("%s ignored: %s\n", origin, name);
init_debug("%s ignored: %s (not built into kernel)\n",
origin, name);
}
/* Process "security=", if given. */
......@@ -310,7 +311,8 @@ static void __init ordered_lsm_parse(const char *order, const char *origin)
if (exists_ordered_lsm(lsm))
continue;
set_enabled(lsm, false);
init_debug("%s disabled: %s\n", origin, lsm->name);
init_debug("%s skipped: %s (not in requested order)\n",
origin, lsm->name);
}
kfree(sep);
......@@ -321,6 +323,24 @@ static void __init lsm_early_task(struct task_struct *task);
static int lsm_append(const char *new, char **result);
static void __init report_lsm_order(void)
{
struct lsm_info **lsm, *early;
int first = 0;
pr_info("initializing lsm=");
/* Report each enabled LSM name, comma separated. */
for (early = __start_early_lsm_info; early < __end_early_lsm_info; early++)
if (is_enabled(early))
pr_cont("%s%s", first++ == 0 ? "" : ",", early->name);
for (lsm = ordered_lsms; *lsm; lsm++)
if (is_enabled(*lsm))
pr_cont("%s%s", first++ == 0 ? "" : ",", (*lsm)->name);
pr_cont("\n");
}
static void __init ordered_lsm_init(void)
{
struct lsm_info **lsm;
......@@ -330,7 +350,8 @@ static void __init ordered_lsm_init(void)
if (chosen_lsm_order) {
if (chosen_major_lsm) {
pr_info("security= is ignored because it is superseded by lsm=\n");
pr_warn("security=%s is ignored because it is superseded by lsm=%s\n",
chosen_major_lsm, chosen_lsm_order);
chosen_major_lsm = NULL;
}
ordered_lsm_parse(chosen_lsm_order, "cmdline");
......@@ -340,6 +361,8 @@ static void __init ordered_lsm_init(void)
for (lsm = ordered_lsms; *lsm; lsm++)
prepare_lsm(*lsm);
report_lsm_order();
init_debug("cred blob size = %d\n", blob_sizes.lbs_cred);
init_debug("file blob size = %d\n", blob_sizes.lbs_file);
init_debug("inode blob size = %d\n", blob_sizes.lbs_inode);
......@@ -396,13 +419,17 @@ int __init security_init(void)
{
struct lsm_info *lsm;
pr_info("Security Framework initializing\n");
init_debug("legacy security=%s\n", chosen_major_lsm ?: " *unspecified*");
init_debug(" CONFIG_LSM=%s\n", builtin_lsm_order);
init_debug("boot arg lsm=%s\n", chosen_lsm_order ?: " *unspecified*");
/*
* Append the names of the early LSM modules now that kmalloc() is
* available
*/
for (lsm = __start_early_lsm_info; lsm < __end_early_lsm_info; lsm++) {
init_debug(" early started: %s (%s)\n", lsm->name,
is_enabled(lsm) ? "enabled" : "disabled");
if (lsm->enabled)
lsm_append(lsm->name, &lsm_names);
}
......@@ -2315,8 +2342,8 @@ int security_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
}
EXPORT_SYMBOL(security_sock_rcv_skb);
int security_socket_getpeersec_stream(struct socket *sock, char __user *optval,
int __user *optlen, unsigned len)
int security_socket_getpeersec_stream(struct socket *sock, sockptr_t optval,
sockptr_t optlen, unsigned int len)
{
return call_int_hook(socket_getpeersec_stream, -ENOPROTOOPT, sock,
optval, optlen, len);
......
......@@ -5138,11 +5138,12 @@ static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
return err;
}
static int selinux_socket_getpeersec_stream(struct socket *sock, char __user *optval,
int __user *optlen, unsigned len)
static int selinux_socket_getpeersec_stream(struct socket *sock,
sockptr_t optval, sockptr_t optlen,
unsigned int len)
{
int err = 0;
char *scontext;
char *scontext = NULL;
u32 scontext_len;
struct sk_security_struct *sksec = sock->sk->sk_security;
u32 peer_sid = SECSID_NULL;
......@@ -5158,17 +5159,15 @@ static int selinux_socket_getpeersec_stream(struct socket *sock, char __user *op
&scontext_len);
if (err)
return err;
if (scontext_len > len) {
err = -ERANGE;
goto out_len;
}
if (copy_to_user(optval, scontext, scontext_len))
if (copy_to_sockptr(optval, scontext, scontext_len))
err = -EFAULT;
out_len:
if (put_user(scontext_len, optlen))
if (copy_to_sockptr(optlen, &scontext_len, sizeof(scontext_len)))
err = -EFAULT;
kfree(scontext);
return err;
......
......@@ -4074,12 +4074,12 @@ static int smack_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
* returns zero on success, an error code otherwise
*/
static int smack_socket_getpeersec_stream(struct socket *sock,
char __user *optval,
int __user *optlen, unsigned len)
sockptr_t optval, sockptr_t optlen,
unsigned int len)
{
struct socket_smack *ssp;
char *rcp = "";
int slen = 1;
u32 slen = 1;
int rc = 0;
ssp = sock->sk->sk_security;
......@@ -4087,15 +4087,16 @@ static int smack_socket_getpeersec_stream(struct socket *sock,
rcp = ssp->smk_packet->smk_known;
slen = strlen(rcp) + 1;
}
if (slen > len)
if (slen > len) {
rc = -ERANGE;
else if (copy_to_user(optval, rcp, slen) != 0)
rc = -EFAULT;
goto out_len;
}
if (put_user(slen, optlen) != 0)
if (copy_to_sockptr(optval, rcp, slen))
rc = -EFAULT;
out_len:
if (copy_to_sockptr(optlen, &slen, sizeof(slen)))
rc = -EFAULT;
return rc;
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment