Skip to content

Commit 1537ad1

Browse files
WOnder93pcmoore
authored andcommitted
kernfs: fix xattr name handling in LSM helpers
The implementation of kernfs_security_xattr_*() helpers reuses the kernfs_node_xattr_*() functions, which take the suffix of the xattr name and extract full xattr name from it using xattr_full_name(). However, this function relies on the fact that the suffix passed to xattr handlers from VFS is always constructed from the full name by just incerementing the pointer. This doesn't necessarily hold for the callers of kernfs_security_xattr_*(), so their usage will easily lead to out-of-bounds access. Fix this by moving the xattr name reconstruction to the VFS xattr handlers and replacing the kernfs_security_xattr_*() helpers with more general kernfs_xattr_*() helpers that take full xattr name and allow accessing all kernfs node's xattrs. Reported-by: kernel test robot <[email protected]> Fixes: b230d5a ("LSM: add new hook for kernfs node initialization") Fixes: ec882da ("selinux: implement the kernfs_init_security hook") Signed-off-by: Ondrej Mosnacek <[email protected]> Signed-off-by: Paul Moore <[email protected]>
1 parent 593854c commit 1537ad1

File tree

3 files changed

+33
-56
lines changed

3 files changed

+33
-56
lines changed

fs/kernfs/inode.c

Lines changed: 21 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -288,81 +288,61 @@ int kernfs_iop_permission(struct inode *inode, int mask)
288288
return generic_permission(inode, mask);
289289
}
290290

291-
static int kernfs_node_xattr_get(const struct xattr_handler *handler,
292-
struct kernfs_node *kn, const char *suffix,
293-
void *value, size_t size)
291+
int kernfs_xattr_get(struct kernfs_node *kn, const char *name,
292+
void *value, size_t size)
294293
{
295-
const char *name = xattr_full_name(handler, suffix);
296-
struct kernfs_iattrs *attrs;
297-
298-
attrs = kernfs_iattrs_noalloc(kn);
294+
struct kernfs_iattrs *attrs = kernfs_iattrs_noalloc(kn);
299295
if (!attrs)
300296
return -ENODATA;
301297

302298
return simple_xattr_get(&attrs->xattrs, name, value, size);
303299
}
304300

305-
static int kernfs_node_xattr_set(const struct xattr_handler *handler,
306-
struct kernfs_node *kn, const char *suffix,
307-
const void *value, size_t size, int flags)
301+
int kernfs_xattr_set(struct kernfs_node *kn, const char *name,
302+
const void *value, size_t size, int flags)
308303
{
309-
const char *name = xattr_full_name(handler, suffix);
310-
struct kernfs_iattrs *attrs;
311-
312-
attrs = kernfs_iattrs(kn);
304+
struct kernfs_iattrs *attrs = kernfs_iattrs(kn);
313305
if (!attrs)
314306
return -ENOMEM;
315307

316308
return simple_xattr_set(&attrs->xattrs, name, value, size, flags);
317309
}
318310

319-
static int kernfs_xattr_get(const struct xattr_handler *handler,
320-
struct dentry *unused, struct inode *inode,
321-
const char *suffix, void *value, size_t size)
311+
static int kernfs_vfs_xattr_get(const struct xattr_handler *handler,
312+
struct dentry *unused, struct inode *inode,
313+
const char *suffix, void *value, size_t size)
322314
{
315+
const char *name = xattr_full_name(handler, suffix);
323316
struct kernfs_node *kn = inode->i_private;
324317

325-
return kernfs_node_xattr_get(handler, kn, suffix, value, size);
318+
return kernfs_xattr_get(kn, name, value, size);
326319
}
327320

328-
static int kernfs_xattr_set(const struct xattr_handler *handler,
329-
struct dentry *unused, struct inode *inode,
330-
const char *suffix, const void *value,
331-
size_t size, int flags)
321+
static int kernfs_vfs_xattr_set(const struct xattr_handler *handler,
322+
struct dentry *unused, struct inode *inode,
323+
const char *suffix, const void *value,
324+
size_t size, int flags)
332325
{
326+
const char *name = xattr_full_name(handler, suffix);
333327
struct kernfs_node *kn = inode->i_private;
334328

335-
return kernfs_node_xattr_set(handler, kn, suffix, value, size, flags);
329+
return kernfs_xattr_set(kn, name, value, size, flags);
336330
}
337331

338332
static const struct xattr_handler kernfs_trusted_xattr_handler = {
339333
.prefix = XATTR_TRUSTED_PREFIX,
340-
.get = kernfs_xattr_get,
341-
.set = kernfs_xattr_set,
334+
.get = kernfs_vfs_xattr_get,
335+
.set = kernfs_vfs_xattr_set,
342336
};
343337

