summaryrefslogtreecommitdiff
path: root/security/security.c
diff options
context:
space:
mode:
authorPaul Moore <paul@paul-moore.com>2023-10-24 14:44:00 -0400
committerPaul Moore <paul@paul-moore.com>2023-11-12 22:54:42 -0500
commitd7cf3412a9f6c547e5ee443fa7644e08898aa3e2 (patch)
treef5ab0f4687f6d7efae5ac221906a18ddf3b11330 /security/security.c
parentfdcf699b60712ecd6e41d9fc09137279257a4bf8 (diff)
lsm: consolidate buffer size handling into lsm_fill_user_ctx()
While we have a lsm_fill_user_ctx() helper function designed to make life easier for LSMs which return lsm_ctx structs to userspace, we didn't include all of the buffer length safety checks and buffer padding adjustments in the helper. This led to code duplication across the different LSMs and the possibility for mistakes across the different LSM subsystems. In order to reduce code duplication and decrease the chances of silly mistakes, we're consolidating all of this code into the lsm_fill_user_ctx() helper. The buffer padding is also modified from a fixed 8-byte alignment to an alignment that matches the word length of the machine (BITS_PER_LONG / 8). Signed-off-by: Paul Moore <paul@paul-moore.com>
Diffstat (limited to 'security/security.c')
-rw-r--r--security/security.c55
1 files changed, 31 insertions, 24 deletions
diff --git a/security/security.c b/security/security.c
index 78e7ffcc9f6c..86f7a1995991 100644
--- a/security/security.c
+++ b/security/security.c
@@ -772,42 +772,49 @@ static int lsm_superblock_alloc(struct super_block *sb)
/**
* lsm_fill_user_ctx - Fill a user space lsm_ctx structure
- * @ctx: an LSM context to be filled
- * @context: the new context value
- * @context_size: the size of the new context value
+ * @uctx: a userspace LSM context to be filled
+ * @uctx_len: available uctx size (input), used uctx size (output)
+ * @val: the new LSM context value
+ * @val_len: the size of the new LSM context value
* @id: LSM id
* @flags: LSM defined flags
*
- * Fill all of the fields in a user space lsm_ctx structure.
- * Caller is assumed to have verified that @ctx has enough space
- * for @context.
+ * Fill all of the fields in a userspace lsm_ctx structure.
*
- * Returns 0 on success, -EFAULT on a copyout error, -ENOMEM
- * if memory can't be allocated.
+ * Returns 0 on success, -E2BIG if userspace buffer is not large enough,
+ * -EFAULT on a copyout error, -ENOMEM if memory can't be allocated.
*/
-int lsm_fill_user_ctx(struct lsm_ctx __user *ctx, void *context,
- size_t context_size, u64 id, u64 flags)
+int lsm_fill_user_ctx(struct lsm_ctx __user *uctx, size_t *uctx_len,
+ void *val, size_t val_len,
+ u64 id, u64 flags)
{
- struct lsm_ctx *lctx;
- size_t locallen = struct_size(lctx, ctx, context_size);
+ struct lsm_ctx *nctx = NULL;
+ size_t nctx_len;
int rc = 0;
- lctx = kzalloc(locallen, GFP_KERNEL);
- if (lctx == NULL)
- return -ENOMEM;
-
- lctx->id = id;
- lctx->flags = flags;
- lctx->ctx_len = context_size;
- lctx->len = locallen;
+ nctx_len = ALIGN(struct_size(nctx, ctx, val_len), BITS_PER_LONG / 8);
+ if (nctx_len > *uctx_len) {
+ rc = -E2BIG;
+ goto out;
+ }
- memcpy(lctx->ctx, context, context_size);
+ nctx = kzalloc(nctx_len, GFP_KERNEL);
+ if (nctx == NULL) {
+ rc = -ENOMEM;
+ goto out;
+ }
+ nctx->id = id;
+ nctx->flags = flags;
+ nctx->len = nctx_len;
+ nctx->ctx_len = val_len;
+ memcpy(nctx->ctx, val, val_len);
- if (copy_to_user(ctx, lctx, locallen))
+ if (copy_to_user(uctx, nctx, nctx_len))
rc = -EFAULT;
- kfree(lctx);
-
+out:
+ kfree(nctx);
+ *uctx_len = nctx_len;
return rc;
}