344338
static const struct xattr_handler kernfs_security_xattr_handler = {
345339
.prefix = XATTR_SECURITY_PREFIX,
346-
.get = kernfs_xattr_get,
347-
.set = kernfs_xattr_set,
340+
.get = kernfs_vfs_xattr_get,
341+
.set = kernfs_vfs_xattr_set,
348342
};
349343

350344
const struct xattr_handler *kernfs_xattr_handlers[] = {
351345
&kernfs_trusted_xattr_handler,
352346
&kernfs_security_xattr_handler,
353347
NULL
354348
};
355-
356-
int kernfs_security_xattr_get(struct kernfs_node *kn, const char *suffix,
357-
void *value, size_t size)
358-
{
359-
return kernfs_node_xattr_get(&kernfs_security_xattr_handler,
360-
kn, suffix, value, size);
361-
}
362-
363-
int kernfs_security_xattr_set(struct kernfs_node *kn, const char *suffix,
364-
void *value, size_t size, int flags)
365-
{
366-
return kernfs_node_xattr_set(&kernfs_security_xattr_handler,
367-
kn, suffix, value, size, flags);
368-
}

include/linux/kernfs.h

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -371,10 +371,10 @@ __poll_t kernfs_generic_poll(struct kernfs_open_file *of,
371371
struct poll_table_struct *pt);
372372
void kernfs_notify(struct kernfs_node *kn);
373373

374-
int kernfs_security_xattr_get(struct kernfs_node *kn, const char *suffix,
375-
void *value, size_t size);
376-
int kernfs_security_xattr_set(struct kernfs_node *kn, const char *suffix,
377-
void *value, size_t size, int flags);
374+
int kernfs_xattr_get(struct kernfs_node *kn, const char *name,
375+
void *value, size_t size);
376+
int kernfs_xattr_set(struct kernfs_node *kn, const char *name,
377+
const void *value, size_t size, int flags);
378378

379379
const void *kernfs_super_ns(struct super_block *sb);
380380
int kernfs_get_tree(struct fs_context *fc);
@@ -478,14 +478,12 @@ static inline int kernfs_setattr(struct kernfs_node *kn,
478478

479479
static inline void kernfs_notify(struct kernfs_node *kn) { }
480480

481-
static inline int kernfs_security_xattr_get(struct kernfs_node *kn,
482-
const char *suffix, void *value,
483-
size_t size)
481+
static inline int kernfs_xattr_get(struct kernfs_node *kn, const char *name,
482+
void *value, size_t size)
484483
{ return -ENOSYS; }
485484

486-
static inline int kernfs_security_xattr_set(struct kernfs_node *kn,
487-
const char *suffix, void *value,
488-
size_t size, int flags)
485+
static inline int kernfs_xattr_set(struct kernfs_node *kn, const char *name,
486+
const void *value, size_t size, int flags)
489487
{ return -ENOSYS; }
490488

491489
static inline const void *kernfs_super_ns(struct super_block *sb)

security/selinux/hooks.c

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3394,7 +3394,7 @@ static int selinux_kernfs_init_security(struct kernfs_node *kn_dir,
33943394
int rc;
33953395
char *context;
33963396

3397-
rc = kernfs_security_xattr_get(kn_dir, XATTR_SELINUX_SUFFIX, NULL, 0);
3397+
rc = kernfs_xattr_get(kn_dir, XATTR_NAME_SELINUX, NULL, 0);
33983398
if (rc == -ENODATA)
33993399
return 0;
34003400
else if (rc < 0)
@@ -3405,8 +3405,7 @@ static int selinux_kernfs_init_security(struct kernfs_node *kn_dir,
34053405
if (!context)
34063406
return -ENOMEM;
34073407

3408-
rc = kernfs_security_xattr_get(kn_dir, XATTR_SELINUX_SUFFIX, context,
3409-
clen);
3408+
rc = kernfs_xattr_get(kn_dir, XATTR_NAME_SELINUX, context, clen);
34103409
if (rc < 0) {
34113410
kfree(context);
34123411
return rc;
@@ -3439,8 +3438,8 @@ static int selinux_kernfs_init_security(struct kernfs_node *kn_dir,
34393438
if (rc)
34403439
return rc;
34413440

3442-
rc = kernfs_security_xattr_set(kn, XATTR_SELINUX_SUFFIX, context, clen,
3443-
XATTR_CREATE);
3441+
rc = kernfs_xattr_set(kn, XATTR_NAME_SELINUX, context, clen,
3442+
XATTR_CREATE);
34443443
kfree(context);
34453444
return rc;
34463445
}

0 commit comments

Comments
 (0)