linux-security-module.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH bpf-next v2 0/7] Add check for bpf lsm return value
@ 2024-03-25  9:56 Xu Kuohai
  2024-03-25  9:56 ` [PATCH bpf-next v2 1/7] bpf, lsm: Annotate lsm hook return integer with new macro LSM_RET_INT Xu Kuohai
                   ` (7 more replies)
  0 siblings, 8 replies; 13+ messages in thread
From: Xu Kuohai @ 2024-03-25  9:56 UTC (permalink / raw)
  To: bpf, linux-security-module
  Cc: Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko,
	Martin KaFai Lau, Eduard Zingerman, Song Liu, Yonghong Song,
	John Fastabend, KP Singh, Stanislav Fomichev, Hao Luo, Jiri Olsa,
	Florent Revest, Brendan Jackman, Paul Moore, James Morris,
	Serge E . Hallyn, Khadija Kamran, Casey Schaufler,
	Ondrej Mosnacek, Kees Cook, John Johansen, Lukas Bulwahn,
	Roberto Sassu, Shung-Hsi Yu

From: Xu Kuohai <xukuohai@huawei.com>

A bpf prog returning positive number attached to file_alloc_security hook
will make kernel panic.

Here is a panic log:

[  441.235774] BUG: kernel NULL pointer dereference, address: 00000000000009
[  441.236748] #PF: supervisor write access in kernel mode
[  441.237429] #PF: error_code(0x0002) - not-present page
[  441.238119] PGD 800000000b02f067 P4D 800000000b02f067 PUD b031067 PMD 0
[  441.238990] Oops: 0002 [#1] PREEMPT SMP PTI
[  441.239546] CPU: 0 PID: 347 Comm: loader Not tainted 6.8.0-rc6-gafe0cbf23373 #22
[  441.240496] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.15.0-0-g2dd4b4
[  441.241933] RIP: 0010:alloc_file+0x4b/0x190
[  441.242485] Code: 8b 04 25 c0 3c 1f 00 48 8b b0 30 0c 00 00 e8 9c fe ff ff 48 3d 00 f0 ff fb
[  441.244820] RSP: 0018:ffffc90000c67c40 EFLAGS: 00010203
[  441.245484] RAX: ffff888006a891a0 RBX: ffffffff8223bd00 RCX: 0000000035b08000
[  441.246391] RDX: ffff88800b95f7b0 RSI: 00000000001fc110 RDI: f089cd0b8088ffff
[  441.247294] RBP: ffffc90000c67c58 R08: 0000000000000001 R09: 0000000000000001
[  441.248209] R10: 0000000000000001 R11: 0000000000000001 R12: 0000000000000001
[  441.249108] R13: ffffc90000c67c78 R14: ffffffff8223bd00 R15: fffffffffffffff4
[  441.250007] FS:  00000000005f3300(0000) GS:ffff88803ec00000(0000) knlGS:0000000000000000
[  441.251053] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[  441.251788] CR2: 00000000000001a9 CR3: 000000000bdc4003 CR4: 0000000000170ef0
[  441.252688] Call Trace:
[  441.253011]  <TASK>
[  441.253296]  ? __die+0x24/0x70
[  441.253702]  ? page_fault_oops+0x15b/0x480
[  441.254236]  ? fixup_exception+0x26/0x330
[  441.254750]  ? exc_page_fault+0x6d/0x1c0
[  441.255257]  ? asm_exc_page_fault+0x26/0x30
[  441.255792]  ? alloc_file+0x4b/0x190
[  441.256257]  alloc_file_pseudo+0x9f/0xf0
[  441.256760]  __anon_inode_getfile+0x87/0x190
[  441.257311]  ? lock_release+0x14e/0x3f0
[  441.257808]  bpf_link_prime+0xe8/0x1d0
[  441.258315]  bpf_tracing_prog_attach+0x311/0x570
[  441.258916]  ? __pfx_bpf_lsm_file_alloc_security+0x10/0x10
[  441.259605]  __sys_bpf+0x1bb7/0x2dc0
[  441.260070]  __x64_sys_bpf+0x20/0x30
[  441.260533]  do_syscall_64+0x72/0x140
[  441.261004]  entry_SYSCALL_64_after_hwframe+0x6e/0x76
[  441.261643] RIP: 0033:0x4b0349
[  441.262045] Code: ff ff c3 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 40 00 48 89 f8 48 89 f7 48 88
[  441.264355] RSP: 002b:00007fff74daee38 EFLAGS: 00000246 ORIG_RAX: 0000000000000141
[  441.265293] RAX: ffffffffffffffda RBX: 00007fff74daef30 RCX: 00000000004b0349
[  441.266187] RDX: 0000000000000040 RSI: 00007fff74daee50 RDI: 000000000000001c
[  441.267114] RBP: 000000000000001b R08: 00000000005ef820 R09: 0000000000000000
[  441.268018] R10: 0000000000000000 R11: 0000000000000246 R12: 0000000000000004
[  441.268907] R13: 0000000000000004 R14: 00000000005ef018 R15: 00000000004004e8

The reason is that the positive number returned by bpf prog is not a
valid errno, and could not be filtered out with IS_ERR which is used by
the file system to check errors. As a result, the filesystem mistakenly
uses this random positive number as file pointer, causing panic.

To fix this issue, there are two schemes:

1. Modify the calling sites of file_alloc_security to take positive
   return values as zero.

2. Make the bpf verifier to ensure no unpredicted value returned by
   lsm bpf prog.

Considering that hook file_alloc_security never returned positive number
before bpf lsm was introduced, and other lsm hooks may have the same
problem, scheme 2 is more reasonable.

So this patch set adds lsm return value check in verifier to fix it.

v2:
fix bpf ci failure

v1:
https://lore.kernel.org/bpf/20240316122359.1073787-1-xukuohai@huaweicloud.com/

Xu Kuohai (7):
  bpf, lsm: Annotate lsm hook return integer with new macro LSM_RET_INT
  bpf, lsm: Add return value range description for lsm hook
  bpf, lsm: Add function to read lsm hook return value range
  bpf, lsm: Check bpf lsm hook return values in verifier
  bpf: Fix compare error in function retval_range_within
  selftests/bpf: Avoid load failure for token_lsm.c
  selftests/bpf: Add return value checks and corrections for failed
    progs

 include/linux/bpf.h                           |   1 +
 include/linux/bpf_lsm.h                       |   8 +
 include/linux/lsm_hook_defs.h                 | 433 +++++++++---------
 include/linux/lsm_hooks.h                     |   6 -
 kernel/bpf/bpf_lsm.c                          |  66 ++-
 kernel/bpf/btf.c                              |   5 +-
 kernel/bpf/verifier.c                         |  59 ++-
 security/security.c                           |   1 +
 tools/testing/selftests/bpf/progs/err.h       |  10 +
 .../selftests/bpf/progs/test_sig_in_xattr.c   |   4 +
 .../bpf/progs/test_verify_pkcs7_sig.c         |   8 +-
 tools/testing/selftests/bpf/progs/token_lsm.c |   4 +-
 .../bpf/progs/verifier_global_subprogs.c      |   7 +-
 13 files changed, 376 insertions(+), 236 deletions(-)

-- 
2.30.2


^ permalink raw reply	[flat|nested] 13+ messages in thread

* [PATCH bpf-next v2 1/7] bpf, lsm: Annotate lsm hook return integer with new macro LSM_RET_INT
  2024-03-25  9:56 [PATCH bpf-next v2 0/7] Add check for bpf lsm return value Xu Kuohai
@ 2024-03-25  9:56 ` Xu Kuohai
  2024-03-25  9:56 ` [PATCH bpf-next v2 2/7] bpf, lsm: Add return value range description for lsm hook Xu Kuohai
                   ` (6 subsequent siblings)
  7 siblings, 0 replies; 13+ messages in thread
From: Xu Kuohai @ 2024-03-25  9:56 UTC (permalink / raw)
  To: bpf, linux-security-module
  Cc: Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko,
	Martin KaFai Lau, Eduard Zingerman, Song Liu, Yonghong Song,
	John Fastabend, KP Singh, Stanislav Fomichev, Hao Luo, Jiri Olsa,
	Florent Revest, Brendan Jackman, Paul Moore, James Morris,
	Serge E . Hallyn, Khadija Kamran, Casey Schaufler,
	Ondrej Mosnacek, Kees Cook, John Johansen, Lukas Bulwahn,
	Roberto Sassu, Shung-Hsi Yu

From: Xu Kuohai <xukuohai@huawei.com>

Add macro LSM_RET_INT to annotate lsm hook return integer type and the
default return value. The follow-up patch will use this macro to add
return value range descriptions.

Signed-off-by: Xu Kuohai <xukuohai@huawei.com>
---
 include/linux/lsm_hook_defs.h | 424 +++++++++++++++++-----------------
 include/linux/lsm_hooks.h     |   6 -
 kernel/bpf/bpf_lsm.c          |  10 +
 security/security.c           |   1 +
 4 files changed, 224 insertions(+), 217 deletions(-)

diff --git a/include/linux/lsm_hook_defs.h b/include/linux/lsm_hook_defs.h
index 642272576582..22b64b15faa8 100644
--- a/include/linux/lsm_hook_defs.h
+++ b/include/linux/lsm_hook_defs.h
@@ -26,409 +26,411 @@
  *   #undef LSM_HOOK
  * };
  */
-LSM_HOOK(int, 0, binder_set_context_mgr, const struct cred *mgr)
-LSM_HOOK(int, 0, binder_transaction, const struct cred *from,
+LSM_HOOK(int, LSM_RET_INT(0), binder_set_context_mgr, const struct cred *mgr)
+LSM_HOOK(int, LSM_RET_INT(0), binder_transaction, const struct cred *from,
 	 const struct cred *to)
-LSM_HOOK(int, 0, binder_transfer_binder, const struct cred *from,
+LSM_HOOK(int, LSM_RET_INT(0), binder_transfer_binder, const struct cred *from,
 	 const struct cred *to)
-LSM_HOOK(int, 0, binder_transfer_file, const struct cred *from,
+LSM_HOOK(int, LSM_RET_INT(0), binder_transfer_file, const struct cred *from,
 	 const struct cred *to, const struct file *file)
-LSM_HOOK(int, 0, ptrace_access_check, struct task_struct *child,
+LSM_HOOK(int, LSM_RET_INT(0), ptrace_access_check, struct task_struct *child,
 	 unsigned int mode)
-LSM_HOOK(int, 0, ptrace_traceme, struct task_struct *parent)
-LSM_HOOK(int, 0, capget, const struct task_struct *target, kernel_cap_t *effective,
+LSM_HOOK(int, LSM_RET_INT(0), ptrace_traceme, struct task_struct *parent)
+LSM_HOOK(int, LSM_RET_INT(0), capget, const struct task_struct *target, kernel_cap_t *effective,
 	 kernel_cap_t *inheritable, kernel_cap_t *permitted)
-LSM_HOOK(int, 0, capset, struct cred *new, const struct cred *old,
+LSM_HOOK(int, LSM_RET_INT(0), capset, struct cred *new, const struct cred *old,
 	 const kernel_cap_t *effective, const kernel_cap_t *inheritable,
 	 const kernel_cap_t *permitted)
-LSM_HOOK(int, 0, capable, const struct cred *cred, struct user_namespace *ns,
+LSM_HOOK(int, LSM_RET_INT(0), capable, const struct cred *cred, struct user_namespace *ns,
 	 int cap, unsigned int opts)
-LSM_HOOK(int, 0, quotactl, int cmds, int type, int id, const struct super_block *sb)
-LSM_HOOK(int, 0, quota_on, struct dentry *dentry)
-LSM_HOOK(int, 0, syslog, int type)
-LSM_HOOK(int, 0, settime, const struct timespec64 *ts,
+LSM_HOOK(int, LSM_RET_INT(0), quotactl, int cmds, int type, int id, const struct super_block *sb)
+LSM_HOOK(int, LSM_RET_INT(0), quota_on, struct dentry *dentry)
+LSM_HOOK(int, LSM_RET_INT(0), syslog, int type)
+LSM_HOOK(int, LSM_RET_INT(0), settime, const struct timespec64 *ts,
 	 const struct timezone *tz)
-LSM_HOOK(int, 1, vm_enough_memory, struct mm_struct *mm, long pages)
-LSM_HOOK(int, 0, bprm_creds_for_exec, struct linux_binprm *bprm)
-LSM_HOOK(int, 0, bprm_creds_from_file, struct linux_binprm *bprm, const struct file *file)
-LSM_HOOK(int, 0, bprm_check_security, struct linux_binprm *bprm)
+LSM_HOOK(int, LSM_RET_INT(1), vm_enough_memory, struct mm_struct *mm, long pages)
+LSM_HOOK(int, LSM_RET_INT(0), bprm_creds_for_exec, struct linux_binprm *bprm)
+LSM_HOOK(int, LSM_RET_INT(0), bprm_creds_from_file, struct linux_binprm *bprm,
+	 const struct file *file)
+LSM_HOOK(int, LSM_RET_INT(0), bprm_check_security, struct linux_binprm *bprm)
 LSM_HOOK(void, LSM_RET_VOID, bprm_committing_creds, const struct linux_binprm *bprm)
 LSM_HOOK(void, LSM_RET_VOID, bprm_committed_creds, const struct linux_binprm *bprm)
-LSM_HOOK(int, 0, fs_context_submount, struct fs_context *fc, struct super_block *reference)
-LSM_HOOK(int, 0, fs_context_dup, struct fs_context *fc,
+LSM_HOOK(int, LSM_RET_INT(0), fs_context_submount, struct fs_context *fc,
+	 struct super_block *reference)
+LSM_HOOK(int, LSM_RET_INT(0), fs_context_dup, struct fs_context *fc,
 	 struct fs_context *src_sc)
-LSM_HOOK(int, -ENOPARAM, fs_context_parse_param, struct fs_context *fc,
+LSM_HOOK(int, LSM_RET_INT(-ENOPARAM), fs_context_parse_param, struct fs_context *fc,
 	 struct fs_parameter *param)
-LSM_HOOK(int, 0, sb_alloc_security, struct super_block *sb)
+LSM_HOOK(int, LSM_RET_INT(0), sb_alloc_security, struct super_block *sb)
 LSM_HOOK(void, LSM_RET_VOID, sb_delete, struct super_block *sb)
 LSM_HOOK(void, LSM_RET_VOID, sb_free_security, struct super_block *sb)
 LSM_HOOK(void, LSM_RET_VOID, sb_free_mnt_opts, void *mnt_opts)
-LSM_HOOK(int, 0, sb_eat_lsm_opts, char *orig, void **mnt_opts)
-LSM_HOOK(int, 0, sb_mnt_opts_compat, struct super_block *sb, void *mnt_opts)
-LSM_HOOK(int, 0, sb_remount, struct super_block *sb, void *mnt_opts)
-LSM_HOOK(int, 0, sb_kern_mount, const struct super_block *sb)
-LSM_HOOK(int, 0, sb_show_options, struct seq_file *m, struct super_block *sb)
-LSM_HOOK(int, 0, sb_statfs, struct dentry *dentry)
-LSM_HOOK(int, 0, sb_mount, const char *dev_name, const struct path *path,
+LSM_HOOK(int, LSM_RET_INT(0), sb_eat_lsm_opts, char *orig, void **mnt_opts)
+LSM_HOOK(int, LSM_RET_INT(0), sb_mnt_opts_compat, struct super_block *sb, void *mnt_opts)
+LSM_HOOK(int, LSM_RET_INT(0), sb_remount, struct super_block *sb, void *mnt_opts)
+LSM_HOOK(int, LSM_RET_INT(0), sb_kern_mount, const struct super_block *sb)
+LSM_HOOK(int, LSM_RET_INT(0), sb_show_options, struct seq_file *m, struct super_block *sb)
+LSM_HOOK(int, LSM_RET_INT(0), sb_statfs, struct dentry *dentry)
+LSM_HOOK(int, LSM_RET_INT(0), sb_mount, const char *dev_name, const struct path *path,
 	 const char *type, unsigned long flags, void *data)
-LSM_HOOK(int, 0, sb_umount, struct vfsmount *mnt, int flags)
-LSM_HOOK(int, 0, sb_pivotroot, const struct path *old_path,
+LSM_HOOK(int, LSM_RET_INT(0), sb_umount, struct vfsmount *mnt, int flags)
+LSM_HOOK(int, LSM_RET_INT(0), sb_pivotroot, const struct path *old_path,
 	 const struct path *new_path)
-LSM_HOOK(int, 0, sb_set_mnt_opts, struct super_block *sb, void *mnt_opts,
+LSM_HOOK(int, LSM_RET_INT(0), sb_set_mnt_opts, struct super_block *sb, void *mnt_opts,
 	 unsigned long kern_flags, unsigned long *set_kern_flags)
-LSM_HOOK(int, 0, sb_clone_mnt_opts, const struct super_block *oldsb,
+LSM_HOOK(int, LSM_RET_INT(0), sb_clone_mnt_opts, const struct super_block *oldsb,
 	 struct super_block *newsb, unsigned long kern_flags,
 	 unsigned long *set_kern_flags)
-LSM_HOOK(int, 0, move_mount, const struct path *from_path,
+LSM_HOOK(int, LSM_RET_INT(0), move_mount, const struct path *from_path,
 	 const struct path *to_path)
-LSM_HOOK(int, -EOPNOTSUPP, dentry_init_security, struct dentry *dentry,
+LSM_HOOK(int, LSM_RET_INT(-EOPNOTSUPP), dentry_init_security, struct dentry *dentry,
 	 int mode, const struct qstr *name, const char **xattr_name,
 	 void **ctx, u32 *ctxlen)
-LSM_HOOK(int, 0, dentry_create_files_as, struct dentry *dentry, int mode,
+LSM_HOOK(int, LSM_RET_INT(0), dentry_create_files_as, struct dentry *dentry, int mode,
 	 struct qstr *name, const struct cred *old, struct cred *new)
 
 #ifdef CONFIG_SECURITY_PATH
-LSM_HOOK(int, 0, path_unlink, const struct path *dir, struct dentry *dentry)
-LSM_HOOK(int, 0, path_mkdir, const struct path *dir, struct dentry *dentry,
+LSM_HOOK(int, LSM_RET_INT(0), path_unlink, const struct path *dir, struct dentry *dentry)
+LSM_HOOK(int, LSM_RET_INT(0), path_mkdir, const struct path *dir, struct dentry *dentry,
 	 umode_t mode)
-LSM_HOOK(int, 0, path_rmdir, const struct path *dir, struct dentry *dentry)
-LSM_HOOK(int, 0, path_mknod, const struct path *dir, struct dentry *dentry,
+LSM_HOOK(int, LSM_RET_INT(0), path_rmdir, const struct path *dir, struct dentry *dentry)
+LSM_HOOK(int, LSM_RET_INT(0), path_mknod, const struct path *dir, struct dentry *dentry,
 	 umode_t mode, unsigned int dev)
-LSM_HOOK(int, 0, path_truncate, const struct path *path)
-LSM_HOOK(int, 0, path_symlink, const struct path *dir, struct dentry *dentry,
+LSM_HOOK(int, LSM_RET_INT(0), path_truncate, const struct path *path)
+LSM_HOOK(int, LSM_RET_INT(0), path_symlink, const struct path *dir, struct dentry *dentry,
 	 const char *old_name)
-LSM_HOOK(int, 0, path_link, struct dentry *old_dentry,
+LSM_HOOK(int, LSM_RET_INT(0), path_link, struct dentry *old_dentry,
 	 const struct path *new_dir, struct dentry *new_dentry)
-LSM_HOOK(int, 0, path_rename, const struct path *old_dir,
+LSM_HOOK(int, LSM_RET_INT(0), path_rename, const struct path *old_dir,
 	 struct dentry *old_dentry, const struct path *new_dir,
 	 struct dentry *new_dentry, unsigned int flags)
-LSM_HOOK(int, 0, path_chmod, const struct path *path, umode_t mode)
-LSM_HOOK(int, 0, path_chown, const struct path *path, kuid_t uid, kgid_t gid)
-LSM_HOOK(int, 0, path_chroot, const struct path *path)
+LSM_HOOK(int, LSM_RET_INT(0), path_chmod, const struct path *path, umode_t mode)
+LSM_HOOK(int, LSM_RET_INT(0), path_chown, const struct path *path, kuid_t uid, kgid_t gid)
+LSM_HOOK(int, LSM_RET_INT(0), path_chroot, const struct path *path)
 #endif /* CONFIG_SECURITY_PATH */
 
 /* Needed for inode based security check */
-LSM_HOOK(int, 0, path_notify, const struct path *path, u64 mask,
+LSM_HOOK(int, LSM_RET_INT(0), path_notify, const struct path *path, u64 mask,
 	 unsigned int obj_type)
-LSM_HOOK(int, 0, inode_alloc_security, struct inode *inode)
+LSM_HOOK(int, LSM_RET_INT(0), inode_alloc_security, struct inode *inode)
 LSM_HOOK(void, LSM_RET_VOID, inode_free_security, struct inode *inode)
-LSM_HOOK(int, -EOPNOTSUPP, inode_init_security, struct inode *inode,
+LSM_HOOK(int, LSM_RET_INT(-EOPNOTSUPP), inode_init_security, struct inode *inode,
 	 struct inode *dir, const struct qstr *qstr, struct xattr *xattrs,
 	 int *xattr_count)
-LSM_HOOK(int, 0, inode_init_security_anon, struct inode *inode,
+LSM_HOOK(int, LSM_RET_INT(0), inode_init_security_anon, struct inode *inode,
 	 const struct qstr *name, const struct inode *context_inode)
-LSM_HOOK(int, 0, inode_create, struct inode *dir, struct dentry *dentry,
+LSM_HOOK(int, LSM_RET_INT(0), inode_create, struct inode *dir, struct dentry *dentry,
 	 umode_t mode)
-LSM_HOOK(int, 0, inode_link, struct dentry *old_dentry, struct inode *dir,
+LSM_HOOK(int, LSM_RET_INT(0), inode_link, struct dentry *old_dentry, struct inode *dir,
 	 struct dentry *new_dentry)
-LSM_HOOK(int, 0, inode_unlink, struct inode *dir, struct dentry *dentry)
-LSM_HOOK(int, 0, inode_symlink, struct inode *dir, struct dentry *dentry,
+LSM_HOOK(int, LSM_RET_INT(0), inode_unlink, struct inode *dir, struct dentry *dentry)
+LSM_HOOK(int, LSM_RET_INT(0), inode_symlink, struct inode *dir, struct dentry *dentry,
 	 const char *old_name)
-LSM_HOOK(int, 0, inode_mkdir, struct inode *dir, struct dentry *dentry,
+LSM_HOOK(int, LSM_RET_INT(0), inode_mkdir, struct inode *dir, struct dentry *dentry,
 	 umode_t mode)
-LSM_HOOK(int, 0, inode_rmdir, struct inode *dir, struct dentry *dentry)
-LSM_HOOK(int, 0, inode_mknod, struct inode *dir, struct dentry *dentry,
+LSM_HOOK(int, LSM_RET_INT(0), inode_rmdir, struct inode *dir, struct dentry *dentry)
+LSM_HOOK(int, LSM_RET_INT(0), inode_mknod, struct inode *dir, struct dentry *dentry,
 	 umode_t mode, dev_t dev)
-LSM_HOOK(int, 0, inode_rename, struct inode *old_dir, struct dentry *old_dentry,
+LSM_HOOK(int, LSM_RET_INT(0), inode_rename, struct inode *old_dir, struct dentry *old_dentry,
 	 struct inode *new_dir, struct dentry *new_dentry)
-LSM_HOOK(int, 0, inode_readlink, struct dentry *dentry)
-LSM_HOOK(int, 0, inode_follow_link, struct dentry *dentry, struct inode *inode,
+LSM_HOOK(int, LSM_RET_INT(0), inode_readlink, struct dentry *dentry)
+LSM_HOOK(int, LSM_RET_INT(0), inode_follow_link, struct dentry *dentry, struct inode *inode,
 	 bool rcu)
-LSM_HOOK(int, 0, inode_permission, struct inode *inode, int mask)
-LSM_HOOK(int, 0, inode_setattr, struct dentry *dentry, struct iattr *attr)
-LSM_HOOK(int, 0, inode_getattr, const struct path *path)
-LSM_HOOK(int, 0, inode_setxattr, struct mnt_idmap *idmap,
+LSM_HOOK(int, LSM_RET_INT(0), inode_permission, struct inode *inode, int mask)
+LSM_HOOK(int, LSM_RET_INT(0), inode_setattr, struct dentry *dentry, struct iattr *attr)
+LSM_HOOK(int, LSM_RET_INT(0), inode_getattr, const struct path *path)
+LSM_HOOK(int, LSM_RET_INT(0), inode_setxattr, struct mnt_idmap *idmap,
 	 struct dentry *dentry, const char *name, const void *value,
 	 size_t size, int flags)
 LSM_HOOK(void, LSM_RET_VOID, inode_post_setxattr, struct dentry *dentry,
 	 const char *name, const void *value, size_t size, int flags)
-LSM_HOOK(int, 0, inode_getxattr, struct dentry *dentry, const char *name)
-LSM_HOOK(int, 0, inode_listxattr, struct dentry *dentry)
-LSM_HOOK(int, 0, inode_removexattr, struct mnt_idmap *idmap,
+LSM_HOOK(int, LSM_RET_INT(0), inode_getxattr, struct dentry *dentry, const char *name)
+LSM_HOOK(int, LSM_RET_INT(0), inode_listxattr, struct dentry *dentry)
+LSM_HOOK(int, LSM_RET_INT(0), inode_removexattr, struct mnt_idmap *idmap,
 	 struct dentry *dentry, const char *name)
-LSM_HOOK(int, 0, inode_set_acl, struct mnt_idmap *idmap,
+LSM_HOOK(int, LSM_RET_INT(0), inode_set_acl, struct mnt_idmap *idmap,
 	 struct dentry *dentry, const char *acl_name, struct posix_acl *kacl)
-LSM_HOOK(int, 0, inode_get_acl, struct mnt_idmap *idmap,
+LSM_HOOK(int, LSM_RET_INT(0), inode_get_acl, struct mnt_idmap *idmap,
 	 struct dentry *dentry, const char *acl_name)
-LSM_HOOK(int, 0, inode_remove_acl, struct mnt_idmap *idmap,
+LSM_HOOK(int, LSM_RET_INT(0), inode_remove_acl, struct mnt_idmap *idmap,
 	 struct dentry *dentry, const char *acl_name)
-LSM_HOOK(int, 0, inode_need_killpriv, struct dentry *dentry)
-LSM_HOOK(int, 0, inode_killpriv, struct mnt_idmap *idmap,
+LSM_HOOK(int, LSM_RET_INT(0), inode_need_killpriv, struct dentry *dentry)
+LSM_HOOK(int, LSM_RET_INT(0), inode_killpriv, struct mnt_idmap *idmap,
 	 struct dentry *dentry)
-LSM_HOOK(int, -EOPNOTSUPP, inode_getsecurity, struct mnt_idmap *idmap,
+LSM_HOOK(int, LSM_RET_INT(-EOPNOTSUPP), inode_getsecurity, struct mnt_idmap *idmap,
 	 struct inode *inode, const char *name, void **buffer, bool alloc)
-LSM_HOOK(int, -EOPNOTSUPP, inode_setsecurity, struct inode *inode,
+LSM_HOOK(int, LSM_RET_INT(-EOPNOTSUPP), inode_setsecurity, struct inode *inode,
 	 const char *name, const void *value, size_t size, int flags)
-LSM_HOOK(int, 0, inode_listsecurity, struct inode *inode, char *buffer,
+LSM_HOOK(int, LSM_RET_INT(0), inode_listsecurity, struct inode *inode, char *buffer,
 	 size_t buffer_size)
 LSM_HOOK(void, LSM_RET_VOID, inode_getsecid, struct inode *inode, u32 *secid)
-LSM_HOOK(int, 0, inode_copy_up, struct dentry *src, struct cred **new)
-LSM_HOOK(int, -EOPNOTSUPP, inode_copy_up_xattr, const char *name)
-LSM_HOOK(int, 0, kernfs_init_security, struct kernfs_node *kn_dir,
+LSM_HOOK(int, LSM_RET_INT(0), inode_copy_up, struct dentry *src, struct cred **new)
+LSM_HOOK(int, LSM_RET_INT(-EOPNOTSUPP), inode_copy_up_xattr, const char *name)
+LSM_HOOK(int, LSM_RET_INT(0), kernfs_init_security, struct kernfs_node *kn_dir,
 	 struct kernfs_node *kn)
-LSM_HOOK(int, 0, file_permission, struct file *file, int mask)
-LSM_HOOK(int, 0, file_alloc_security, struct file *file)
+LSM_HOOK(int, LSM_RET_INT(0), file_permission, struct file *file, int mask)
+LSM_HOOK(int, LSM_RET_INT(0), file_alloc_security, struct file *file)
 LSM_HOOK(void, LSM_RET_VOID, file_free_security, struct file *file)
-LSM_HOOK(int, 0, file_ioctl, struct file *file, unsigned int cmd,
+LSM_HOOK(int, LSM_RET_INT(0), file_ioctl, struct file *file, unsigned int cmd,
 	 unsigned long arg)
-LSM_HOOK(int, 0, file_ioctl_compat, struct file *file, unsigned int cmd,
+LSM_HOOK(int, LSM_RET_INT(0), file_ioctl_compat, struct file *file, unsigned int cmd,
 	 unsigned long arg)
-LSM_HOOK(int, 0, mmap_addr, unsigned long addr)
-LSM_HOOK(int, 0, mmap_file, struct file *file, unsigned long reqprot,
+LSM_HOOK(int, LSM_RET_INT(0), mmap_addr, unsigned long addr)
+LSM_HOOK(int, LSM_RET_INT(0), mmap_file, struct file *file, unsigned long reqprot,
 	 unsigned long prot, unsigned long flags)
-LSM_HOOK(int, 0, file_mprotect, struct vm_area_struct *vma,
+LSM_HOOK(int, LSM_RET_INT(0), file_mprotect, struct vm_area_struct *vma,
 	 unsigned long reqprot, unsigned long prot)
-LSM_HOOK(int, 0, file_lock, struct file *file, unsigned int cmd)
-LSM_HOOK(int, 0, file_fcntl, struct file *file, unsigned int cmd,
+LSM_HOOK(int, LSM_RET_INT(0), file_lock, struct file *file, unsigned int cmd)
+LSM_HOOK(int, LSM_RET_INT(0), file_fcntl, struct file *file, unsigned int cmd,
 	 unsigned long arg)
 LSM_HOOK(void, LSM_RET_VOID, file_set_fowner, struct file *file)
-LSM_HOOK(int, 0, file_send_sigiotask, struct task_struct *tsk,
+LSM_HOOK(int, LSM_RET_INT(0), file_send_sigiotask, struct task_struct *tsk,
 	 struct fown_struct *fown, int sig)
-LSM_HOOK(int, 0, file_receive, struct file *file)
-LSM_HOOK(int, 0, file_open, struct file *file)
-LSM_HOOK(int, 0, file_truncate, struct file *file)
-LSM_HOOK(int, 0, task_alloc, struct task_struct *task,
+LSM_HOOK(int, LSM_RET_INT(0), file_receive, struct file *file)
+LSM_HOOK(int, LSM_RET_INT(0), file_open, struct file *file)
+LSM_HOOK(int, LSM_RET_INT(0), file_truncate, struct file *file)
+LSM_HOOK(int, LSM_RET_INT(0), task_alloc, struct task_struct *task,
 	 unsigned long clone_flags)
 LSM_HOOK(void, LSM_RET_VOID, task_free, struct task_struct *task)
-LSM_HOOK(int, 0, cred_alloc_blank, struct cred *cred, gfp_t gfp)
+LSM_HOOK(int, LSM_RET_INT(0), cred_alloc_blank, struct cred *cred, gfp_t gfp)
 LSM_HOOK(void, LSM_RET_VOID, cred_free, struct cred *cred)
-LSM_HOOK(int, 0, cred_prepare, struct cred *new, const struct cred *old,
+LSM_HOOK(int, LSM_RET_INT(0), cred_prepare, struct cred *new, const struct cred *old,
 	 gfp_t gfp)
 LSM_HOOK(void, LSM_RET_VOID, cred_transfer, struct cred *new,
 	 const struct cred *old)
 LSM_HOOK(void, LSM_RET_VOID, cred_getsecid, const struct cred *c, u32 *secid)
-LSM_HOOK(int, 0, kernel_act_as, struct cred *new, u32 secid)
-LSM_HOOK(int, 0, kernel_create_files_as, struct cred *new, struct inode *inode)
-LSM_HOOK(int, 0, kernel_module_request, char *kmod_name)
-LSM_HOOK(int, 0, kernel_load_data, enum kernel_load_data_id id, bool contents)
-LSM_HOOK(int, 0, kernel_post_load_data, char *buf, loff_t size,
+LSM_HOOK(int, LSM_RET_INT(0), kernel_act_as, struct cred *new, u32 secid)
+LSM_HOOK(int, LSM_RET_INT(0), kernel_create_files_as, struct cred *new, struct inode *inode)
+LSM_HOOK(int, LSM_RET_INT(0), kernel_module_request, char *kmod_name)
+LSM_HOOK(int, LSM_RET_INT(0), kernel_load_data, enum kernel_load_data_id id, bool contents)
+LSM_HOOK(int, LSM_RET_INT(0), kernel_post_load_data, char *buf, loff_t size,
 	 enum kernel_load_data_id id, char *description)
-LSM_HOOK(int, 0, kernel_read_file, struct file *file,
+LSM_HOOK(int, LSM_RET_INT(0), kernel_read_file, struct file *file,
 	 enum kernel_read_file_id id, bool contents)
-LSM_HOOK(int, 0, kernel_post_read_file, struct file *file, char *buf,
+LSM_HOOK(int, LSM_RET_INT(0), kernel_post_read_file, struct file *file, char *buf,
 	 loff_t size, enum kernel_read_file_id id)
-LSM_HOOK(int, 0, task_fix_setuid, struct cred *new, const struct cred *old,
+LSM_HOOK(int, LSM_RET_INT(0), task_fix_setuid, struct cred *new, const struct cred *old,
 	 int flags)
-LSM_HOOK(int, 0, task_fix_setgid, struct cred *new, const struct cred * old,
+LSM_HOOK(int, LSM_RET_INT(0), task_fix_setgid, struct cred *new, const struct cred *old,
 	 int flags)
-LSM_HOOK(int, 0, task_fix_setgroups, struct cred *new, const struct cred * old)
-LSM_HOOK(int, 0, task_setpgid, struct task_struct *p, pid_t pgid)
-LSM_HOOK(int, 0, task_getpgid, struct task_struct *p)
-LSM_HOOK(int, 0, task_getsid, struct task_struct *p)
+LSM_HOOK(int, LSM_RET_INT(0), task_fix_setgroups, struct cred *new, const struct cred *old)
+LSM_HOOK(int, LSM_RET_INT(0), task_setpgid, struct task_struct *p, pid_t pgid)
+LSM_HOOK(int, LSM_RET_INT(0), task_getpgid, struct task_struct *p)
+LSM_HOOK(int, LSM_RET_INT(0), task_getsid, struct task_struct *p)
 LSM_HOOK(void, LSM_RET_VOID, current_getsecid_subj, u32 *secid)
 LSM_HOOK(void, LSM_RET_VOID, task_getsecid_obj,
 	 struct task_struct *p, u32 *secid)
-LSM_HOOK(int, 0, task_setnice, struct task_struct *p, int nice)
-LSM_HOOK(int, 0, task_setioprio, struct task_struct *p, int ioprio)
-LSM_HOOK(int, 0, task_getioprio, struct task_struct *p)
-LSM_HOOK(int, 0, task_prlimit, const struct cred *cred,
+LSM_HOOK(int, LSM_RET_INT(0), task_setnice, struct task_struct *p, int nice)
+LSM_HOOK(int, LSM_RET_INT(0), task_setioprio, struct task_struct *p, int ioprio)
+LSM_HOOK(int, LSM_RET_INT(0), task_getioprio, struct task_struct *p)
+LSM_HOOK(int, LSM_RET_INT(0), task_prlimit, const struct cred *cred,
 	 const struct cred *tcred, unsigned int flags)
-LSM_HOOK(int, 0, task_setrlimit, struct task_struct *p, unsigned int resource,
+LSM_HOOK(int, LSM_RET_INT(0), task_setrlimit, struct task_struct *p, unsigned int resource,
 	 struct rlimit *new_rlim)
-LSM_HOOK(int, 0, task_setscheduler, struct task_struct *p)
-LSM_HOOK(int, 0, task_getscheduler, struct task_struct *p)
-LSM_HOOK(int, 0, task_movememory, struct task_struct *p)
-LSM_HOOK(int, 0, task_kill, struct task_struct *p, struct kernel_siginfo *info,
+LSM_HOOK(int, LSM_RET_INT(0), task_setscheduler, struct task_struct *p)
+LSM_HOOK(int, LSM_RET_INT(0), task_getscheduler, struct task_struct *p)
+LSM_HOOK(int, LSM_RET_INT(0), task_movememory, struct task_struct *p)
+LSM_HOOK(int, LSM_RET_INT(0), task_kill, struct task_struct *p, struct kernel_siginfo *info,
 	 int sig, const struct cred *cred)
-LSM_HOOK(int, -ENOSYS, task_prctl, int option, unsigned long arg2,
+LSM_HOOK(int, LSM_RET_INT(-ENOSYS), task_prctl, int option, unsigned long arg2,
 	 unsigned long arg3, unsigned long arg4, unsigned long arg5)
 LSM_HOOK(void, LSM_RET_VOID, task_to_inode, struct task_struct *p,
 	 struct inode *inode)
-LSM_HOOK(int, 0, userns_create, const struct cred *cred)
-LSM_HOOK(int, 0, ipc_permission, struct kern_ipc_perm *ipcp, short flag)
+LSM_HOOK(int, LSM_RET_INT(0), userns_create, const struct cred *cred)
+LSM_HOOK(int, LSM_RET_INT(0), ipc_permission, struct kern_ipc_perm *ipcp, short flag)
 LSM_HOOK(void, LSM_RET_VOID, ipc_getsecid, struct kern_ipc_perm *ipcp,
 	 u32 *secid)
-LSM_HOOK(int, 0, msg_msg_alloc_security, struct msg_msg *msg)
+LSM_HOOK(int, LSM_RET_INT(0), msg_msg_alloc_security, struct msg_msg *msg)
 LSM_HOOK(void, LSM_RET_VOID, msg_msg_free_security, struct msg_msg *msg)
-LSM_HOOK(int, 0, msg_queue_alloc_security, struct kern_ipc_perm *perm)
+LSM_HOOK(int, LSM_RET_INT(0), msg_queue_alloc_security, struct kern_ipc_perm *perm)
 LSM_HOOK(void, LSM_RET_VOID, msg_queue_free_security,
 	 struct kern_ipc_perm *perm)
-LSM_HOOK(int, 0, msg_queue_associate, struct kern_ipc_perm *perm, int msqflg)
-LSM_HOOK(int, 0, msg_queue_msgctl, struct kern_ipc_perm *perm, int cmd)
-LSM_HOOK(int, 0, msg_queue_msgsnd, struct kern_ipc_perm *perm,
+LSM_HOOK(int, LSM_RET_INT(0), msg_queue_associate, struct kern_ipc_perm *perm, int msqflg)
+LSM_HOOK(int, LSM_RET_INT(0), msg_queue_msgctl, struct kern_ipc_perm *perm, int cmd)
+LSM_HOOK(int, LSM_RET_INT(0), msg_queue_msgsnd, struct kern_ipc_perm *perm,
 	 struct msg_msg *msg, int msqflg)
-LSM_HOOK(int, 0, msg_queue_msgrcv, struct kern_ipc_perm *perm,
+LSM_HOOK(int, LSM_RET_INT(0), msg_queue_msgrcv, struct kern_ipc_perm *perm,
 	 struct msg_msg *msg, struct task_struct *target, long type, int mode)
-LSM_HOOK(int, 0, shm_alloc_security, struct kern_ipc_perm *perm)
+LSM_HOOK(int, LSM_RET_INT(0), shm_alloc_security, struct kern_ipc_perm *perm)
 LSM_HOOK(void, LSM_RET_VOID, shm_free_security, struct kern_ipc_perm *perm)
-LSM_HOOK(int, 0, shm_associate, struct kern_ipc_perm *perm, int shmflg)
-LSM_HOOK(int, 0, shm_shmctl, struct kern_ipc_perm *perm, int cmd)
-LSM_HOOK(int, 0, shm_shmat, struct kern_ipc_perm *perm, char __user *shmaddr,
+LSM_HOOK(int, LSM_RET_INT(0), shm_associate, struct kern_ipc_perm *perm, int shmflg)
+LSM_HOOK(int, LSM_RET_INT(0), shm_shmctl, struct kern_ipc_perm *perm, int cmd)
+LSM_HOOK(int, LSM_RET_INT(0), shm_shmat, struct kern_ipc_perm *perm, char __user *shmaddr,
 	 int shmflg)
-LSM_HOOK(int, 0, sem_alloc_security, struct kern_ipc_perm *perm)
+LSM_HOOK(int, LSM_RET_INT(0), sem_alloc_security, struct kern_ipc_perm *perm)
 LSM_HOOK(void, LSM_RET_VOID, sem_free_security, struct kern_ipc_perm *perm)
-LSM_HOOK(int, 0, sem_associate, struct kern_ipc_perm *perm, int semflg)
-LSM_HOOK(int, 0, sem_semctl, struct kern_ipc_perm *perm, int cmd)
-LSM_HOOK(int, 0, sem_semop, struct kern_ipc_perm *perm, struct sembuf *sops,
+LSM_HOOK(int, LSM_RET_INT(0), sem_associate, struct kern_ipc_perm *perm, int semflg)
+LSM_HOOK(int, LSM_RET_INT(0), sem_semctl, struct kern_ipc_perm *perm, int cmd)
+LSM_HOOK(int, LSM_RET_INT(0), sem_semop, struct kern_ipc_perm *perm, struct sembuf *sops,
 	 unsigned nsops, int alter)
-LSM_HOOK(int, 0, netlink_send, struct sock *sk, struct sk_buff *skb)
+LSM_HOOK(int, LSM_RET_INT(0), netlink_send, struct sock *sk, struct sk_buff *skb)
 LSM_HOOK(void, LSM_RET_VOID, d_instantiate, struct dentry *dentry,
 	 struct inode *inode)
-LSM_HOOK(int, -EOPNOTSUPP, getselfattr, unsigned int attr,
+LSM_HOOK(int, LSM_RET_INT(-EOPNOTSUPP), getselfattr, unsigned int attr,
 	 struct lsm_ctx __user *ctx, size_t *size, u32 flags)
-LSM_HOOK(int, -EOPNOTSUPP, setselfattr, unsigned int attr,
+LSM_HOOK(int, LSM_RET_INT(-EOPNOTSUPP), setselfattr, unsigned int attr,
 	 struct lsm_ctx *ctx, size_t size, u32 flags)
-LSM_HOOK(int, -EINVAL, getprocattr, struct task_struct *p, const char *name,
+LSM_HOOK(int, LSM_RET_INT(-EINVAL), getprocattr, struct task_struct *p, const char *name,
 	 char **value)
-LSM_HOOK(int, -EINVAL, setprocattr, const char *name, void *value, size_t size)
-LSM_HOOK(int, 0, ismaclabel, const char *name)
-LSM_HOOK(int, -EOPNOTSUPP, secid_to_secctx, u32 secid, char **secdata,
+LSM_HOOK(int, LSM_RET_INT(-EINVAL), setprocattr, const char *name, void *value, size_t size)
+LSM_HOOK(int, LSM_RET_INT(0), ismaclabel, const char *name)
+LSM_HOOK(int, LSM_RET_INT(-EOPNOTSUPP), secid_to_secctx, u32 secid, char **secdata,
 	 u32 *seclen)
-LSM_HOOK(int, 0, secctx_to_secid, const char *secdata, u32 seclen, u32 *secid)
+LSM_HOOK(int, LSM_RET_INT(0), secctx_to_secid, const char *secdata, u32 seclen, u32 *secid)
 LSM_HOOK(void, LSM_RET_VOID, release_secctx, char *secdata, u32 seclen)
 LSM_HOOK(void, LSM_RET_VOID, inode_invalidate_secctx, struct inode *inode)
-LSM_HOOK(int, 0, inode_notifysecctx, struct inode *inode, void *ctx, u32 ctxlen)
-LSM_HOOK(int, 0, inode_setsecctx, struct dentry *dentry, void *ctx, u32 ctxlen)
-LSM_HOOK(int, -EOPNOTSUPP, inode_getsecctx, struct inode *inode, void **ctx,
+LSM_HOOK(int, LSM_RET_INT(0), inode_notifysecctx, struct inode *inode, void *ctx, u32 ctxlen)
+LSM_HOOK(int, LSM_RET_INT(0), inode_setsecctx, struct dentry *dentry, void *ctx, u32 ctxlen)
+LSM_HOOK(int, LSM_RET_INT(-EOPNOTSUPP), inode_getsecctx, struct inode *inode, void **ctx,
 	 u32 *ctxlen)
 
 #if defined(CONFIG_SECURITY) && defined(CONFIG_WATCH_QUEUE)
-LSM_HOOK(int, 0, post_notification, const struct cred *w_cred,
+LSM_HOOK(int, LSM_RET_INT(0), post_notification, const struct cred *w_cred,
 	 const struct cred *cred, struct watch_notification *n)
 #endif /* CONFIG_SECURITY && CONFIG_WATCH_QUEUE */
 
 #if defined(CONFIG_SECURITY) && defined(CONFIG_KEY_NOTIFICATIONS)
-LSM_HOOK(int, 0, watch_key, struct key *key)
+LSM_HOOK(int, LSM_RET_INT(0), watch_key, struct key *key)
 #endif /* CONFIG_SECURITY && CONFIG_KEY_NOTIFICATIONS */
 
 #ifdef CONFIG_SECURITY_NETWORK
-LSM_HOOK(int, 0, unix_stream_connect, struct sock *sock, struct sock *other,
+LSM_HOOK(int, LSM_RET_INT(0), unix_stream_connect, struct sock *sock, struct sock *other,
 	 struct sock *newsk)
-LSM_HOOK(int, 0, unix_may_send, struct socket *sock, struct socket *other)
-LSM_HOOK(int, 0, socket_create, int family, int type, int protocol, int kern)
-LSM_HOOK(int, 0, socket_post_create, struct socket *sock, int family, int type,
+LSM_HOOK(int, LSM_RET_INT(0), unix_may_send, struct socket *sock, struct socket *other)
+LSM_HOOK(int, LSM_RET_INT(0), socket_create, int family, int type, int protocol, int kern)
+LSM_HOOK(int, LSM_RET_INT(0), socket_post_create, struct socket *sock, int family, int type,
 	 int protocol, int kern)
-LSM_HOOK(int, 0, socket_socketpair, struct socket *socka, struct socket *sockb)
-LSM_HOOK(int, 0, socket_bind, struct socket *sock, struct sockaddr *address,
+LSM_HOOK(int, LSM_RET_INT(0), socket_socketpair, struct socket *socka, struct socket *sockb)
+LSM_HOOK(int, LSM_RET_INT(0), socket_bind, struct socket *sock, struct sockaddr *address,
 	 int addrlen)
-LSM_HOOK(int, 0, socket_connect, struct socket *sock, struct sockaddr *address,
+LSM_HOOK(int, LSM_RET_INT(0), socket_connect, struct socket *sock, struct sockaddr *address,
 	 int addrlen)
-LSM_HOOK(int, 0, socket_listen, struct socket *sock, int backlog)
-LSM_HOOK(int, 0, socket_accept, struct socket *sock, struct socket *newsock)
-LSM_HOOK(int, 0, socket_sendmsg, struct socket *sock, struct msghdr *msg,
+LSM_HOOK(int, LSM_RET_INT(0), socket_listen, struct socket *sock, int backlog)
+LSM_HOOK(int, LSM_RET_INT(0), socket_accept, struct socket *sock, struct socket *newsock)
+LSM_HOOK(int, LSM_RET_INT(0), socket_sendmsg, struct socket *sock, struct msghdr *msg,
 	 int size)
-LSM_HOOK(int, 0, socket_recvmsg, struct socket *sock, struct msghdr *msg,
+LSM_HOOK(int, LSM_RET_INT(0), socket_recvmsg, struct socket *sock, struct msghdr *msg,
 	 int size, int flags)
-LSM_HOOK(int, 0, socket_getsockname, struct socket *sock)
-LSM_HOOK(int, 0, socket_getpeername, struct socket *sock)
-LSM_HOOK(int, 0, socket_getsockopt, struct socket *sock, int level, int optname)
-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, -ENOPROTOOPT, socket_getpeersec_stream, struct socket *sock,
+LSM_HOOK(int, LSM_RET_INT(0), socket_getsockname, struct socket *sock)
+LSM_HOOK(int, LSM_RET_INT(0), socket_getpeername, struct socket *sock)
+LSM_HOOK(int, LSM_RET_INT(0), socket_getsockopt, struct socket *sock, int level, int optname)
+LSM_HOOK(int, LSM_RET_INT(0), socket_setsockopt, struct socket *sock, int level, int optname)
+LSM_HOOK(int, LSM_RET_INT(0), socket_shutdown, struct socket *sock, int how)
+LSM_HOOK(int, LSM_RET_INT(0), socket_sock_rcv_skb, struct sock *sk, struct sk_buff *skb)
+LSM_HOOK(int, LSM_RET_INT(-ENOPROTOOPT), socket_getpeersec_stream, struct socket *sock,
 	 sockptr_t optval, sockptr_t optlen, unsigned int len)
-LSM_HOOK(int, -ENOPROTOOPT, socket_getpeersec_dgram, struct socket *sock,
+LSM_HOOK(int, LSM_RET_INT(-ENOPROTOOPT), 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)
+LSM_HOOK(int, LSM_RET_INT(0), sk_alloc_security, struct sock *sk, int family, gfp_t priority)
 LSM_HOOK(void, LSM_RET_VOID, sk_free_security, struct sock *sk)
 LSM_HOOK(void, LSM_RET_VOID, sk_clone_security, const struct sock *sk,
 	 struct sock *newsk)
 LSM_HOOK(void, LSM_RET_VOID, sk_getsecid, const struct sock *sk, u32 *secid)
 LSM_HOOK(void, LSM_RET_VOID, sock_graft, struct sock *sk, struct socket *parent)
-LSM_HOOK(int, 0, inet_conn_request, const struct sock *sk, struct sk_buff *skb,
+LSM_HOOK(int, LSM_RET_INT(0), inet_conn_request, const struct sock *sk, struct sk_buff *skb,
 	 struct request_sock *req)
 LSM_HOOK(void, LSM_RET_VOID, inet_csk_clone, struct sock *newsk,
 	 const struct request_sock *req)
 LSM_HOOK(void, LSM_RET_VOID, inet_conn_established, struct sock *sk,
 	 struct sk_buff *skb)
-LSM_HOOK(int, 0, secmark_relabel_packet, u32 secid)
+LSM_HOOK(int, LSM_RET_INT(0), secmark_relabel_packet, u32 secid)
 LSM_HOOK(void, LSM_RET_VOID, secmark_refcount_inc, void)
 LSM_HOOK(void, LSM_RET_VOID, secmark_refcount_dec, void)
 LSM_HOOK(void, LSM_RET_VOID, req_classify_flow, const struct request_sock *req,
 	 struct flowi_common *flic)
-LSM_HOOK(int, 0, tun_dev_alloc_security, void **security)
+LSM_HOOK(int, LSM_RET_INT(0), tun_dev_alloc_security, void **security)
 LSM_HOOK(void, LSM_RET_VOID, tun_dev_free_security, void *security)
-LSM_HOOK(int, 0, tun_dev_create, void)
-LSM_HOOK(int, 0, tun_dev_attach_queue, void *security)
-LSM_HOOK(int, 0, tun_dev_attach, struct sock *sk, void *security)
-LSM_HOOK(int, 0, tun_dev_open, void *security)
-LSM_HOOK(int, 0, sctp_assoc_request, struct sctp_association *asoc,
+LSM_HOOK(int, LSM_RET_INT(0), tun_dev_create, void)
+LSM_HOOK(int, LSM_RET_INT(0), tun_dev_attach_queue, void *security)
+LSM_HOOK(int, LSM_RET_INT(0), tun_dev_attach, struct sock *sk, void *security)
+LSM_HOOK(int, LSM_RET_INT(0), tun_dev_open, void *security)
+LSM_HOOK(int, LSM_RET_INT(0), sctp_assoc_request, struct sctp_association *asoc,
 	 struct sk_buff *skb)
-LSM_HOOK(int, 0, sctp_bind_connect, struct sock *sk, int optname,
+LSM_HOOK(int, LSM_RET_INT(0), sctp_bind_connect, struct sock *sk, int optname,
 	 struct sockaddr *address, int addrlen)
 LSM_HOOK(void, LSM_RET_VOID, sctp_sk_clone, struct sctp_association *asoc,
 	 struct sock *sk, struct sock *newsk)
-LSM_HOOK(int, 0, sctp_assoc_established, struct sctp_association *asoc,
+LSM_HOOK(int, LSM_RET_INT(0), sctp_assoc_established, struct sctp_association *asoc,
 	 struct sk_buff *skb)
-LSM_HOOK(int, 0, mptcp_add_subflow, struct sock *sk, struct sock *ssk)
+LSM_HOOK(int, LSM_RET_INT(0), mptcp_add_subflow, struct sock *sk, struct sock *ssk)
 #endif /* CONFIG_SECURITY_NETWORK */
 
 #ifdef CONFIG_SECURITY_INFINIBAND
-LSM_HOOK(int, 0, ib_pkey_access, void *sec, u64 subnet_prefix, u16 pkey)
-LSM_HOOK(int, 0, ib_endport_manage_subnet, void *sec, const char *dev_name,
+LSM_HOOK(int, LSM_RET_INT(0), ib_pkey_access, void *sec, u64 subnet_prefix, u16 pkey)
+LSM_HOOK(int, LSM_RET_INT(0), ib_endport_manage_subnet, void *sec, const char *dev_name,
 	 u8 port_num)
-LSM_HOOK(int, 0, ib_alloc_security, void **sec)
+LSM_HOOK(int, LSM_RET_INT(0), ib_alloc_security, void **sec)
 LSM_HOOK(void, LSM_RET_VOID, ib_free_security, void *sec)
 #endif /* CONFIG_SECURITY_INFINIBAND */
 
 #ifdef CONFIG_SECURITY_NETWORK_XFRM
-LSM_HOOK(int, 0, xfrm_policy_alloc_security, struct xfrm_sec_ctx **ctxp,
+LSM_HOOK(int, LSM_RET_INT(0), xfrm_policy_alloc_security, struct xfrm_sec_ctx **ctxp,
 	 struct xfrm_user_sec_ctx *sec_ctx, gfp_t gfp)
-LSM_HOOK(int, 0, xfrm_policy_clone_security, struct xfrm_sec_ctx *old_ctx,
+LSM_HOOK(int, LSM_RET_INT(0), xfrm_policy_clone_security, struct xfrm_sec_ctx *old_ctx,
 	 struct xfrm_sec_ctx **new_ctx)
 LSM_HOOK(void, LSM_RET_VOID, xfrm_policy_free_security,
 	 struct xfrm_sec_ctx *ctx)
-LSM_HOOK(int, 0, xfrm_policy_delete_security, struct xfrm_sec_ctx *ctx)
-LSM_HOOK(int, 0, xfrm_state_alloc, struct xfrm_state *x,
+LSM_HOOK(int, LSM_RET_INT(0), xfrm_policy_delete_security, struct xfrm_sec_ctx *ctx)
+LSM_HOOK(int, LSM_RET_INT(0), xfrm_state_alloc, struct xfrm_state *x,
 	 struct xfrm_user_sec_ctx *sec_ctx)
-LSM_HOOK(int, 0, xfrm_state_alloc_acquire, struct xfrm_state *x,
+LSM_HOOK(int, LSM_RET_INT(0), xfrm_state_alloc_acquire, struct xfrm_state *x,
 	 struct xfrm_sec_ctx *polsec, u32 secid)
 LSM_HOOK(void, LSM_RET_VOID, xfrm_state_free_security, struct xfrm_state *x)
-LSM_HOOK(int, 0, xfrm_state_delete_security, struct xfrm_state *x)
-LSM_HOOK(int, 0, xfrm_policy_lookup, struct xfrm_sec_ctx *ctx, u32 fl_secid)
-LSM_HOOK(int, 1, xfrm_state_pol_flow_match, struct xfrm_state *x,
+LSM_HOOK(int, LSM_RET_INT(0), xfrm_state_delete_security, struct xfrm_state *x)
+LSM_HOOK(int, LSM_RET_INT(0), xfrm_policy_lookup, struct xfrm_sec_ctx *ctx, u32 fl_secid)
+LSM_HOOK(int, LSM_RET_INT(1), xfrm_state_pol_flow_match, struct xfrm_state *x,
 	 struct xfrm_policy *xp, const struct flowi_common *flic)
-LSM_HOOK(int, 0, xfrm_decode_session, struct sk_buff *skb, u32 *secid,
+LSM_HOOK(int, LSM_RET_INT(0), xfrm_decode_session, struct sk_buff *skb, u32 *secid,
 	 int ckall)
 #endif /* CONFIG_SECURITY_NETWORK_XFRM */
 
 /* key management security hooks */
 #ifdef CONFIG_KEYS
-LSM_HOOK(int, 0, key_alloc, struct key *key, const struct cred *cred,
+LSM_HOOK(int, LSM_RET_INT(0), key_alloc, struct key *key, const struct cred *cred,
 	 unsigned long flags)
 LSM_HOOK(void, LSM_RET_VOID, key_free, struct key *key)
-LSM_HOOK(int, 0, key_permission, key_ref_t key_ref, const struct cred *cred,
+LSM_HOOK(int, LSM_RET_INT(0), key_permission, key_ref_t key_ref, const struct cred *cred,
 	 enum key_need_perm need_perm)
-LSM_HOOK(int, 0, key_getsecurity, struct key *key, char **buffer)
+LSM_HOOK(int, LSM_RET_INT(0), key_getsecurity, struct key *key, char **buffer)
 #endif /* CONFIG_KEYS */
 
 #ifdef CONFIG_AUDIT
-LSM_HOOK(int, 0, audit_rule_init, u32 field, u32 op, char *rulestr,
+LSM_HOOK(int, LSM_RET_INT(0), audit_rule_init, u32 field, u32 op, char *rulestr,
 	 void **lsmrule)
-LSM_HOOK(int, 0, audit_rule_known, struct audit_krule *krule)
-LSM_HOOK(int, 0, audit_rule_match, u32 secid, u32 field, u32 op, void *lsmrule)
+LSM_HOOK(int, LSM_RET_INT(0), audit_rule_known, struct audit_krule *krule)
+LSM_HOOK(int, LSM_RET_INT(0), audit_rule_match, u32 secid, u32 field, u32 op, void *lsmrule)
 LSM_HOOK(void, LSM_RET_VOID, audit_rule_free, void *lsmrule)
 #endif /* CONFIG_AUDIT */
 
 #ifdef CONFIG_BPF_SYSCALL
-LSM_HOOK(int, 0, bpf, int cmd, union bpf_attr *attr, unsigned int size)
-LSM_HOOK(int, 0, bpf_map, struct bpf_map *map, fmode_t fmode)
-LSM_HOOK(int, 0, bpf_prog, struct bpf_prog *prog)
-LSM_HOOK(int, 0, bpf_map_create, struct bpf_map *map, union bpf_attr *attr,
+LSM_HOOK(int, LSM_RET_INT(0), bpf, int cmd, union bpf_attr *attr, unsigned int size)
+LSM_HOOK(int, LSM_RET_INT(0), bpf_map, struct bpf_map *map, fmode_t fmode)
+LSM_HOOK(int, LSM_RET_INT(0), bpf_prog, struct bpf_prog *prog)
+LSM_HOOK(int, LSM_RET_INT(0), bpf_map_create, struct bpf_map *map, union bpf_attr *attr,
 	 struct bpf_token *token)
 LSM_HOOK(void, LSM_RET_VOID, bpf_map_free, struct bpf_map *map)
-LSM_HOOK(int, 0, bpf_prog_load, struct bpf_prog *prog, union bpf_attr *attr,
+LSM_HOOK(int, LSM_RET_INT(0), bpf_prog_load, struct bpf_prog *prog, union bpf_attr *attr,
 	 struct bpf_token *token)
 LSM_HOOK(void, LSM_RET_VOID, bpf_prog_free, struct bpf_prog *prog)
-LSM_HOOK(int, 0, bpf_token_create, struct bpf_token *token, union bpf_attr *attr,
+LSM_HOOK(int, LSM_RET_INT(0), bpf_token_create, struct bpf_token *token, union bpf_attr *attr,
 	 struct path *path)
 LSM_HOOK(void, LSM_RET_VOID, bpf_token_free, struct bpf_token *token)
-LSM_HOOK(int, 0, bpf_token_cmd, const struct bpf_token *token, enum bpf_cmd cmd)
-LSM_HOOK(int, 0, bpf_token_capable, const struct bpf_token *token, int cap)
+LSM_HOOK(int, LSM_RET_INT(0), bpf_token_cmd, const struct bpf_token *token, enum bpf_cmd cmd)
+LSM_HOOK(int, LSM_RET_INT(0), bpf_token_capable, const struct bpf_token *token, int cap)
 #endif /* CONFIG_BPF_SYSCALL */
 
-LSM_HOOK(int, 0, locked_down, enum lockdown_reason what)
+LSM_HOOK(int, LSM_RET_INT(0), locked_down, enum lockdown_reason what)
 
 #ifdef CONFIG_PERF_EVENTS
-LSM_HOOK(int, 0, perf_event_open, struct perf_event_attr *attr, int type)
-LSM_HOOK(int, 0, perf_event_alloc, struct perf_event *event)
+LSM_HOOK(int, LSM_RET_INT(0), perf_event_open, struct perf_event_attr *attr, int type)
+LSM_HOOK(int, LSM_RET_INT(0), perf_event_alloc, struct perf_event *event)
 LSM_HOOK(void, LSM_RET_VOID, perf_event_free, struct perf_event *event)
-LSM_HOOK(int, 0, perf_event_read, struct perf_event *event)
-LSM_HOOK(int, 0, perf_event_write, struct perf_event *event)
+LSM_HOOK(int, LSM_RET_INT(0), perf_event_read, struct perf_event *event)
+LSM_HOOK(int, LSM_RET_INT(0), perf_event_write, struct perf_event *event)
 #endif /* CONFIG_PERF_EVENTS */
 
 #ifdef CONFIG_IO_URING
-LSM_HOOK(int, 0, uring_override_creds, const struct cred *new)
-LSM_HOOK(int, 0, uring_sqpoll, void)
-LSM_HOOK(int, 0, uring_cmd, struct io_uring_cmd *ioucmd)
+LSM_HOOK(int, LSM_RET_INT(0), uring_override_creds, const struct cred *new)
+LSM_HOOK(int, LSM_RET_INT(0), uring_sqpoll, void)
+LSM_HOOK(int, LSM_RET_INT(0), uring_cmd, struct io_uring_cmd *ioucmd)
 #endif /* CONFIG_IO_URING */
diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h
index a2ade0ffe9e7..14690cad4fb9 100644
--- a/include/linux/lsm_hooks.h
+++ b/include/linux/lsm_hooks.h
@@ -98,12 +98,6 @@ static inline struct xattr *lsm_get_xattr_slot(struct xattr *xattrs,
 	return &xattrs[(*xattr_count)++];
 }
 
-/*
- * LSM_RET_VOID is used as the default value in LSM_HOOK definitions for void
- * LSM hooks (in include/linux/lsm_hook_defs.h).
- */
-#define LSM_RET_VOID ((void) 0)
-
 /*
  * Initializing a security_hook_list structure takes
  * up a lot of space in a source file. This macro takes
diff --git a/kernel/bpf/bpf_lsm.c b/kernel/bpf/bpf_lsm.c
index 68240c3c6e7d..2185dc4c0aed 100644
--- a/kernel/bpf/bpf_lsm.c
+++ b/kernel/bpf/bpf_lsm.c
@@ -18,6 +18,14 @@
 #include <linux/ima.h>
 #include <linux/bpf-cgroup.h>
 
+/*
+ * LSM_RET_VOID is used as the default value in LSM_HOOK definitions for void
+ * LSM hooks (in include/linux/lsm_hook_defs.h).
+ */
+#define LSM_RET_VOID ((void) 0)
+
+#define LSM_RET_INT(defval) defval
+
 /* For every LSM hook that allows attachment of BPF programs, declare a nop
  * function where a BPF program can be attached.
  */
@@ -29,6 +37,8 @@ noinline RET bpf_lsm_##NAME(__VA_ARGS__)	\
 
 #include <linux/lsm_hook_defs.h>
 #undef LSM_HOOK
+#undef LSM_RET_INT
+#undef LSM_RET_VOID
 
 #define LSM_HOOK(RET, DEFAULT, NAME, ...) BTF_ID(func, bpf_lsm_##NAME)
 BTF_SET_START(bpf_lsm_hooks)
diff --git a/security/security.c b/security/security.c
index aef69632d0a9..72408a9f0822 100644
--- a/security/security.c
+++ b/security/security.c
@@ -828,6 +828,7 @@ int lsm_fill_user_ctx(struct lsm_ctx __user *uctx, size_t *uctx_len,
  * The macros below define static constants for the default value of each
  * LSM hook.
  */
+#define LSM_RET_INT(defval) defval
 #define LSM_RET_DEFAULT(NAME) (NAME##_default)
 #define DECLARE_LSM_RET_DEFAULT_void(DEFAULT, NAME)
 #define DECLARE_LSM_RET_DEFAULT_int(DEFAULT, NAME) \
-- 
2.30.2


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH bpf-next v2 2/7] bpf, lsm: Add return value range description for lsm hook
  2024-03-25  9:56 [PATCH bpf-next v2 0/7] Add check for bpf lsm return value Xu Kuohai
  2024-03-25  9:56 ` [PATCH bpf-next v2 1/7] bpf, lsm: Annotate lsm hook return integer with new macro LSM_RET_INT Xu Kuohai
@ 2024-03-25  9:56 ` Xu Kuohai
  2024-04-08 17:09   ` KP Singh
  2024-03-25  9:56 ` [PATCH bpf-next v2 3/7] bpf, lsm: Add function to read lsm hook return value range Xu Kuohai
                   ` (5 subsequent siblings)
  7 siblings, 1 reply; 13+ messages in thread
From: Xu Kuohai @ 2024-03-25  9:56 UTC (permalink / raw)
  To: bpf, linux-security-module
  Cc: Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko,
	Martin KaFai Lau, Eduard Zingerman, Song Liu, Yonghong Song,
	John Fastabend, KP Singh, Stanislav Fomichev, Hao Luo, Jiri Olsa,
	Florent Revest, Brendan Jackman, Paul Moore, James Morris,
	Serge E . Hallyn, Khadija Kamran, Casey Schaufler,
	Ondrej Mosnacek, Kees Cook, John Johansen, Lukas Bulwahn,
	Roberto Sassu, Shung-Hsi Yu

From: Xu Kuohai <xukuohai@huawei.com>

Add return value descriptions for lsm hook.

Two integer ranges are added:

1. ERRNO: Integer between -MAX_ERRNO and 0, including -MAX_ERRNO and 0.
2. ANY: Any integer

Signed-off-by: Xu Kuohai <xukuohai@huawei.com>
---
 include/linux/lsm_hook_defs.h | 431 +++++++++++++++++-----------------
 kernel/bpf/bpf_lsm.c          |   2 +-
 security/security.c           |   2 +-
 3 files changed, 218 insertions(+), 217 deletions(-)

diff --git a/include/linux/lsm_hook_defs.h b/include/linux/lsm_hook_defs.h
index 22b64b15faa8..f6a744910aa4 100644
--- a/include/linux/lsm_hook_defs.h
+++ b/include/linux/lsm_hook_defs.h
@@ -18,419 +18,420 @@
  * The macro LSM_HOOK is used to define the data structures required by
  * the LSM framework using the pattern:
  *
- *	LSM_HOOK(<return_type>, <default_value>, <hook_name>, args...)
+ *	LSM_HOOK(<return_type>, <return_description>, <hook_name>, args...)
  *
  * struct security_hook_heads {
- *   #define LSM_HOOK(RET, DEFAULT, NAME, ...) struct hlist_head NAME;
+ *   #define LSM_HOOK(RET, RETVAL_DESC, NAME, ...) struct hlist_head NAME;
  *   #include <linux/lsm_hook_defs.h>
  *   #undef LSM_HOOK
  * };
  */
-LSM_HOOK(int, LSM_RET_INT(0), binder_set_context_mgr, const struct cred *mgr)
-LSM_HOOK(int, LSM_RET_INT(0), binder_transaction, const struct cred *from,
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), binder_set_context_mgr, const struct cred *mgr)
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), binder_transaction, const struct cred *from,
 	 const struct cred *to)
-LSM_HOOK(int, LSM_RET_INT(0), binder_transfer_binder, const struct cred *from,
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), binder_transfer_binder, const struct cred *from,
 	 const struct cred *to)
-LSM_HOOK(int, LSM_RET_INT(0), binder_transfer_file, const struct cred *from,
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), binder_transfer_file, const struct cred *from,
 	 const struct cred *to, const struct file *file)
-LSM_HOOK(int, LSM_RET_INT(0), ptrace_access_check, struct task_struct *child,
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), ptrace_access_check, struct task_struct *child,
 	 unsigned int mode)
-LSM_HOOK(int, LSM_RET_INT(0), ptrace_traceme, struct task_struct *parent)
-LSM_HOOK(int, LSM_RET_INT(0), capget, const struct task_struct *target, kernel_cap_t *effective,
-	 kernel_cap_t *inheritable, kernel_cap_t *permitted)
-LSM_HOOK(int, LSM_RET_INT(0), capset, struct cred *new, const struct cred *old,
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), ptrace_traceme, struct task_struct *parent)
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), capget, const struct task_struct *target,
+	 kernel_cap_t *effective, kernel_cap_t *inheritable, kernel_cap_t *permitted)
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), capset, struct cred *new, const struct cred *old,
 	 const kernel_cap_t *effective, const kernel_cap_t *inheritable,
 	 const kernel_cap_t *permitted)
-LSM_HOOK(int, LSM_RET_INT(0), capable, const struct cred *cred, struct user_namespace *ns,
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), capable, const struct cred *cred, struct user_namespace *ns,
 	 int cap, unsigned int opts)
-LSM_HOOK(int, LSM_RET_INT(0), quotactl, int cmds, int type, int id, const struct super_block *sb)
-LSM_HOOK(int, LSM_RET_INT(0), quota_on, struct dentry *dentry)
-LSM_HOOK(int, LSM_RET_INT(0), syslog, int type)
-LSM_HOOK(int, LSM_RET_INT(0), settime, const struct timespec64 *ts,
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), quotactl, int cmds, int type, int id,
+	 const struct super_block *sb)
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), quota_on, struct dentry *dentry)
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), syslog, int type)
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), settime, const struct timespec64 *ts,
 	 const struct timezone *tz)
-LSM_HOOK(int, LSM_RET_INT(1), vm_enough_memory, struct mm_struct *mm, long pages)
-LSM_HOOK(int, LSM_RET_INT(0), bprm_creds_for_exec, struct linux_binprm *bprm)
-LSM_HOOK(int, LSM_RET_INT(0), bprm_creds_from_file, struct linux_binprm *bprm,
+LSM_HOOK(int, LSM_RET_INT(1, ANY), vm_enough_memory, struct mm_struct *mm, long pages)
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), bprm_creds_for_exec, struct linux_binprm *bprm)
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), bprm_creds_from_file, struct linux_binprm *bprm,
 	 const struct file *file)
-LSM_HOOK(int, LSM_RET_INT(0), bprm_check_security, struct linux_binprm *bprm)
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), bprm_check_security, struct linux_binprm *bprm)
 LSM_HOOK(void, LSM_RET_VOID, bprm_committing_creds, const struct linux_binprm *bprm)
 LSM_HOOK(void, LSM_RET_VOID, bprm_committed_creds, const struct linux_binprm *bprm)
-LSM_HOOK(int, LSM_RET_INT(0), fs_context_submount, struct fs_context *fc,
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), fs_context_submount, struct fs_context *fc,
 	 struct super_block *reference)
-LSM_HOOK(int, LSM_RET_INT(0), fs_context_dup, struct fs_context *fc,
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), fs_context_dup, struct fs_context *fc,
 	 struct fs_context *src_sc)
-LSM_HOOK(int, LSM_RET_INT(-ENOPARAM), fs_context_parse_param, struct fs_context *fc,
+LSM_HOOK(int, LSM_RET_INT(-ENOPARAM, ERRNO), fs_context_parse_param, struct fs_context *fc,
 	 struct fs_parameter *param)
-LSM_HOOK(int, LSM_RET_INT(0), sb_alloc_security, struct super_block *sb)
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), sb_alloc_security, struct super_block *sb)
 LSM_HOOK(void, LSM_RET_VOID, sb_delete, struct super_block *sb)
 LSM_HOOK(void, LSM_RET_VOID, sb_free_security, struct super_block *sb)
 LSM_HOOK(void, LSM_RET_VOID, sb_free_mnt_opts, void *mnt_opts)
-LSM_HOOK(int, LSM_RET_INT(0), sb_eat_lsm_opts, char *orig, void **mnt_opts)
-LSM_HOOK(int, LSM_RET_INT(0), sb_mnt_opts_compat, struct super_block *sb, void *mnt_opts)
-LSM_HOOK(int, LSM_RET_INT(0), sb_remount, struct super_block *sb, void *mnt_opts)
-LSM_HOOK(int, LSM_RET_INT(0), sb_kern_mount, const struct super_block *sb)
-LSM_HOOK(int, LSM_RET_INT(0), sb_show_options, struct seq_file *m, struct super_block *sb)
-LSM_HOOK(int, LSM_RET_INT(0), sb_statfs, struct dentry *dentry)
-LSM_HOOK(int, LSM_RET_INT(0), sb_mount, const char *dev_name, const struct path *path,
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), sb_eat_lsm_opts, char *orig, void **mnt_opts)
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), sb_mnt_opts_compat, struct super_block *sb, void *mnt_opts)
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), sb_remount, struct super_block *sb, void *mnt_opts)
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), sb_kern_mount, const struct super_block *sb)
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), sb_show_options, struct seq_file *m, struct super_block *sb)
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), sb_statfs, struct dentry *dentry)
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), sb_mount, const char *dev_name, const struct path *path,
 	 const char *type, unsigned long flags, void *data)
-LSM_HOOK(int, LSM_RET_INT(0), sb_umount, struct vfsmount *mnt, int flags)
-LSM_HOOK(int, LSM_RET_INT(0), sb_pivotroot, const struct path *old_path,
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), sb_umount, struct vfsmount *mnt, int flags)
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), sb_pivotroot, const struct path *old_path,
 	 const struct path *new_path)
-LSM_HOOK(int, LSM_RET_INT(0), sb_set_mnt_opts, struct super_block *sb, void *mnt_opts,
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), sb_set_mnt_opts, struct super_block *sb, void *mnt_opts,
 	 unsigned long kern_flags, unsigned long *set_kern_flags)
-LSM_HOOK(int, LSM_RET_INT(0), sb_clone_mnt_opts, const struct super_block *oldsb,
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), sb_clone_mnt_opts, const struct super_block *oldsb,
 	 struct super_block *newsb, unsigned long kern_flags,
 	 unsigned long *set_kern_flags)
-LSM_HOOK(int, LSM_RET_INT(0), move_mount, const struct path *from_path,
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), move_mount, const struct path *from_path,
 	 const struct path *to_path)
-LSM_HOOK(int, LSM_RET_INT(-EOPNOTSUPP), dentry_init_security, struct dentry *dentry,
+LSM_HOOK(int, LSM_RET_INT(-EOPNOTSUPP, ERRNO), dentry_init_security, struct dentry *dentry,
 	 int mode, const struct qstr *name, const char **xattr_name,
 	 void **ctx, u32 *ctxlen)
-LSM_HOOK(int, LSM_RET_INT(0), dentry_create_files_as, struct dentry *dentry, int mode,
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), dentry_create_files_as, struct dentry *dentry, int mode,
 	 struct qstr *name, const struct cred *old, struct cred *new)
 
 #ifdef CONFIG_SECURITY_PATH
-LSM_HOOK(int, LSM_RET_INT(0), path_unlink, const struct path *dir, struct dentry *dentry)
-LSM_HOOK(int, LSM_RET_INT(0), path_mkdir, const struct path *dir, struct dentry *dentry,
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), path_unlink, const struct path *dir, struct dentry *dentry)
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), path_mkdir, const struct path *dir, struct dentry *dentry,
 	 umode_t mode)
-LSM_HOOK(int, LSM_RET_INT(0), path_rmdir, const struct path *dir, struct dentry *dentry)
-LSM_HOOK(int, LSM_RET_INT(0), path_mknod, const struct path *dir, struct dentry *dentry,
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), path_rmdir, const struct path *dir, struct dentry *dentry)
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), path_mknod, const struct path *dir, struct dentry *dentry,
 	 umode_t mode, unsigned int dev)
-LSM_HOOK(int, LSM_RET_INT(0), path_truncate, const struct path *path)
-LSM_HOOK(int, LSM_RET_INT(0), path_symlink, const struct path *dir, struct dentry *dentry,
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), path_truncate, const struct path *path)
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), path_symlink, const struct path *dir, struct dentry *dentry,
 	 const char *old_name)
-LSM_HOOK(int, LSM_RET_INT(0), path_link, struct dentry *old_dentry,
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), path_link, struct dentry *old_dentry,
 	 const struct path *new_dir, struct dentry *new_dentry)
-LSM_HOOK(int, LSM_RET_INT(0), path_rename, const struct path *old_dir,
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), path_rename, const struct path *old_dir,
 	 struct dentry *old_dentry, const struct path *new_dir,
 	 struct dentry *new_dentry, unsigned int flags)
-LSM_HOOK(int, LSM_RET_INT(0), path_chmod, const struct path *path, umode_t mode)
-LSM_HOOK(int, LSM_RET_INT(0), path_chown, const struct path *path, kuid_t uid, kgid_t gid)
-LSM_HOOK(int, LSM_RET_INT(0), path_chroot, const struct path *path)
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), path_chmod, const struct path *path, umode_t mode)
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), path_chown, const struct path *path, kuid_t uid, kgid_t gid)
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), path_chroot, const struct path *path)
 #endif /* CONFIG_SECURITY_PATH */
 
 /* Needed for inode based security check */
-LSM_HOOK(int, LSM_RET_INT(0), path_notify, const struct path *path, u64 mask,
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), path_notify, const struct path *path, u64 mask,
 	 unsigned int obj_type)
-LSM_HOOK(int, LSM_RET_INT(0), inode_alloc_security, struct inode *inode)
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), inode_alloc_security, struct inode *inode)
 LSM_HOOK(void, LSM_RET_VOID, inode_free_security, struct inode *inode)
-LSM_HOOK(int, LSM_RET_INT(-EOPNOTSUPP), inode_init_security, struct inode *inode,
+LSM_HOOK(int, LSM_RET_INT(-EOPNOTSUPP, ERRNO), inode_init_security, struct inode *inode,
 	 struct inode *dir, const struct qstr *qstr, struct xattr *xattrs,
 	 int *xattr_count)
-LSM_HOOK(int, LSM_RET_INT(0), inode_init_security_anon, struct inode *inode,
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), inode_init_security_anon, struct inode *inode,
 	 const struct qstr *name, const struct inode *context_inode)
-LSM_HOOK(int, LSM_RET_INT(0), inode_create, struct inode *dir, struct dentry *dentry,
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), inode_create, struct inode *dir, struct dentry *dentry,
 	 umode_t mode)
-LSM_HOOK(int, LSM_RET_INT(0), inode_link, struct dentry *old_dentry, struct inode *dir,
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), inode_link, struct dentry *old_dentry, struct inode *dir,
 	 struct dentry *new_dentry)
-LSM_HOOK(int, LSM_RET_INT(0), inode_unlink, struct inode *dir, struct dentry *dentry)
-LSM_HOOK(int, LSM_RET_INT(0), inode_symlink, struct inode *dir, struct dentry *dentry,
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), inode_unlink, struct inode *dir, struct dentry *dentry)
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), inode_symlink, struct inode *dir, struct dentry *dentry,
 	 const char *old_name)
-LSM_HOOK(int, LSM_RET_INT(0), inode_mkdir, struct inode *dir, struct dentry *dentry,
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), inode_mkdir, struct inode *dir, struct dentry *dentry,
 	 umode_t mode)
-LSM_HOOK(int, LSM_RET_INT(0), inode_rmdir, struct inode *dir, struct dentry *dentry)
-LSM_HOOK(int, LSM_RET_INT(0), inode_mknod, struct inode *dir, struct dentry *dentry,
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), inode_rmdir, struct inode *dir, struct dentry *dentry)
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), inode_mknod, struct inode *dir, struct dentry *dentry,
 	 umode_t mode, dev_t dev)
-LSM_HOOK(int, LSM_RET_INT(0), inode_rename, struct inode *old_dir, struct dentry *old_dentry,
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), inode_rename, struct inode *old_dir, struct dentry *old_dentry,
 	 struct inode *new_dir, struct dentry *new_dentry)
-LSM_HOOK(int, LSM_RET_INT(0), inode_readlink, struct dentry *dentry)
-LSM_HOOK(int, LSM_RET_INT(0), inode_follow_link, struct dentry *dentry, struct inode *inode,
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), inode_readlink, struct dentry *dentry)
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), inode_follow_link, struct dentry *dentry, struct inode *inode,
 	 bool rcu)
-LSM_HOOK(int, LSM_RET_INT(0), inode_permission, struct inode *inode, int mask)
-LSM_HOOK(int, LSM_RET_INT(0), inode_setattr, struct dentry *dentry, struct iattr *attr)
-LSM_HOOK(int, LSM_RET_INT(0), inode_getattr, const struct path *path)
-LSM_HOOK(int, LSM_RET_INT(0), inode_setxattr, struct mnt_idmap *idmap,
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), inode_permission, struct inode *inode, int mask)
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), inode_setattr, struct dentry *dentry, struct iattr *attr)
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), inode_getattr, const struct path *path)
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), inode_setxattr, struct mnt_idmap *idmap,
 	 struct dentry *dentry, const char *name, const void *value,
 	 size_t size, int flags)
 LSM_HOOK(void, LSM_RET_VOID, inode_post_setxattr, struct dentry *dentry,
 	 const char *name, const void *value, size_t size, int flags)
-LSM_HOOK(int, LSM_RET_INT(0), inode_getxattr, struct dentry *dentry, const char *name)
-LSM_HOOK(int, LSM_RET_INT(0), inode_listxattr, struct dentry *dentry)
-LSM_HOOK(int, LSM_RET_INT(0), inode_removexattr, struct mnt_idmap *idmap,
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), inode_getxattr, struct dentry *dentry, const char *name)
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), inode_listxattr, struct dentry *dentry)
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), inode_removexattr, struct mnt_idmap *idmap,
 	 struct dentry *dentry, const char *name)
-LSM_HOOK(int, LSM_RET_INT(0), inode_set_acl, struct mnt_idmap *idmap,
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), inode_set_acl, struct mnt_idmap *idmap,
 	 struct dentry *dentry, const char *acl_name, struct posix_acl *kacl)
-LSM_HOOK(int, LSM_RET_INT(0), inode_get_acl, struct mnt_idmap *idmap,
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), inode_get_acl, struct mnt_idmap *idmap,
 	 struct dentry *dentry, const char *acl_name)
-LSM_HOOK(int, LSM_RET_INT(0), inode_remove_acl, struct mnt_idmap *idmap,
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), inode_remove_acl, struct mnt_idmap *idmap,
 	 struct dentry *dentry, const char *acl_name)
-LSM_HOOK(int, LSM_RET_INT(0), inode_need_killpriv, struct dentry *dentry)
-LSM_HOOK(int, LSM_RET_INT(0), inode_killpriv, struct mnt_idmap *idmap,
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), inode_need_killpriv, struct dentry *dentry)
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), inode_killpriv, struct mnt_idmap *idmap,
 	 struct dentry *dentry)
-LSM_HOOK(int, LSM_RET_INT(-EOPNOTSUPP), inode_getsecurity, struct mnt_idmap *idmap,
+LSM_HOOK(int, LSM_RET_INT(-EOPNOTSUPP, ERRNO), inode_getsecurity, struct mnt_idmap *idmap,
 	 struct inode *inode, const char *name, void **buffer, bool alloc)
-LSM_HOOK(int, LSM_RET_INT(-EOPNOTSUPP), inode_setsecurity, struct inode *inode,
+LSM_HOOK(int, LSM_RET_INT(-EOPNOTSUPP, ERRNO), inode_setsecurity, struct inode *inode,
 	 const char *name, const void *value, size_t size, int flags)
-LSM_HOOK(int, LSM_RET_INT(0), inode_listsecurity, struct inode *inode, char *buffer,
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), inode_listsecurity, struct inode *inode, char *buffer,
 	 size_t buffer_size)
 LSM_HOOK(void, LSM_RET_VOID, inode_getsecid, struct inode *inode, u32 *secid)
-LSM_HOOK(int, LSM_RET_INT(0), inode_copy_up, struct dentry *src, struct cred **new)
-LSM_HOOK(int, LSM_RET_INT(-EOPNOTSUPP), inode_copy_up_xattr, const char *name)
-LSM_HOOK(int, LSM_RET_INT(0), kernfs_init_security, struct kernfs_node *kn_dir,
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), inode_copy_up, struct dentry *src, struct cred **new)
+LSM_HOOK(int, LSM_RET_INT(-EOPNOTSUPP, ERRNO), inode_copy_up_xattr, const char *name)
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), kernfs_init_security, struct kernfs_node *kn_dir,
 	 struct kernfs_node *kn)
-LSM_HOOK(int, LSM_RET_INT(0), file_permission, struct file *file, int mask)
-LSM_HOOK(int, LSM_RET_INT(0), file_alloc_security, struct file *file)
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), file_permission, struct file *file, int mask)
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), file_alloc_security, struct file *file)
 LSM_HOOK(void, LSM_RET_VOID, file_free_security, struct file *file)
-LSM_HOOK(int, LSM_RET_INT(0), file_ioctl, struct file *file, unsigned int cmd,
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), file_ioctl, struct file *file, unsigned int cmd,
 	 unsigned long arg)
-LSM_HOOK(int, LSM_RET_INT(0), file_ioctl_compat, struct file *file, unsigned int cmd,
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), file_ioctl_compat, struct file *file, unsigned int cmd,
 	 unsigned long arg)
-LSM_HOOK(int, LSM_RET_INT(0), mmap_addr, unsigned long addr)
-LSM_HOOK(int, LSM_RET_INT(0), mmap_file, struct file *file, unsigned long reqprot,
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), mmap_addr, unsigned long addr)
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), mmap_file, struct file *file, unsigned long reqprot,
 	 unsigned long prot, unsigned long flags)
-LSM_HOOK(int, LSM_RET_INT(0), file_mprotect, struct vm_area_struct *vma,
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), file_mprotect, struct vm_area_struct *vma,
 	 unsigned long reqprot, unsigned long prot)
-LSM_HOOK(int, LSM_RET_INT(0), file_lock, struct file *file, unsigned int cmd)
-LSM_HOOK(int, LSM_RET_INT(0), file_fcntl, struct file *file, unsigned int cmd,
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), file_lock, struct file *file, unsigned int cmd)
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), file_fcntl, struct file *file, unsigned int cmd,
 	 unsigned long arg)
 LSM_HOOK(void, LSM_RET_VOID, file_set_fowner, struct file *file)
-LSM_HOOK(int, LSM_RET_INT(0), file_send_sigiotask, struct task_struct *tsk,
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), file_send_sigiotask, struct task_struct *tsk,
 	 struct fown_struct *fown, int sig)
-LSM_HOOK(int, LSM_RET_INT(0), file_receive, struct file *file)
-LSM_HOOK(int, LSM_RET_INT(0), file_open, struct file *file)
-LSM_HOOK(int, LSM_RET_INT(0), file_truncate, struct file *file)
-LSM_HOOK(int, LSM_RET_INT(0), task_alloc, struct task_struct *task,
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), file_receive, struct file *file)
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), file_open, struct file *file)
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), file_truncate, struct file *file)
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), task_alloc, struct task_struct *task,
 	 unsigned long clone_flags)
 LSM_HOOK(void, LSM_RET_VOID, task_free, struct task_struct *task)
-LSM_HOOK(int, LSM_RET_INT(0), cred_alloc_blank, struct cred *cred, gfp_t gfp)
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), cred_alloc_blank, struct cred *cred, gfp_t gfp)
 LSM_HOOK(void, LSM_RET_VOID, cred_free, struct cred *cred)
-LSM_HOOK(int, LSM_RET_INT(0), cred_prepare, struct cred *new, const struct cred *old,
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), cred_prepare, struct cred *new, const struct cred *old,
 	 gfp_t gfp)
 LSM_HOOK(void, LSM_RET_VOID, cred_transfer, struct cred *new,
 	 const struct cred *old)
 LSM_HOOK(void, LSM_RET_VOID, cred_getsecid, const struct cred *c, u32 *secid)
-LSM_HOOK(int, LSM_RET_INT(0), kernel_act_as, struct cred *new, u32 secid)
-LSM_HOOK(int, LSM_RET_INT(0), kernel_create_files_as, struct cred *new, struct inode *inode)
-LSM_HOOK(int, LSM_RET_INT(0), kernel_module_request, char *kmod_name)
-LSM_HOOK(int, LSM_RET_INT(0), kernel_load_data, enum kernel_load_data_id id, bool contents)
-LSM_HOOK(int, LSM_RET_INT(0), kernel_post_load_data, char *buf, loff_t size,
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), kernel_act_as, struct cred *new, u32 secid)
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), kernel_create_files_as, struct cred *new, struct inode *inode)
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), kernel_module_request, char *kmod_name)
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), kernel_load_data, enum kernel_load_data_id id, bool contents)
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), kernel_post_load_data, char *buf, loff_t size,
 	 enum kernel_load_data_id id, char *description)
-LSM_HOOK(int, LSM_RET_INT(0), kernel_read_file, struct file *file,
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), kernel_read_file, struct file *file,
 	 enum kernel_read_file_id id, bool contents)
-LSM_HOOK(int, LSM_RET_INT(0), kernel_post_read_file, struct file *file, char *buf,
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), kernel_post_read_file, struct file *file, char *buf,
 	 loff_t size, enum kernel_read_file_id id)
-LSM_HOOK(int, LSM_RET_INT(0), task_fix_setuid, struct cred *new, const struct cred *old,
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), task_fix_setuid, struct cred *new, const struct cred *old,
 	 int flags)
-LSM_HOOK(int, LSM_RET_INT(0), task_fix_setgid, struct cred *new, const struct cred *old,
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), task_fix_setgid, struct cred *new, const struct cred *old,
 	 int flags)
-LSM_HOOK(int, LSM_RET_INT(0), task_fix_setgroups, struct cred *new, const struct cred *old)
-LSM_HOOK(int, LSM_RET_INT(0), task_setpgid, struct task_struct *p, pid_t pgid)
-LSM_HOOK(int, LSM_RET_INT(0), task_getpgid, struct task_struct *p)
-LSM_HOOK(int, LSM_RET_INT(0), task_getsid, struct task_struct *p)
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), task_fix_setgroups, struct cred *new, const struct cred *old)
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), task_setpgid, struct task_struct *p, pid_t pgid)
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), task_getpgid, struct task_struct *p)
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), task_getsid, struct task_struct *p)
 LSM_HOOK(void, LSM_RET_VOID, current_getsecid_subj, u32 *secid)
 LSM_HOOK(void, LSM_RET_VOID, task_getsecid_obj,
 	 struct task_struct *p, u32 *secid)
-LSM_HOOK(int, LSM_RET_INT(0), task_setnice, struct task_struct *p, int nice)
-LSM_HOOK(int, LSM_RET_INT(0), task_setioprio, struct task_struct *p, int ioprio)
-LSM_HOOK(int, LSM_RET_INT(0), task_getioprio, struct task_struct *p)
-LSM_HOOK(int, LSM_RET_INT(0), task_prlimit, const struct cred *cred,
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), task_setnice, struct task_struct *p, int nice)
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), task_setioprio, struct task_struct *p, int ioprio)
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), task_getioprio, struct task_struct *p)
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), task_prlimit, const struct cred *cred,
 	 const struct cred *tcred, unsigned int flags)
-LSM_HOOK(int, LSM_RET_INT(0), task_setrlimit, struct task_struct *p, unsigned int resource,
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), task_setrlimit, struct task_struct *p, unsigned int resource,
 	 struct rlimit *new_rlim)
-LSM_HOOK(int, LSM_RET_INT(0), task_setscheduler, struct task_struct *p)
-LSM_HOOK(int, LSM_RET_INT(0), task_getscheduler, struct task_struct *p)
-LSM_HOOK(int, LSM_RET_INT(0), task_movememory, struct task_struct *p)
-LSM_HOOK(int, LSM_RET_INT(0), task_kill, struct task_struct *p, struct kernel_siginfo *info,
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), task_setscheduler, struct task_struct *p)
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), task_getscheduler, struct task_struct *p)
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), task_movememory, struct task_struct *p)
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), task_kill, struct task_struct *p, struct kernel_siginfo *info,
 	 int sig, const struct cred *cred)
-LSM_HOOK(int, LSM_RET_INT(-ENOSYS), task_prctl, int option, unsigned long arg2,
+LSM_HOOK(int, LSM_RET_INT(-ENOSYS, ERRNO), task_prctl, int option, unsigned long arg2,
 	 unsigned long arg3, unsigned long arg4, unsigned long arg5)
 LSM_HOOK(void, LSM_RET_VOID, task_to_inode, struct task_struct *p,
 	 struct inode *inode)
-LSM_HOOK(int, LSM_RET_INT(0), userns_create, const struct cred *cred)
-LSM_HOOK(int, LSM_RET_INT(0), ipc_permission, struct kern_ipc_perm *ipcp, short flag)
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), userns_create, const struct cred *cred)
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), ipc_permission, struct kern_ipc_perm *ipcp, short flag)
 LSM_HOOK(void, LSM_RET_VOID, ipc_getsecid, struct kern_ipc_perm *ipcp,
 	 u32 *secid)
-LSM_HOOK(int, LSM_RET_INT(0), msg_msg_alloc_security, struct msg_msg *msg)
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), msg_msg_alloc_security, struct msg_msg *msg)
 LSM_HOOK(void, LSM_RET_VOID, msg_msg_free_security, struct msg_msg *msg)
-LSM_HOOK(int, LSM_RET_INT(0), msg_queue_alloc_security, struct kern_ipc_perm *perm)
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), msg_queue_alloc_security, struct kern_ipc_perm *perm)
 LSM_HOOK(void, LSM_RET_VOID, msg_queue_free_security,
 	 struct kern_ipc_perm *perm)
-LSM_HOOK(int, LSM_RET_INT(0), msg_queue_associate, struct kern_ipc_perm *perm, int msqflg)
-LSM_HOOK(int, LSM_RET_INT(0), msg_queue_msgctl, struct kern_ipc_perm *perm, int cmd)
-LSM_HOOK(int, LSM_RET_INT(0), msg_queue_msgsnd, struct kern_ipc_perm *perm,
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), msg_queue_associate, struct kern_ipc_perm *perm, int msqflg)
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), msg_queue_msgctl, struct kern_ipc_perm *perm, int cmd)
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), msg_queue_msgsnd, struct kern_ipc_perm *perm,
 	 struct msg_msg *msg, int msqflg)
-LSM_HOOK(int, LSM_RET_INT(0), msg_queue_msgrcv, struct kern_ipc_perm *perm,
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), msg_queue_msgrcv, struct kern_ipc_perm *perm,
 	 struct msg_msg *msg, struct task_struct *target, long type, int mode)
-LSM_HOOK(int, LSM_RET_INT(0), shm_alloc_security, struct kern_ipc_perm *perm)
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), shm_alloc_security, struct kern_ipc_perm *perm)
 LSM_HOOK(void, LSM_RET_VOID, shm_free_security, struct kern_ipc_perm *perm)
-LSM_HOOK(int, LSM_RET_INT(0), shm_associate, struct kern_ipc_perm *perm, int shmflg)
-LSM_HOOK(int, LSM_RET_INT(0), shm_shmctl, struct kern_ipc_perm *perm, int cmd)
-LSM_HOOK(int, LSM_RET_INT(0), shm_shmat, struct kern_ipc_perm *perm, char __user *shmaddr,
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), shm_associate, struct kern_ipc_perm *perm, int shmflg)
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), shm_shmctl, struct kern_ipc_perm *perm, int cmd)
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), shm_shmat, struct kern_ipc_perm *perm, char __user *shmaddr,
 	 int shmflg)
-LSM_HOOK(int, LSM_RET_INT(0), sem_alloc_security, struct kern_ipc_perm *perm)
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), sem_alloc_security, struct kern_ipc_perm *perm)
 LSM_HOOK(void, LSM_RET_VOID, sem_free_security, struct kern_ipc_perm *perm)
-LSM_HOOK(int, LSM_RET_INT(0), sem_associate, struct kern_ipc_perm *perm, int semflg)
-LSM_HOOK(int, LSM_RET_INT(0), sem_semctl, struct kern_ipc_perm *perm, int cmd)
-LSM_HOOK(int, LSM_RET_INT(0), sem_semop, struct kern_ipc_perm *perm, struct sembuf *sops,
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), sem_associate, struct kern_ipc_perm *perm, int semflg)
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), sem_semctl, struct kern_ipc_perm *perm, int cmd)
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), sem_semop, struct kern_ipc_perm *perm, struct sembuf *sops,
 	 unsigned nsops, int alter)
-LSM_HOOK(int, LSM_RET_INT(0), netlink_send, struct sock *sk, struct sk_buff *skb)
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), netlink_send, struct sock *sk, struct sk_buff *skb)
 LSM_HOOK(void, LSM_RET_VOID, d_instantiate, struct dentry *dentry,
 	 struct inode *inode)
-LSM_HOOK(int, LSM_RET_INT(-EOPNOTSUPP), getselfattr, unsigned int attr,
+LSM_HOOK(int, LSM_RET_INT(-EOPNOTSUPP, ERRNO), getselfattr, unsigned int attr,
 	 struct lsm_ctx __user *ctx, size_t *size, u32 flags)
-LSM_HOOK(int, LSM_RET_INT(-EOPNOTSUPP), setselfattr, unsigned int attr,
+LSM_HOOK(int, LSM_RET_INT(-EOPNOTSUPP, ERRNO), setselfattr, unsigned int attr,
 	 struct lsm_ctx *ctx, size_t size, u32 flags)
-LSM_HOOK(int, LSM_RET_INT(-EINVAL), getprocattr, struct task_struct *p, const char *name,
+LSM_HOOK(int, LSM_RET_INT(-EINVAL, ERRNO), getprocattr, struct task_struct *p, const char *name,
 	 char **value)
-LSM_HOOK(int, LSM_RET_INT(-EINVAL), setprocattr, const char *name, void *value, size_t size)
-LSM_HOOK(int, LSM_RET_INT(0), ismaclabel, const char *name)
-LSM_HOOK(int, LSM_RET_INT(-EOPNOTSUPP), secid_to_secctx, u32 secid, char **secdata,
+LSM_HOOK(int, LSM_RET_INT(-EINVAL, ERRNO), setprocattr, const char *name, void *value, size_t size)
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), ismaclabel, const char *name)
+LSM_HOOK(int, LSM_RET_INT(-EOPNOTSUPP, ERRNO), secid_to_secctx, u32 secid, char **secdata,
 	 u32 *seclen)
-LSM_HOOK(int, LSM_RET_INT(0), secctx_to_secid, const char *secdata, u32 seclen, u32 *secid)
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), secctx_to_secid, const char *secdata, u32 seclen, u32 *secid)
 LSM_HOOK(void, LSM_RET_VOID, release_secctx, char *secdata, u32 seclen)
 LSM_HOOK(void, LSM_RET_VOID, inode_invalidate_secctx, struct inode *inode)
-LSM_HOOK(int, LSM_RET_INT(0), inode_notifysecctx, struct inode *inode, void *ctx, u32 ctxlen)
-LSM_HOOK(int, LSM_RET_INT(0), inode_setsecctx, struct dentry *dentry, void *ctx, u32 ctxlen)
-LSM_HOOK(int, LSM_RET_INT(-EOPNOTSUPP), inode_getsecctx, struct inode *inode, void **ctx,
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), inode_notifysecctx, struct inode *inode, void *ctx, u32 ctxlen)
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), inode_setsecctx, struct dentry *dentry, void *ctx, u32 ctxlen)
+LSM_HOOK(int, LSM_RET_INT(-EOPNOTSUPP, ERRNO), inode_getsecctx, struct inode *inode, void **ctx,
 	 u32 *ctxlen)
 
 #if defined(CONFIG_SECURITY) && defined(CONFIG_WATCH_QUEUE)
-LSM_HOOK(int, LSM_RET_INT(0), post_notification, const struct cred *w_cred,
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), post_notification, const struct cred *w_cred,
 	 const struct cred *cred, struct watch_notification *n)
 #endif /* CONFIG_SECURITY && CONFIG_WATCH_QUEUE */
 
 #if defined(CONFIG_SECURITY) && defined(CONFIG_KEY_NOTIFICATIONS)
-LSM_HOOK(int, LSM_RET_INT(0), watch_key, struct key *key)
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), watch_key, struct key *key)
 #endif /* CONFIG_SECURITY && CONFIG_KEY_NOTIFICATIONS */
 
 #ifdef CONFIG_SECURITY_NETWORK
-LSM_HOOK(int, LSM_RET_INT(0), unix_stream_connect, struct sock *sock, struct sock *other,
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), unix_stream_connect, struct sock *sock, struct sock *other,
 	 struct sock *newsk)
-LSM_HOOK(int, LSM_RET_INT(0), unix_may_send, struct socket *sock, struct socket *other)
-LSM_HOOK(int, LSM_RET_INT(0), socket_create, int family, int type, int protocol, int kern)
-LSM_HOOK(int, LSM_RET_INT(0), socket_post_create, struct socket *sock, int family, int type,
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), unix_may_send, struct socket *sock, struct socket *other)
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), socket_create, int family, int type, int protocol, int kern)
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), socket_post_create, struct socket *sock, int family, int type,
 	 int protocol, int kern)
-LSM_HOOK(int, LSM_RET_INT(0), socket_socketpair, struct socket *socka, struct socket *sockb)
-LSM_HOOK(int, LSM_RET_INT(0), socket_bind, struct socket *sock, struct sockaddr *address,
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), socket_socketpair, struct socket *socka, struct socket *sockb)
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), socket_bind, struct socket *sock, struct sockaddr *address,
 	 int addrlen)
-LSM_HOOK(int, LSM_RET_INT(0), socket_connect, struct socket *sock, struct sockaddr *address,
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), socket_connect, struct socket *sock, struct sockaddr *address,
 	 int addrlen)
-LSM_HOOK(int, LSM_RET_INT(0), socket_listen, struct socket *sock, int backlog)
-LSM_HOOK(int, LSM_RET_INT(0), socket_accept, struct socket *sock, struct socket *newsock)
-LSM_HOOK(int, LSM_RET_INT(0), socket_sendmsg, struct socket *sock, struct msghdr *msg,
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), socket_listen, struct socket *sock, int backlog)
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), socket_accept, struct socket *sock, struct socket *newsock)
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), socket_sendmsg, struct socket *sock, struct msghdr *msg,
 	 int size)
-LSM_HOOK(int, LSM_RET_INT(0), socket_recvmsg, struct socket *sock, struct msghdr *msg,
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), socket_recvmsg, struct socket *sock, struct msghdr *msg,
 	 int size, int flags)
-LSM_HOOK(int, LSM_RET_INT(0), socket_getsockname, struct socket *sock)
-LSM_HOOK(int, LSM_RET_INT(0), socket_getpeername, struct socket *sock)
-LSM_HOOK(int, LSM_RET_INT(0), socket_getsockopt, struct socket *sock, int level, int optname)
-LSM_HOOK(int, LSM_RET_INT(0), socket_setsockopt, struct socket *sock, int level, int optname)
-LSM_HOOK(int, LSM_RET_INT(0), socket_shutdown, struct socket *sock, int how)
-LSM_HOOK(int, LSM_RET_INT(0), socket_sock_rcv_skb, struct sock *sk, struct sk_buff *skb)
-LSM_HOOK(int, LSM_RET_INT(-ENOPROTOOPT), socket_getpeersec_stream, struct socket *sock,
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), socket_getsockname, struct socket *sock)
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), socket_getpeername, struct socket *sock)
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), socket_getsockopt, struct socket *sock, int level, int optname)
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), socket_setsockopt, struct socket *sock, int level, int optname)
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), socket_shutdown, struct socket *sock, int how)
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), socket_sock_rcv_skb, struct sock *sk, struct sk_buff *skb)
+LSM_HOOK(int, LSM_RET_INT(-ENOPROTOOPT, ERRNO), socket_getpeersec_stream, struct socket *sock,
 	 sockptr_t optval, sockptr_t optlen, unsigned int len)
-LSM_HOOK(int, LSM_RET_INT(-ENOPROTOOPT), socket_getpeersec_dgram, struct socket *sock,
+LSM_HOOK(int, LSM_RET_INT(-ENOPROTOOPT, ERRNO), socket_getpeersec_dgram, struct socket *sock,
 	 struct sk_buff *skb, u32 *secid)
-LSM_HOOK(int, LSM_RET_INT(0), sk_alloc_security, struct sock *sk, int family, gfp_t priority)
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), sk_alloc_security, struct sock *sk, int family, gfp_t priority)
 LSM_HOOK(void, LSM_RET_VOID, sk_free_security, struct sock *sk)
 LSM_HOOK(void, LSM_RET_VOID, sk_clone_security, const struct sock *sk,
 	 struct sock *newsk)
 LSM_HOOK(void, LSM_RET_VOID, sk_getsecid, const struct sock *sk, u32 *secid)
 LSM_HOOK(void, LSM_RET_VOID, sock_graft, struct sock *sk, struct socket *parent)
-LSM_HOOK(int, LSM_RET_INT(0), inet_conn_request, const struct sock *sk, struct sk_buff *skb,
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), inet_conn_request, const struct sock *sk, struct sk_buff *skb,
 	 struct request_sock *req)
 LSM_HOOK(void, LSM_RET_VOID, inet_csk_clone, struct sock *newsk,
 	 const struct request_sock *req)
 LSM_HOOK(void, LSM_RET_VOID, inet_conn_established, struct sock *sk,
 	 struct sk_buff *skb)
-LSM_HOOK(int, LSM_RET_INT(0), secmark_relabel_packet, u32 secid)
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), secmark_relabel_packet, u32 secid)
 LSM_HOOK(void, LSM_RET_VOID, secmark_refcount_inc, void)
 LSM_HOOK(void, LSM_RET_VOID, secmark_refcount_dec, void)
 LSM_HOOK(void, LSM_RET_VOID, req_classify_flow, const struct request_sock *req,
 	 struct flowi_common *flic)
-LSM_HOOK(int, LSM_RET_INT(0), tun_dev_alloc_security, void **security)
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), tun_dev_alloc_security, void **security)
 LSM_HOOK(void, LSM_RET_VOID, tun_dev_free_security, void *security)
-LSM_HOOK(int, LSM_RET_INT(0), tun_dev_create, void)
-LSM_HOOK(int, LSM_RET_INT(0), tun_dev_attach_queue, void *security)
-LSM_HOOK(int, LSM_RET_INT(0), tun_dev_attach, struct sock *sk, void *security)
-LSM_HOOK(int, LSM_RET_INT(0), tun_dev_open, void *security)
-LSM_HOOK(int, LSM_RET_INT(0), sctp_assoc_request, struct sctp_association *asoc,
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), tun_dev_create, void)
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), tun_dev_attach_queue, void *security)
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), tun_dev_attach, struct sock *sk, void *security)
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), tun_dev_open, void *security)
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), sctp_assoc_request, struct sctp_association *asoc,
 	 struct sk_buff *skb)
-LSM_HOOK(int, LSM_RET_INT(0), sctp_bind_connect, struct sock *sk, int optname,
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), sctp_bind_connect, struct sock *sk, int optname,
 	 struct sockaddr *address, int addrlen)
 LSM_HOOK(void, LSM_RET_VOID, sctp_sk_clone, struct sctp_association *asoc,
 	 struct sock *sk, struct sock *newsk)
-LSM_HOOK(int, LSM_RET_INT(0), sctp_assoc_established, struct sctp_association *asoc,
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), sctp_assoc_established, struct sctp_association *asoc,
 	 struct sk_buff *skb)
-LSM_HOOK(int, LSM_RET_INT(0), mptcp_add_subflow, struct sock *sk, struct sock *ssk)
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), mptcp_add_subflow, struct sock *sk, struct sock *ssk)
 #endif /* CONFIG_SECURITY_NETWORK */
 
 #ifdef CONFIG_SECURITY_INFINIBAND
-LSM_HOOK(int, LSM_RET_INT(0), ib_pkey_access, void *sec, u64 subnet_prefix, u16 pkey)
-LSM_HOOK(int, LSM_RET_INT(0), ib_endport_manage_subnet, void *sec, const char *dev_name,
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), ib_pkey_access, void *sec, u64 subnet_prefix, u16 pkey)
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), ib_endport_manage_subnet, void *sec, const char *dev_name,
 	 u8 port_num)
-LSM_HOOK(int, LSM_RET_INT(0), ib_alloc_security, void **sec)
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), ib_alloc_security, void **sec)
 LSM_HOOK(void, LSM_RET_VOID, ib_free_security, void *sec)
 #endif /* CONFIG_SECURITY_INFINIBAND */
 
 #ifdef CONFIG_SECURITY_NETWORK_XFRM
-LSM_HOOK(int, LSM_RET_INT(0), xfrm_policy_alloc_security, struct xfrm_sec_ctx **ctxp,
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), xfrm_policy_alloc_security, struct xfrm_sec_ctx **ctxp,
 	 struct xfrm_user_sec_ctx *sec_ctx, gfp_t gfp)
-LSM_HOOK(int, LSM_RET_INT(0), xfrm_policy_clone_security, struct xfrm_sec_ctx *old_ctx,
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), xfrm_policy_clone_security, struct xfrm_sec_ctx *old_ctx,
 	 struct xfrm_sec_ctx **new_ctx)
 LSM_HOOK(void, LSM_RET_VOID, xfrm_policy_free_security,
 	 struct xfrm_sec_ctx *ctx)
-LSM_HOOK(int, LSM_RET_INT(0), xfrm_policy_delete_security, struct xfrm_sec_ctx *ctx)
-LSM_HOOK(int, LSM_RET_INT(0), xfrm_state_alloc, struct xfrm_state *x,
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), xfrm_policy_delete_security, struct xfrm_sec_ctx *ctx)
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), xfrm_state_alloc, struct xfrm_state *x,
 	 struct xfrm_user_sec_ctx *sec_ctx)
-LSM_HOOK(int, LSM_RET_INT(0), xfrm_state_alloc_acquire, struct xfrm_state *x,
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), xfrm_state_alloc_acquire, struct xfrm_state *x,
 	 struct xfrm_sec_ctx *polsec, u32 secid)
 LSM_HOOK(void, LSM_RET_VOID, xfrm_state_free_security, struct xfrm_state *x)
-LSM_HOOK(int, LSM_RET_INT(0), xfrm_state_delete_security, struct xfrm_state *x)
-LSM_HOOK(int, LSM_RET_INT(0), xfrm_policy_lookup, struct xfrm_sec_ctx *ctx, u32 fl_secid)
-LSM_HOOK(int, LSM_RET_INT(1), xfrm_state_pol_flow_match, struct xfrm_state *x,
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), xfrm_state_delete_security, struct xfrm_state *x)
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), xfrm_policy_lookup, struct xfrm_sec_ctx *ctx, u32 fl_secid)
+LSM_HOOK(int, LSM_RET_INT(1, ANY), xfrm_state_pol_flow_match, struct xfrm_state *x,
 	 struct xfrm_policy *xp, const struct flowi_common *flic)
-LSM_HOOK(int, LSM_RET_INT(0), xfrm_decode_session, struct sk_buff *skb, u32 *secid,
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), xfrm_decode_session, struct sk_buff *skb, u32 *secid,
 	 int ckall)
 #endif /* CONFIG_SECURITY_NETWORK_XFRM */
 
 /* key management security hooks */
 #ifdef CONFIG_KEYS
-LSM_HOOK(int, LSM_RET_INT(0), key_alloc, struct key *key, const struct cred *cred,
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), key_alloc, struct key *key, const struct cred *cred,
 	 unsigned long flags)
 LSM_HOOK(void, LSM_RET_VOID, key_free, struct key *key)
-LSM_HOOK(int, LSM_RET_INT(0), key_permission, key_ref_t key_ref, const struct cred *cred,
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), key_permission, key_ref_t key_ref, const struct cred *cred,
 	 enum key_need_perm need_perm)
-LSM_HOOK(int, LSM_RET_INT(0), key_getsecurity, struct key *key, char **buffer)
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), key_getsecurity, struct key *key, char **buffer)
 #endif /* CONFIG_KEYS */
 
 #ifdef CONFIG_AUDIT
-LSM_HOOK(int, LSM_RET_INT(0), audit_rule_init, u32 field, u32 op, char *rulestr,
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), audit_rule_init, u32 field, u32 op, char *rulestr,
 	 void **lsmrule)
-LSM_HOOK(int, LSM_RET_INT(0), audit_rule_known, struct audit_krule *krule)
-LSM_HOOK(int, LSM_RET_INT(0), audit_rule_match, u32 secid, u32 field, u32 op, void *lsmrule)
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), audit_rule_known, struct audit_krule *krule)
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), audit_rule_match, u32 secid, u32 field, u32 op, void *lsmrule)
 LSM_HOOK(void, LSM_RET_VOID, audit_rule_free, void *lsmrule)
 #endif /* CONFIG_AUDIT */
 
 #ifdef CONFIG_BPF_SYSCALL
-LSM_HOOK(int, LSM_RET_INT(0), bpf, int cmd, union bpf_attr *attr, unsigned int size)
-LSM_HOOK(int, LSM_RET_INT(0), bpf_map, struct bpf_map *map, fmode_t fmode)
-LSM_HOOK(int, LSM_RET_INT(0), bpf_prog, struct bpf_prog *prog)
-LSM_HOOK(int, LSM_RET_INT(0), bpf_map_create, struct bpf_map *map, union bpf_attr *attr,
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), bpf, int cmd, union bpf_attr *attr, unsigned int size)
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), bpf_map, struct bpf_map *map, fmode_t fmode)
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), bpf_prog, struct bpf_prog *prog)
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), bpf_map_create, struct bpf_map *map, union bpf_attr *attr,
 	 struct bpf_token *token)
 LSM_HOOK(void, LSM_RET_VOID, bpf_map_free, struct bpf_map *map)
-LSM_HOOK(int, LSM_RET_INT(0), bpf_prog_load, struct bpf_prog *prog, union bpf_attr *attr,
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), bpf_prog_load, struct bpf_prog *prog, union bpf_attr *attr,
 	 struct bpf_token *token)
 LSM_HOOK(void, LSM_RET_VOID, bpf_prog_free, struct bpf_prog *prog)
-LSM_HOOK(int, LSM_RET_INT(0), bpf_token_create, struct bpf_token *token, union bpf_attr *attr,
-	 struct path *path)
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), bpf_token_create, struct bpf_token *token,
+	 union bpf_attr *attr, struct path *path)
 LSM_HOOK(void, LSM_RET_VOID, bpf_token_free, struct bpf_token *token)
-LSM_HOOK(int, LSM_RET_INT(0), bpf_token_cmd, const struct bpf_token *token, enum bpf_cmd cmd)
-LSM_HOOK(int, LSM_RET_INT(0), bpf_token_capable, const struct bpf_token *token, int cap)
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), bpf_token_cmd, const struct bpf_token *token, enum bpf_cmd cmd)
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), bpf_token_capable, const struct bpf_token *token, int cap)
 #endif /* CONFIG_BPF_SYSCALL */
 
-LSM_HOOK(int, LSM_RET_INT(0), locked_down, enum lockdown_reason what)
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), locked_down, enum lockdown_reason what)
 
 #ifdef CONFIG_PERF_EVENTS
-LSM_HOOK(int, LSM_RET_INT(0), perf_event_open, struct perf_event_attr *attr, int type)
-LSM_HOOK(int, LSM_RET_INT(0), perf_event_alloc, struct perf_event *event)
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), perf_event_open, struct perf_event_attr *attr, int type)
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), perf_event_alloc, struct perf_event *event)
 LSM_HOOK(void, LSM_RET_VOID, perf_event_free, struct perf_event *event)
-LSM_HOOK(int, LSM_RET_INT(0), perf_event_read, struct perf_event *event)
-LSM_HOOK(int, LSM_RET_INT(0), perf_event_write, struct perf_event *event)
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), perf_event_read, struct perf_event *event)
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), perf_event_write, struct perf_event *event)
 #endif /* CONFIG_PERF_EVENTS */
 
 #ifdef CONFIG_IO_URING
-LSM_HOOK(int, LSM_RET_INT(0), uring_override_creds, const struct cred *new)
-LSM_HOOK(int, LSM_RET_INT(0), uring_sqpoll, void)
-LSM_HOOK(int, LSM_RET_INT(0), uring_cmd, struct io_uring_cmd *ioucmd)
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), uring_override_creds, const struct cred *new)
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), uring_sqpoll, void)
+LSM_HOOK(int, LSM_RET_INT(0, ERRNO), uring_cmd, struct io_uring_cmd *ioucmd)
 #endif /* CONFIG_IO_URING */
diff --git a/kernel/bpf/bpf_lsm.c b/kernel/bpf/bpf_lsm.c
index 2185dc4c0aed..ee9d1a795334 100644
--- a/kernel/bpf/bpf_lsm.c
+++ b/kernel/bpf/bpf_lsm.c
@@ -24,7 +24,7 @@
  */
 #define LSM_RET_VOID ((void) 0)
 
-#define LSM_RET_INT(defval) defval
+#define LSM_RET_INT(defval, ...) defval
 
 /* For every LSM hook that allows attachment of BPF programs, declare a nop
  * function where a BPF program can be attached.
diff --git a/security/security.c b/security/security.c
index 72408a9f0822..0cce7c9c9007 100644
--- a/security/security.c
+++ b/security/security.c
@@ -828,7 +828,7 @@ int lsm_fill_user_ctx(struct lsm_ctx __user *uctx, size_t *uctx_len,
  * The macros below define static constants for the default value of each
  * LSM hook.
  */
-#define LSM_RET_INT(defval) defval
+#define LSM_RET_INT(defval, ...) defval
 #define LSM_RET_DEFAULT(NAME) (NAME##_default)
 #define DECLARE_LSM_RET_DEFAULT_void(DEFAULT, NAME)
 #define DECLARE_LSM_RET_DEFAULT_int(DEFAULT, NAME) \
-- 
2.30.2


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH bpf-next v2 3/7] bpf, lsm: Add function to read lsm hook return value range
  2024-03-25  9:56 [PATCH bpf-next v2 0/7] Add check for bpf lsm return value Xu Kuohai
  2024-03-25  9:56 ` [PATCH bpf-next v2 1/7] bpf, lsm: Annotate lsm hook return integer with new macro LSM_RET_INT Xu Kuohai
  2024-03-25  9:56 ` [PATCH bpf-next v2 2/7] bpf, lsm: Add return value range description for lsm hook Xu Kuohai
@ 2024-03-25  9:56 ` Xu Kuohai
  2024-03-25  9:56 ` [PATCH bpf-next v2 4/7] bpf, lsm: Check bpf lsm hook return values in verifier Xu Kuohai
                   ` (4 subsequent siblings)
  7 siblings, 0 replies; 13+ messages in thread
From: Xu Kuohai @ 2024-03-25  9:56 UTC (permalink / raw)
  To: bpf, linux-security-module
  Cc: Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko,
	Martin KaFai Lau, Eduard Zingerman, Song Liu, Yonghong Song,
	John Fastabend, KP Singh, Stanislav Fomichev, Hao Luo, Jiri Olsa,
	Florent Revest, Brendan Jackman, Paul Moore, James Morris,
	Serge E . Hallyn, Khadija Kamran, Casey Schaufler,
	Ondrej Mosnacek, Kees Cook, John Johansen, Lukas Bulwahn,
	Roberto Sassu, Shung-Hsi Yu

From: Xu Kuohai <xukuohai@huawei.com>

Add function to read lsm hook return value range. The following patch
will use this information to check lsm hook return values in bpf
verifier.

Signed-off-by: Xu Kuohai <xukuohai@huawei.com>
---
 include/linux/bpf_lsm.h |  8 ++++++
 kernel/bpf/bpf_lsm.c    | 56 ++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 63 insertions(+), 1 deletion(-)

diff --git a/include/linux/bpf_lsm.h b/include/linux/bpf_lsm.h
index 1de7ece5d36d..e51c042abf43 100644
--- a/include/linux/bpf_lsm.h
+++ b/include/linux/bpf_lsm.h
@@ -9,6 +9,7 @@
 
 #include <linux/sched.h>
 #include <linux/bpf.h>
+#include <linux/bpf_verifier.h>
 #include <linux/lsm_hooks.h>
 
 #ifdef CONFIG_BPF_LSM
@@ -45,6 +46,8 @@ void bpf_inode_storage_free(struct inode *inode);
 
 void bpf_lsm_find_cgroup_shim(const struct bpf_prog *prog, bpf_func_t *bpf_func);
 
+int bpf_lsm_get_retval_range(const struct bpf_prog *prog,
+			      struct bpf_retval_range *range);
 #else /* !CONFIG_BPF_LSM */
 
 static inline bool bpf_lsm_is_sleepable_hook(u32 btf_id)
@@ -78,6 +81,11 @@ static inline void bpf_lsm_find_cgroup_shim(const struct bpf_prog *prog,
 {
 }
 
+static inline int bpf_lsm_get_retval_range(const struct bpf_prog *prog,
+					   struct bpf_retval_range *range)
+{
+	return -EOPNOTSUPP;
+}
 #endif /* CONFIG_BPF_LSM */
 
 #endif /* _LINUX_BPF_LSM_H */
diff --git a/kernel/bpf/bpf_lsm.c b/kernel/bpf/bpf_lsm.c
index ee9d1a795334..7b4611fd3a37 100644
--- a/kernel/bpf/bpf_lsm.c
+++ b/kernel/bpf/bpf_lsm.c
@@ -11,7 +11,6 @@
 #include <linux/lsm_hooks.h>
 #include <linux/bpf_lsm.h>
 #include <linux/kallsyms.h>
-#include <linux/bpf_verifier.h>
 #include <net/bpf_sk_storage.h>
 #include <linux/bpf_local_storage.h>
 #include <linux/btf_ids.h>
@@ -40,6 +39,31 @@ noinline RET bpf_lsm_##NAME(__VA_ARGS__)	\
 #undef LSM_RET_INT
 #undef LSM_RET_VOID
 
+struct lsm_retval_desc {
+	unsigned long func_addr;
+	int minval;
+	int maxval;
+};
+
+#define LSM_RET_INT_ERRNO -MAX_ERRNO, 0
+#define LSM_RET_INT_ANY INT_MIN, INT_MAX
+#define LSM_RET_INT(defval, range_desc) LSM_RET_INT_##range_desc
+
+#define LSM_HOOK_RETVAL_int(NAME, ...) \
+{ (unsigned long)&bpf_lsm_##NAME, __VA_ARGS__ },
+
+#define LSM_HOOK_RETVAL_void(NAME, ...)
+
+#define LSM_HOOK(RET, DEFAULT, NAME, ...) \
+LSM_HOOK_RETVAL_##RET(NAME, DEFAULT)
+
+static struct lsm_retval_desc lsm_retvalues[]  = {
+#include <linux/lsm_hook_defs.h>
+};
+#undef LSM_HOOK
+#undef LSM_RET_INT
+#undef LSM_RET_VOID
+
 #define LSM_HOOK(RET, DEFAULT, NAME, ...) BTF_ID(func, bpf_lsm_##NAME)
 BTF_SET_START(bpf_lsm_hooks)
 #include <linux/lsm_hook_defs.h>
@@ -399,3 +423,33 @@ const struct bpf_verifier_ops lsm_verifier_ops = {
 	.get_func_proto = bpf_lsm_func_proto,
 	.is_valid_access = btf_ctx_access,
 };
+
+static struct lsm_retval_desc *find_retval_desc(const char *func_name)
+{
+	unsigned long addr;
+	struct lsm_retval_desc *desc;
+
+	addr = kallsyms_lookup_name(func_name);
+	for (unsigned int i = 0U; i < ARRAY_SIZE(lsm_retvalues); i++) {
+		desc = &lsm_retvalues[i];
+		if (addr == desc->func_addr)
+			return desc;
+	}
+
+	return NULL;
+}
+
+int bpf_lsm_get_retval_range(const struct bpf_prog *prog,
+			      struct bpf_retval_range *retval_range)
+{
+	struct lsm_retval_desc *desc;
+
+	desc = find_retval_desc(prog->aux->attach_func_name);
+	if (desc == NULL)
+		return -ENODEV;
+
+	retval_range->minval = desc->minval;
+	retval_range->maxval = desc->maxval;
+
+	return 0;
+}
-- 
2.30.2


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH bpf-next v2 4/7] bpf, lsm: Check bpf lsm hook return values in verifier
  2024-03-25  9:56 [PATCH bpf-next v2 0/7] Add check for bpf lsm return value Xu Kuohai
                   ` (2 preceding siblings ...)
  2024-03-25  9:56 ` [PATCH bpf-next v2 3/7] bpf, lsm: Add function to read lsm hook return value range Xu Kuohai
@ 2024-03-25  9:56 ` Xu Kuohai
  2024-03-25  9:56 ` [PATCH bpf-next v2 5/7] bpf: Fix compare error in function retval_range_within Xu Kuohai
                   ` (3 subsequent siblings)
  7 siblings, 0 replies; 13+ messages in thread
From: Xu Kuohai @ 2024-03-25  9:56 UTC (permalink / raw)
  To: bpf, linux-security-module
  Cc: Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko,
	Martin KaFai Lau, Eduard Zingerman, Song Liu, Yonghong Song,
	John Fastabend, KP Singh, Stanislav Fomichev, Hao Luo, Jiri Olsa,
	Florent Revest, Brendan Jackman, Paul Moore, James Morris,
	Serge E . Hallyn, Khadija Kamran, Casey Schaufler,
	Ondrej Mosnacek, Kees Cook, John Johansen, Lukas Bulwahn,
	Roberto Sassu, Shung-Hsi Yu

From: Xu Kuohai <xukuohai@huawei.com>

A bpf prog returning positive number attached to file_alloc_security hook
will make kernel panic.

The reason is that the positive number returned by bpf prog is not a
valid errno, and could not be filtered out with IS_ERR which is used by
the file system to check errors. As a result, the file system uses this
positive number as file pointer, causing panic.

Considering that hook file_alloc_security never returned positive number
before bpf lsm was introduced, and other bpf lsm hooks may have the same
problem, this patch adds lsm return value check in bpf verifier to ensure
no unpredicted values will be returned by lsm bpf prog.

Fixes: 520b7aa00d8c ("bpf: lsm: Initialize the BPF LSM hooks")
Reported-by: Xin Liu <liuxin350@huawei.com>
Signed-off-by: Xu Kuohai <xukuohai@huawei.com>
---
 include/linux/bpf.h   |  1 +
 kernel/bpf/btf.c      |  5 +++-
 kernel/bpf/verifier.c | 57 +++++++++++++++++++++++++++++++++++++------
 3 files changed, 55 insertions(+), 8 deletions(-)

diff --git a/include/linux/bpf.h b/include/linux/bpf.h
index 4f20f62f9d63..aac92857a5a5 100644
--- a/include/linux/bpf.h
+++ b/include/linux/bpf.h
@@ -917,6 +917,7 @@ struct bpf_insn_access_aux {
 		};
 	};
 	struct bpf_verifier_log *log; /* for verbose logs */
+	bool is_retval; /* is accessing function return value ? */
 };
 
 static inline void
diff --git a/kernel/bpf/btf.c b/kernel/bpf/btf.c
index 90c4a32d89ff..d593684d80c6 100644
--- a/kernel/bpf/btf.c
+++ b/kernel/bpf/btf.c
@@ -6227,8 +6227,11 @@ bool btf_ctx_access(int off, int size, enum bpf_access_type type,
 
 	if (arg == nr_args) {
 		switch (prog->expected_attach_type) {
-		case BPF_LSM_CGROUP:
 		case BPF_LSM_MAC:
+			/* mark we are accessing the return value */
+			info->is_retval = true;
+			fallthrough;
+		case BPF_LSM_CGROUP:
 		case BPF_TRACE_FEXIT:
 			/* When LSM programs are attached to void LSM hooks
 			 * they use FEXIT trampolines and when attached to
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index 63749ad5ac6b..c3387357bc0d 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -2325,6 +2325,25 @@ static void mark_reg_unknown(struct bpf_verifier_env *env,
 	__mark_reg_unknown(env, regs + regno);
 }
 
+static int __mark_reg_s32_range(struct bpf_verifier_env *env,
+				struct bpf_reg_state *regs,
+				u32 regno,
+				s32 s32_min,
+				s32 s32_max)
+{
+	struct bpf_reg_state *reg = regs + regno;
+
+	reg->s32_min_value = max_t(s32, reg->s32_min_value, s32_min);
+	reg->s32_max_value = min_t(s32, reg->s32_max_value, s32_max);
+
+	reg->smin_value = max_t(s64, reg->smin_value, s32_min);
+	reg->smax_value = min_t(s64, reg->smax_value, s32_max);
+
+	reg_bounds_sync(reg);
+
+	return reg_bounds_sanity_check(env, reg, "s32_range");
+}
+
 static void __mark_reg_not_init(const struct bpf_verifier_env *env,
 				struct bpf_reg_state *reg)
 {
@@ -5557,11 +5576,12 @@ static int check_packet_access(struct bpf_verifier_env *env, u32 regno, int off,
 /* check access to 'struct bpf_context' fields.  Supports fixed offsets only */
 static int check_ctx_access(struct bpf_verifier_env *env, int insn_idx, int off, int size,
 			    enum bpf_access_type t, enum bpf_reg_type *reg_type,
-			    struct btf **btf, u32 *btf_id)
+			    struct btf **btf, u32 *btf_id, bool *is_retval)
 {
 	struct bpf_insn_access_aux info = {
 		.reg_type = *reg_type,
 		.log = &env->log,
+		.is_retval = false,
 	};
 
 	if (env->ops->is_valid_access &&
@@ -5574,6 +5594,7 @@ static int check_ctx_access(struct bpf_verifier_env *env, int insn_idx, int off,
 		 * type of narrower access.
 		 */
 		*reg_type = info.reg_type;
+		*is_retval = info.is_retval;
 
 		if (base_type(*reg_type) == PTR_TO_BTF_ID) {
 			*btf = info.btf;
@@ -6715,6 +6736,17 @@ static int check_stack_access_within_bounds(
 	return grow_stack_state(env, state, -min_off /* size */);
 }
 
+static bool get_func_retval_range(struct bpf_prog *prog,
+				  struct bpf_retval_range *range)
+{
+	if (prog->type == BPF_PROG_TYPE_LSM &&
+		prog->expected_attach_type == BPF_LSM_MAC &&
+		!bpf_lsm_get_retval_range(prog, range)) {
+		return true;
+	}
+	return false;
+}
+
 /* check whether memory at (regno + off) is accessible for t = (read | write)
  * if t==write, value_regno is a register which value is stored into memory
  * if t==read, value_regno is a register which will receive the value from memory
@@ -6819,6 +6851,8 @@ static int check_mem_access(struct bpf_verifier_env *env, int insn_idx, u32 regn
 		if (!err && value_regno >= 0 && (t == BPF_READ || rdonly_mem))
 			mark_reg_unknown(env, regs, value_regno);
 	} else if (reg->type == PTR_TO_CTX) {
+		bool is_retval = false;
+		struct bpf_retval_range range;
 		enum bpf_reg_type reg_type = SCALAR_VALUE;
 		struct btf *btf = NULL;
 		u32 btf_id = 0;
@@ -6834,7 +6868,7 @@ static int check_mem_access(struct bpf_verifier_env *env, int insn_idx, u32 regn
 			return err;
 
 		err = check_ctx_access(env, insn_idx, off, size, t, &reg_type, &btf,
-				       &btf_id);
+				       &btf_id, &is_retval);
 		if (err)
 			verbose_linfo(env, insn_idx, "; ");
 		if (!err && t == BPF_READ && value_regno >= 0) {
@@ -6843,7 +6877,14 @@ static int check_mem_access(struct bpf_verifier_env *env, int insn_idx, u32 regn
 			 * case, we know the offset is zero.
 			 */
 			if (reg_type == SCALAR_VALUE) {
-				mark_reg_unknown(env, regs, value_regno);
+				if (is_retval && get_func_retval_range(env->prog, &range)) {
+					err = __mark_reg_s32_range(env, regs, value_regno,
+								   range.minval, range.maxval);
+					if (err)
+						return err;
+				} else {
+					mark_reg_unknown(env, regs, value_regno);
+				}
 			} else {
 				mark_reg_known_zero(env, regs,
 						    value_regno);
@@ -15466,10 +15507,12 @@ static int check_return_code(struct bpf_verifier_env *env, int regno, const char
 
 	case BPF_PROG_TYPE_LSM:
 		if (env->prog->expected_attach_type != BPF_LSM_CGROUP) {
-			/* Regular BPF_PROG_TYPE_LSM programs can return
-			 * any value.
-			 */
-			return 0;
+			/* no range found, any return value is allowed */
+			if (!get_func_retval_range(env->prog, &range))
+				return 0;
+			/* no restricted range, any return value is allowed */
+			if (range.minval == S32_MIN && range.maxval == S32_MAX)
+				return 0;
 		}
 		if (!env->prog->aux->attach_func_proto->type) {
 			/* Make sure programs that attach to void
-- 
2.30.2


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH bpf-next v2 5/7] bpf: Fix compare error in function retval_range_within
  2024-03-25  9:56 [PATCH bpf-next v2 0/7] Add check for bpf lsm return value Xu Kuohai
                   ` (3 preceding siblings ...)
  2024-03-25  9:56 ` [PATCH bpf-next v2 4/7] bpf, lsm: Check bpf lsm hook return values in verifier Xu Kuohai
@ 2024-03-25  9:56 ` Xu Kuohai
  2024-03-25  9:56 ` [PATCH bpf-next v2 6/7] selftests/bpf: Avoid load failure for token_lsm.c Xu Kuohai
                   ` (2 subsequent siblings)
  7 siblings, 0 replies; 13+ messages in thread
From: Xu Kuohai @ 2024-03-25  9:56 UTC (permalink / raw)
  To: bpf, linux-security-module
  Cc: Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko,
	Martin KaFai Lau, Eduard Zingerman, Song Liu, Yonghong Song,
	John Fastabend, KP Singh, Stanislav Fomichev, Hao Luo, Jiri Olsa,
	Florent Revest, Brendan Jackman, Paul Moore, James Morris,
	Serge E . Hallyn, Khadija Kamran, Casey Schaufler,
	Ondrej Mosnacek, Kees Cook, John Johansen, Lukas Bulwahn,
	Roberto Sassu, Shung-Hsi Yu

From: Xu Kuohai <xukuohai@huawei.com>

After checking lsm hook return range in verifier, the test case
"test_progs -t test_lsm" failed, and the failure log says:

libbpf: prog 'test_int_hook': BPF program load failed: Invalid argument
libbpf: prog 'test_int_hook': -- BEGIN PROG LOAD LOG --
0: R1=ctx() R10=fp0
; int BPF_PROG(test_int_hook, struct vm_area_struct *vma, @ lsm.c:89
0: (79) r0 = *(u64 *)(r1 +24)         ; R0_w=scalar(smin=smin32=-4095,smax=smax32=0) R1=ctx()

[...]

24: (b4) w0 = -1                      ; R0_w=0xffffffff
; int BPF_PROG(test_int_hook, struct vm_area_struct *vma, @ lsm.c:89
25: (95) exit
At program exit the register R0 has smin=4294967295 smax=4294967295 should have been in [-4095, 0]

It can be seen that instruction "w0 = -1" zero extended -1 to 64-bit
register r0, setting both smin and smax values of r0 to 4294967295.
This resulted in a false reject when r0 was checked with range [-4095, 0].

Given bpf_retval_range is a 32-bit range, this patch fixes it by
changing the compare between r0 and return range from 64-bit
operation to 32-bit operation.

Fixes: 8fa4ecd49b81 ("bpf: enforce exact retval range on subprog/callback exit")
Signed-off-by: Xu Kuohai <xukuohai@huawei.com>
---
 kernel/bpf/verifier.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index c3387357bc0d..36cd13982926 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -9864,7 +9864,7 @@ static bool in_rbtree_lock_required_cb(struct bpf_verifier_env *env)
 
 static bool retval_range_within(struct bpf_retval_range range, const struct bpf_reg_state *reg)
 {
-	return range.minval <= reg->smin_value && reg->smax_value <= range.maxval;
+	return range.minval <= reg->s32_min_value && reg->s32_max_value <= range.maxval;
 }
 
 static int prepare_func_exit(struct bpf_verifier_env *env, int *insn_idx)
-- 
2.30.2


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH bpf-next v2 6/7] selftests/bpf: Avoid load failure for token_lsm.c
  2024-03-25  9:56 [PATCH bpf-next v2 0/7] Add check for bpf lsm return value Xu Kuohai
                   ` (4 preceding siblings ...)
  2024-03-25  9:56 ` [PATCH bpf-next v2 5/7] bpf: Fix compare error in function retval_range_within Xu Kuohai
@ 2024-03-25  9:56 ` Xu Kuohai
  2024-03-25  9:56 ` [PATCH bpf-next v2 7/7] selftests/bpf: Add return value checks and corrections for failed progs Xu Kuohai
  2024-04-08 21:45 ` [PATCH bpf-next v2 0/7] Add check for bpf lsm return value KP Singh
  7 siblings, 0 replies; 13+ messages in thread
From: Xu Kuohai @ 2024-03-25  9:56 UTC (permalink / raw)
  To: bpf, linux-security-module
  Cc: Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko,
	Martin KaFai Lau, Eduard Zingerman, Song Liu, Yonghong Song,
	John Fastabend, KP Singh, Stanislav Fomichev, Hao Luo, Jiri Olsa,
	Florent Revest, Brendan Jackman, Paul Moore, James Morris,
	Serge E . Hallyn, Khadija Kamran, Casey Schaufler,
	Ondrej Mosnacek, Kees Cook, John Johansen, Lukas Bulwahn,
	Roberto Sassu, Shung-Hsi Yu

From: Xu Kuohai <xukuohai@huawei.com>

The compiler optimized the two bpf progs in token_lsm.c to make return
value from the bool variable in the "return -1" path, causing an
unexpected rejection:

0: R1=ctx() R10=fp0
; int BPF_PROG(bpf_token_capable, struct bpf_token *token, int cap) @ bpf_lsm.c:17
0: (b7) r6 = 0                        ; R6_w=0
; if (my_pid == 0 || my_pid != (bpf_get_current_pid_tgid() >> 32)) @ bpf_lsm.c:19
1: (18) r1 = 0xffffc9000102a000       ; R1_w=map_value(map=bpf_lsm.bss,ks=4,vs=5)
3: (61) r7 = *(u32 *)(r1 +0)          ; R1_w=map_value(map=bpf_lsm.bss,ks=4,vs=5) R7_w=scalar(smin=0,smax=umax=0xffffffff,var_off=(0x0; 0xffffffff))
4: (15) if r7 == 0x0 goto pc+11       ; R7_w=scalar(smin=umin=umin32=1,smax=umax=0xffffffff,var_off=(0x0; 0xffffffff))
5: (67) r7 <<= 32                     ; R7_w=scalar(smax=0x7fffffff00000000,umax=0xffffffff00000000,smin32=0,smax32=umax32=0,var_off=(0x0; 0xffffffff00000000))
6: (c7) r7 s>>= 32                    ; R7_w=scalar(smin=0xffffffff80000000,smax=0x7fffffff)
7: (85) call bpf_get_current_pid_tgid#14      ; R0=scalar()
8: (77) r0 >>= 32                     ; R0_w=scalar(smin=0,smax=umax=0xffffffff,var_off=(0x0; 0xffffffff))
9: (5d) if r0 != r7 goto pc+6         ; R0_w=scalar(smin=smin32=0,smax=umax=umax32=0x7fffffff,var_off=(0x0; 0x7fffffff)) R7=scalar(smin=smin32=0,smax=umax=umax32=0x7fffffff,var_off=(0x0; 0x7fffffff))
; if (reject_capable) @ bpf_lsm.c:21
10: (18) r1 = 0xffffc9000102a004      ; R1_w=map_value(map=bpf_lsm.bss,ks=4,vs=5,off=4)
12: (71) r6 = *(u8 *)(r1 +0)          ; R1_w=map_value(map=bpf_lsm.bss,ks=4,vs=5,off=4) R6_w=scalar(smin=smin32=0,smax=umax=smax32=umax32=255,var_off=(0x0; 0xff))
;  @ bpf_lsm.c:0
13: (87) r6 = -r6                     ; R6_w=scalar()
14: (67) r6 <<= 56                    ; R6_w=scalar(smax=0x7f00000000000000,umax=0xff00000000000000,smin32=0,smax32=umax32=0,var_off=(0x0; 0xff00000000000000))
15: (c7) r6 s>>= 56                   ; R6_w=scalar(smin=smin32=-128,smax=smax32=127)
; int BPF_PROG(bpf_token_capable, struct bpf_token *token, int cap) @ bpf_lsm.c:17
16: (bf) r0 = r6                      ; R0_w=scalar(id=1,smin=smin32=-128,smax=smax32=127) R6_w=scalar(id=1,smin=smin32=-128,smax=smax32=127)
17: (95) exit
At program exit the register R0 has smin=-128 smax=127 should have been in [-4095, 0]

To avoid this failure, change the variable type from bool to int.

Signed-off-by: Xu Kuohai <xukuohai@huawei.com>
---
 tools/testing/selftests/bpf/progs/token_lsm.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/tools/testing/selftests/bpf/progs/token_lsm.c b/tools/testing/selftests/bpf/progs/token_lsm.c
index e4d59b6ba743..a6002d073b1b 100644
--- a/tools/testing/selftests/bpf/progs/token_lsm.c
+++ b/tools/testing/selftests/bpf/progs/token_lsm.c
@@ -8,8 +8,8 @@
 char _license[] SEC("license") = "GPL";
 
 int my_pid;
-bool reject_capable;
-bool reject_cmd;
+int reject_capable;
+int reject_cmd;
 
 SEC("lsm/bpf_token_capable")
 int BPF_PROG(token_capable, struct bpf_token *token, int cap)
-- 
2.30.2


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH bpf-next v2 7/7] selftests/bpf: Add return value checks and corrections for failed progs
  2024-03-25  9:56 [PATCH bpf-next v2 0/7] Add check for bpf lsm return value Xu Kuohai
                   ` (5 preceding siblings ...)
  2024-03-25  9:56 ` [PATCH bpf-next v2 6/7] selftests/bpf: Avoid load failure for token_lsm.c Xu Kuohai
@ 2024-03-25  9:56 ` Xu Kuohai
  2024-04-08 21:45 ` [PATCH bpf-next v2 0/7] Add check for bpf lsm return value KP Singh
  7 siblings, 0 replies; 13+ messages in thread
From: Xu Kuohai @ 2024-03-25  9:56 UTC (permalink / raw)
  To: bpf, linux-security-module
  Cc: Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko,
	Martin KaFai Lau, Eduard Zingerman, Song Liu, Yonghong Song,
	John Fastabend, KP Singh, Stanislav Fomichev, Hao Luo, Jiri Olsa,
	Florent Revest, Brendan Jackman, Paul Moore, James Morris,
	Serge E . Hallyn, Khadija Kamran, Casey Schaufler,
	Ondrej Mosnacek, Kees Cook, John Johansen, Lukas Bulwahn,
	Roberto Sassu, Shung-Hsi Yu

From: Xu Kuohai <xukuohai@huawei.com>

The return ranges of some lsm test bpf progs can not be inferred by
the verifier accurately. To avoid erroneous rejections, add explicit
return value checks and corrections to these progs.

Signed-off-by: Xu Kuohai <xukuohai@huawei.com>
---
 tools/testing/selftests/bpf/progs/err.h                | 10 ++++++++++
 tools/testing/selftests/bpf/progs/test_sig_in_xattr.c  |  4 ++++
 .../selftests/bpf/progs/test_verify_pkcs7_sig.c        |  8 ++++++--
 .../selftests/bpf/progs/verifier_global_subprogs.c     |  7 ++++++-
 4 files changed, 26 insertions(+), 3 deletions(-)

diff --git a/tools/testing/selftests/bpf/progs/err.h b/tools/testing/selftests/bpf/progs/err.h
index d66d283d9e59..38529779a236 100644
--- a/tools/testing/selftests/bpf/progs/err.h
+++ b/tools/testing/selftests/bpf/progs/err.h
@@ -5,6 +5,16 @@
 #define MAX_ERRNO 4095
 #define IS_ERR_VALUE(x) (unsigned long)(void *)(x) >= (unsigned long)-MAX_ERRNO
 
+#define __STR(x) #x
+
+#define set_if_not_errno_or_zero(x, y)			\
+({							\
+	asm volatile ("if %0 s< -4095 goto +1\n"	\
+		      "if %0 s<= 0 goto +1\n"		\
+		      "%0 = " __STR(y) "\n"		\
+		      : "+r"(x));			\
+})
+
 static inline int IS_ERR_OR_NULL(const void *ptr)
 {
 	return !ptr || IS_ERR_VALUE((unsigned long)ptr);
diff --git a/tools/testing/selftests/bpf/progs/test_sig_in_xattr.c b/tools/testing/selftests/bpf/progs/test_sig_in_xattr.c
index 2f0eb1334d65..8ef6b39335b6 100644
--- a/tools/testing/selftests/bpf/progs/test_sig_in_xattr.c
+++ b/tools/testing/selftests/bpf/progs/test_sig_in_xattr.c
@@ -6,6 +6,7 @@
 #include <bpf/bpf_helpers.h>
 #include <bpf/bpf_tracing.h>
 #include "bpf_kfuncs.h"
+#include "err.h"
 
 char _license[] SEC("license") = "GPL";
 
@@ -79,5 +80,8 @@ int BPF_PROG(test_file_open, struct file *f)
 	ret = bpf_verify_pkcs7_signature(&digest_ptr, &sig_ptr, trusted_keyring);
 
 	bpf_key_put(trusted_keyring);
+
+	set_if_not_errno_or_zero(ret, -EFAULT);
+
 	return ret;
 }
diff --git a/tools/testing/selftests/bpf/progs/test_verify_pkcs7_sig.c b/tools/testing/selftests/bpf/progs/test_verify_pkcs7_sig.c
index f42e9f3831a1..12034a73ee2d 100644
--- a/tools/testing/selftests/bpf/progs/test_verify_pkcs7_sig.c
+++ b/tools/testing/selftests/bpf/progs/test_verify_pkcs7_sig.c
@@ -11,6 +11,7 @@
 #include <bpf/bpf_helpers.h>
 #include <bpf/bpf_tracing.h>
 #include "bpf_kfuncs.h"
+#include "err.h"
 
 #define MAX_DATA_SIZE (1024 * 1024)
 #define MAX_SIG_SIZE 1024
@@ -55,12 +56,12 @@ int BPF_PROG(bpf, int cmd, union bpf_attr *attr, unsigned int size)
 
 	ret = bpf_probe_read_kernel(&value, sizeof(value), &attr->value);
 	if (ret)
-		return ret;
+		goto out;
 
 	ret = bpf_copy_from_user(data_val, sizeof(struct data),
 				 (void *)(unsigned long)value);
 	if (ret)
-		return ret;
+		goto out;
 
 	if (data_val->data_len > sizeof(data_val->data))
 		return -EINVAL;
@@ -84,5 +85,8 @@ int BPF_PROG(bpf, int cmd, union bpf_attr *attr, unsigned int size)
 
 	bpf_key_put(trusted_keyring);
 
+out:
+	set_if_not_errno_or_zero(ret, -EFAULT);
+
 	return ret;
 }
diff --git a/tools/testing/selftests/bpf/progs/verifier_global_subprogs.c b/tools/testing/selftests/bpf/progs/verifier_global_subprogs.c
index baff5ffe9405..5df7a98a4c51 100644
--- a/tools/testing/selftests/bpf/progs/verifier_global_subprogs.c
+++ b/tools/testing/selftests/bpf/progs/verifier_global_subprogs.c
@@ -7,6 +7,7 @@
 #include "bpf_misc.h"
 #include "xdp_metadata.h"
 #include "bpf_kfuncs.h"
+#include "err.h"
 
 int arr[1];
 int unkn_idx;
@@ -324,7 +325,11 @@ SEC("?lsm/bpf")
 __success __log_level(2)
 int BPF_PROG(arg_tag_ctx_lsm)
 {
-	return tracing_subprog_void(ctx) + tracing_subprog_u64(ctx);
+	int ret;
+
+	ret = tracing_subprog_void(ctx) + tracing_subprog_u64(ctx);
+	set_if_not_errno_or_zero(ret, -1);
+	return ret;
 }
 
 SEC("?struct_ops/test_1")
-- 
2.30.2


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* Re: [PATCH bpf-next v2 2/7] bpf, lsm: Add return value range description for lsm hook
  2024-03-25  9:56 ` [PATCH bpf-next v2 2/7] bpf, lsm: Add return value range description for lsm hook Xu Kuohai
@ 2024-04-08 17:09   ` KP Singh
  2024-04-08 22:15     ` KP Singh
  0 siblings, 1 reply; 13+ messages in thread
From: KP Singh @ 2024-04-08 17:09 UTC (permalink / raw)
  To: Xu Kuohai
  Cc: bpf, linux-security-module, Alexei Starovoitov, Daniel Borkmann,
	Andrii Nakryiko, Martin KaFai Lau, Eduard Zingerman, Song Liu,
	Yonghong Song, John Fastabend, Stanislav Fomichev, Hao Luo,
	Jiri Olsa, Florent Revest, Brendan Jackman, Paul Moore,
	James Morris, Serge E . Hallyn, Khadija Kamran, Casey Schaufler,
	Ondrej Mosnacek, Kees Cook, John Johansen, Lukas Bulwahn,
	Roberto Sassu, Shung-Hsi Yu



> On 25 Mar 2024, at 10:56, Xu Kuohai <xukuohai@huaweicloud.com> wrote:
> 
> From: Xu Kuohai <xukuohai@huawei.com>
> 
> Add return value descriptions for lsm hook.
> 
> Two integer ranges are added:
> 
> 1. ERRNO: Integer between -MAX_ERRNO and 0, including -MAX_ERRNO and 0.
> 2. ANY: Any integer


I think you should merge this patch and the first patch. It's not clear that the first value in this macro is actually used as the default value until one reads the code. I think you also need to make it clear that there is no logical change on the LSM side in the this patch.

- KP

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH bpf-next v2 0/7] Add check for bpf lsm return value
  2024-03-25  9:56 [PATCH bpf-next v2 0/7] Add check for bpf lsm return value Xu Kuohai
                   ` (6 preceding siblings ...)
  2024-03-25  9:56 ` [PATCH bpf-next v2 7/7] selftests/bpf: Add return value checks and corrections for failed progs Xu Kuohai
@ 2024-04-08 21:45 ` KP Singh
  2024-04-10 12:34   ` Xu Kuohai
  7 siblings, 1 reply; 13+ messages in thread
From: KP Singh @ 2024-04-08 21:45 UTC (permalink / raw)
  To: Xu Kuohai
  Cc: bpf, linux-security-module, Alexei Starovoitov, Daniel Borkmann,
	Andrii Nakryiko, Martin KaFai Lau, Eduard Zingerman, Song Liu,
	Yonghong Song, John Fastabend, Stanislav Fomichev, Hao Luo,
	Jiri Olsa, Florent Revest, Brendan Jackman, Paul Moore,
	James Morris, Serge E . Hallyn, Khadija Kamran, Casey Schaufler,
	Ondrej Mosnacek, Kees Cook, John Johansen, Lukas Bulwahn,
	Roberto Sassu, Shung-Hsi Yu

On Mon, Mar 25, 2024 at 10:53 AM Xu Kuohai <xukuohai@huaweicloud.com> wrote:
>
> From: Xu Kuohai <xukuohai@huawei.com>
>
> A bpf prog returning positive number attached to file_alloc_security hook
> will make kernel panic.
>
> Here is a panic log:
>
> [  441.235774] BUG: kernel NULL pointer dereference, address: 00000000000009
> [  441.236748] #PF: supervisor write access in kernel mode
> [  441.237429] #PF: error_code(0x0002) - not-present page
> [  441.238119] PGD 800000000b02f067 P4D 800000000b02f067 PUD b031067 PMD 0
> [  441.238990] Oops: 0002 [#1] PREEMPT SMP PTI
> [  441.239546] CPU: 0 PID: 347 Comm: loader Not tainted 6.8.0-rc6-gafe0cbf23373 #22
> [  441.240496] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.15.0-0-g2dd4b4
> [  441.241933] RIP: 0010:alloc_file+0x4b/0x190
> [  441.242485] Code: 8b 04 25 c0 3c 1f 00 48 8b b0 30 0c 00 00 e8 9c fe ff ff 48 3d 00 f0 ff fb
> [  441.244820] RSP: 0018:ffffc90000c67c40 EFLAGS: 00010203
> [  441.245484] RAX: ffff888006a891a0 RBX: ffffffff8223bd00 RCX: 0000000035b08000
> [  441.246391] RDX: ffff88800b95f7b0 RSI: 00000000001fc110 RDI: f089cd0b8088ffff
> [  441.247294] RBP: ffffc90000c67c58 R08: 0000000000000001 R09: 0000000000000001
> [  441.248209] R10: 0000000000000001 R11: 0000000000000001 R12: 0000000000000001
> [  441.249108] R13: ffffc90000c67c78 R14: ffffffff8223bd00 R15: fffffffffffffff4
> [  441.250007] FS:  00000000005f3300(0000) GS:ffff88803ec00000(0000) knlGS:0000000000000000
> [  441.251053] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
> [  441.251788] CR2: 00000000000001a9 CR3: 000000000bdc4003 CR4: 0000000000170ef0
> [  441.252688] Call Trace:
> [  441.253011]  <TASK>
> [  441.253296]  ? __die+0x24/0x70
> [  441.253702]  ? page_fault_oops+0x15b/0x480
> [  441.254236]  ? fixup_exception+0x26/0x330
> [  441.254750]  ? exc_page_fault+0x6d/0x1c0
> [  441.255257]  ? asm_exc_page_fault+0x26/0x30
> [  441.255792]  ? alloc_file+0x4b/0x190
> [  441.256257]  alloc_file_pseudo+0x9f/0xf0
> [  441.256760]  __anon_inode_getfile+0x87/0x190
> [  441.257311]  ? lock_release+0x14e/0x3f0
> [  441.257808]  bpf_link_prime+0xe8/0x1d0
> [  441.258315]  bpf_tracing_prog_attach+0x311/0x570
> [  441.258916]  ? __pfx_bpf_lsm_file_alloc_security+0x10/0x10
> [  441.259605]  __sys_bpf+0x1bb7/0x2dc0
> [  441.260070]  __x64_sys_bpf+0x20/0x30
> [  441.260533]  do_syscall_64+0x72/0x140
> [  441.261004]  entry_SYSCALL_64_after_hwframe+0x6e/0x76
> [  441.261643] RIP: 0033:0x4b0349
> [  441.262045] Code: ff ff c3 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 40 00 48 89 f8 48 89 f7 48 88
> [  441.264355] RSP: 002b:00007fff74daee38 EFLAGS: 00000246 ORIG_RAX: 0000000000000141
> [  441.265293] RAX: ffffffffffffffda RBX: 00007fff74daef30 RCX: 00000000004b0349
> [  441.266187] RDX: 0000000000000040 RSI: 00007fff74daee50 RDI: 000000000000001c
> [  441.267114] RBP: 000000000000001b R08: 00000000005ef820 R09: 0000000000000000
> [  441.268018] R10: 0000000000000000 R11: 0000000000000246 R12: 0000000000000004
> [  441.268907] R13: 0000000000000004 R14: 00000000005ef018 R15: 00000000004004e8
>
> The reason is that the positive number returned by bpf prog is not a
> valid errno, and could not be filtered out with IS_ERR which is used by
> the file system to check errors. As a result, the filesystem mistakenly
> uses this random positive number as file pointer, causing panic.
>
> To fix this issue, there are two schemes:
>
> 1. Modify the calling sites of file_alloc_security to take positive
>    return values as zero.
>
> 2. Make the bpf verifier to ensure no unpredicted value returned by
>    lsm bpf prog.
>
> Considering that hook file_alloc_security never returned positive number
> before bpf lsm was introduced, and other lsm hooks may have the same
> problem, scheme 2 is more reasonable.
>
> So this patch set adds lsm return value check in verifier to fix it.
>
> v2:
> fix bpf ci failure
>
> v1:
> https://lore.kernel.org/bpf/20240316122359.1073787-1-xukuohai@huaweicloud.com/
>
> Xu Kuohai (7):
>   bpf, lsm: Annotate lsm hook return integer with new macro LSM_RET_INT
>   bpf, lsm: Add return value range description for lsm hook
>   bpf, lsm: Add function to read lsm hook return value range
>   bpf, lsm: Check bpf lsm hook return values in verifier
>   bpf: Fix compare error in function retval_range_within
>   selftests/bpf: Avoid load failure for token_lsm.c
>   selftests/bpf: Add return value checks and corrections for failed
>     progs

This series does not apply cleanly on any of the following branches:

bpf-next
bpf
linux
linux-next
or Paul's lsm branches

There are just too many merge conflicts in the lsm_hook_defs.h file.

- KP

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH bpf-next v2 2/7] bpf, lsm: Add return value range description for lsm hook
  2024-04-08 17:09   ` KP Singh
@ 2024-04-08 22:15     ` KP Singh
  2024-04-10 12:30       ` Xu Kuohai
  0 siblings, 1 reply; 13+ messages in thread
From: KP Singh @ 2024-04-08 22:15 UTC (permalink / raw)
  To: Xu Kuohai
  Cc: bpf, linux-security-module, Alexei Starovoitov, Daniel Borkmann,
	Andrii Nakryiko, Martin KaFai Lau, Eduard Zingerman, Song Liu,
	Yonghong Song, John Fastabend, Stanislav Fomichev, Hao Luo,
	Jiri Olsa, Florent Revest, Brendan Jackman, Paul Moore,
	James Morris, Serge E . Hallyn, Khadija Kamran, Casey Schaufler,
	Ondrej Mosnacek, Kees Cook, John Johansen, Lukas Bulwahn,
	Roberto Sassu, Shung-Hsi Yu

On Mon, Apr 8, 2024 at 7:09 PM KP Singh <kpsingh@kernel.org> wrote:
>
>
>
> > On 25 Mar 2024, at 10:56, Xu Kuohai <xukuohai@huaweicloud.com> wrote:
> >
> > From: Xu Kuohai <xukuohai@huawei.com>
> >
> > Add return value descriptions for lsm hook.
> >
> > Two integer ranges are added:
> >
> > 1. ERRNO: Integer between -MAX_ERRNO and 0, including -MAX_ERRNO and 0.

I also don't really like these special macros that imply a range. Why
not do something like?

  LSM_RET_INT(default, min, max)

You seemed to have missed the values returned by these hooks:

security_inode_need_killpriv
security_inode_getsecurity
security_inode_listsecurity
security_inode_copy_up_xattr
security_task_prctl

security_getprocattr
securitty_setprocattr
^^these two we should just disable in BPF LSM

security_ismaclabel
^^probably even this

There seem to be only a handful of these. Can we just manage it with a
BTF set on the BPF side?

- KP
> > 2. ANY: Any integer
>
>
> I think you should merge this patch and the first patch. It's not clear that the first value in this macro is actually used as the default value until one reads the code. I think you also need to make it clear that there is no logical change on the LSM side in the this patch.
>
> - KP

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH bpf-next v2 2/7] bpf, lsm: Add return value range description for lsm hook
  2024-04-08 22:15     ` KP Singh
@ 2024-04-10 12:30       ` Xu Kuohai
  0 siblings, 0 replies; 13+ messages in thread
From: Xu Kuohai @ 2024-04-10 12:30 UTC (permalink / raw)
  To: KP Singh
  Cc: bpf, linux-security-module, Alexei Starovoitov, Daniel Borkmann,
	Andrii Nakryiko, Martin KaFai Lau, Eduard Zingerman, Song Liu,
	Yonghong Song, John Fastabend, Stanislav Fomichev, Hao Luo,
	Jiri Olsa, Florent Revest, Brendan Jackman, Paul Moore,
	James Morris, Serge E . Hallyn, Khadija Kamran, Casey Schaufler,
	Ondrej Mosnacek, Kees Cook, John Johansen, Lukas Bulwahn,
	Roberto Sassu, Shung-Hsi Yu

On 4/9/2024 6:15 AM, KP Singh wrote:
> On Mon, Apr 8, 2024 at 7:09 PM KP Singh <kpsingh@kernel.org> wrote:
>>
>>
>>
>>> On 25 Mar 2024, at 10:56, Xu Kuohai <xukuohai@huaweicloud.com> wrote:
>>>
>>> From: Xu Kuohai <xukuohai@huawei.com>
>>>
>>> Add return value descriptions for lsm hook.
>>>
>>> Two integer ranges are added:
>>>
>>> 1. ERRNO: Integer between -MAX_ERRNO and 0, including -MAX_ERRNO and 0.
> 
> I also don't really like these special macros that imply a range. Why
> not do something like?
> 
>    LSM_RET_INT(default, min, max)
>

This also looks good to me, will update in next version.

> You seemed to have missed the values returned by these hooks:
> 
> security_inode_need_killpriv
> security_inode_getsecurity
> security_inode_listsecurity
> security_inode_copy_up_xattr
> security_task_prctl
> 
> security_getprocattr
> securitty_setprocattr
> ^^these two we should just disable in BPF LSM
> 
> security_ismaclabel
> ^^probably even this
>

Good catch! I've fixed the return value ranges based on the return value
description in file security/security.c.

Here are the fixed functions and their return ranges.

security_inode_need_killpriv			[-MAX_ERRNO, INT_MAX]
security_inode_getsecurity			[-MAX_ERRNO, INT_MAX]
security_inode_listsecurity			[-MAX_ERRNO, INT_MAX]
security_inode_copy_up_xattr			[-MAX_ERRNO, 1]
security_getselfattr				[-MAX_ERRNO, INT_MAX]
security_getprocattr				[-MAX_ERRNO, INT_MAX]
security_setprocattr				[-MAX_ERRNO, INT_MAX]
security_task_prctl				[-MAX_ERRNO, INT_MAX]
security_ismaclabel				[0, 1]
security_xfrm_state_pol_flow_match		[INT_MIN, INT_MAX]
security_key_getsecurity			[-MAX_ERRNO, INT_MAX]
security_audit_rule_known			[0, 1]
security_audit_rule_match			[-MAX_ERRNO, 1]

> There seem to be only a handful of these. Can we just manage it with a
> BTF set on the BPF side?
> 

I'll add a disabled bpf lsm hook list on the bpf side.

> - KP
>>> 2. ANY: Any integer
>>
>>
>> I think you should merge this patch and the first patch. It's not clear that the first value in this macro is actually used as the default value until one reads the code. I think you also need to make it clear that there is no logical change on the LSM side in the this patch.

OK.

>>
>> - KP


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH bpf-next v2 0/7] Add check for bpf lsm return value
  2024-04-08 21:45 ` [PATCH bpf-next v2 0/7] Add check for bpf lsm return value KP Singh
@ 2024-04-10 12:34   ` Xu Kuohai
  0 siblings, 0 replies; 13+ messages in thread
From: Xu Kuohai @ 2024-04-10 12:34 UTC (permalink / raw)
  To: KP Singh
  Cc: bpf, linux-security-module, Alexei Starovoitov, Daniel Borkmann,
	Andrii Nakryiko, Martin KaFai Lau, Eduard Zingerman, Song Liu,
	Yonghong Song, John Fastabend, Stanislav Fomichev, Hao Luo,
	Jiri Olsa, Florent Revest, Brendan Jackman, Paul Moore,
	James Morris, Serge E . Hallyn, Khadija Kamran, Casey Schaufler,
	Ondrej Mosnacek, Kees Cook, John Johansen, Lukas Bulwahn,
	Roberto Sassu, Shung-Hsi Yu

On 4/9/2024 5:45 AM, KP Singh wrote:
> On Mon, Mar 25, 2024 at 10:53 AM Xu Kuohai <xukuohai@huaweicloud.com> wrote:
>>
>> From: Xu Kuohai <xukuohai@huawei.com>
>>
>> A bpf prog returning positive number attached to file_alloc_security hook
>> will make kernel panic.
>>
>> Here is a panic log:
>>
>> [  441.235774] BUG: kernel NULL pointer dereference, address: 00000000000009
>> [  441.236748] #PF: supervisor write access in kernel mode
>> [  441.237429] #PF: error_code(0x0002) - not-present page
>> [  441.238119] PGD 800000000b02f067 P4D 800000000b02f067 PUD b031067 PMD 0
>> [  441.238990] Oops: 0002 [#1] PREEMPT SMP PTI
>> [  441.239546] CPU: 0 PID: 347 Comm: loader Not tainted 6.8.0-rc6-gafe0cbf23373 #22
>> [  441.240496] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.15.0-0-g2dd4b4
>> [  441.241933] RIP: 0010:alloc_file+0x4b/0x190
>> [  441.242485] Code: 8b 04 25 c0 3c 1f 00 48 8b b0 30 0c 00 00 e8 9c fe ff ff 48 3d 00 f0 ff fb
>> [  441.244820] RSP: 0018:ffffc90000c67c40 EFLAGS: 00010203
>> [  441.245484] RAX: ffff888006a891a0 RBX: ffffffff8223bd00 RCX: 0000000035b08000
>> [  441.246391] RDX: ffff88800b95f7b0 RSI: 00000000001fc110 RDI: f089cd0b8088ffff
>> [  441.247294] RBP: ffffc90000c67c58 R08: 0000000000000001 R09: 0000000000000001
>> [  441.248209] R10: 0000000000000001 R11: 0000000000000001 R12: 0000000000000001
>> [  441.249108] R13: ffffc90000c67c78 R14: ffffffff8223bd00 R15: fffffffffffffff4
>> [  441.250007] FS:  00000000005f3300(0000) GS:ffff88803ec00000(0000) knlGS:0000000000000000
>> [  441.251053] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
>> [  441.251788] CR2: 00000000000001a9 CR3: 000000000bdc4003 CR4: 0000000000170ef0
>> [  441.252688] Call Trace:
>> [  441.253011]  <TASK>
>> [  441.253296]  ? __die+0x24/0x70
>> [  441.253702]  ? page_fault_oops+0x15b/0x480
>> [  441.254236]  ? fixup_exception+0x26/0x330
>> [  441.254750]  ? exc_page_fault+0x6d/0x1c0
>> [  441.255257]  ? asm_exc_page_fault+0x26/0x30
>> [  441.255792]  ? alloc_file+0x4b/0x190
>> [  441.256257]  alloc_file_pseudo+0x9f/0xf0
>> [  441.256760]  __anon_inode_getfile+0x87/0x190
>> [  441.257311]  ? lock_release+0x14e/0x3f0
>> [  441.257808]  bpf_link_prime+0xe8/0x1d0
>> [  441.258315]  bpf_tracing_prog_attach+0x311/0x570
>> [  441.258916]  ? __pfx_bpf_lsm_file_alloc_security+0x10/0x10
>> [  441.259605]  __sys_bpf+0x1bb7/0x2dc0
>> [  441.260070]  __x64_sys_bpf+0x20/0x30
>> [  441.260533]  do_syscall_64+0x72/0x140
>> [  441.261004]  entry_SYSCALL_64_after_hwframe+0x6e/0x76
>> [  441.261643] RIP: 0033:0x4b0349
>> [  441.262045] Code: ff ff c3 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 40 00 48 89 f8 48 89 f7 48 88
>> [  441.264355] RSP: 002b:00007fff74daee38 EFLAGS: 00000246 ORIG_RAX: 0000000000000141
>> [  441.265293] RAX: ffffffffffffffda RBX: 00007fff74daef30 RCX: 00000000004b0349
>> [  441.266187] RDX: 0000000000000040 RSI: 00007fff74daee50 RDI: 000000000000001c
>> [  441.267114] RBP: 000000000000001b R08: 00000000005ef820 R09: 0000000000000000
>> [  441.268018] R10: 0000000000000000 R11: 0000000000000246 R12: 0000000000000004
>> [  441.268907] R13: 0000000000000004 R14: 00000000005ef018 R15: 00000000004004e8
>>
>> The reason is that the positive number returned by bpf prog is not a
>> valid errno, and could not be filtered out with IS_ERR which is used by
>> the file system to check errors. As a result, the filesystem mistakenly
>> uses this random positive number as file pointer, causing panic.
>>
>> To fix this issue, there are two schemes:
>>
>> 1. Modify the calling sites of file_alloc_security to take positive
>>     return values as zero.
>>
>> 2. Make the bpf verifier to ensure no unpredicted value returned by
>>     lsm bpf prog.
>>
>> Considering that hook file_alloc_security never returned positive number
>> before bpf lsm was introduced, and other lsm hooks may have the same
>> problem, scheme 2 is more reasonable.
>>
>> So this patch set adds lsm return value check in verifier to fix it.
>>
>> v2:
>> fix bpf ci failure
>>
>> v1:
>> https://lore.kernel.org/bpf/20240316122359.1073787-1-xukuohai@huaweicloud.com/
>>
>> Xu Kuohai (7):
>>    bpf, lsm: Annotate lsm hook return integer with new macro LSM_RET_INT
>>    bpf, lsm: Add return value range description for lsm hook
>>    bpf, lsm: Add function to read lsm hook return value range
>>    bpf, lsm: Check bpf lsm hook return values in verifier
>>    bpf: Fix compare error in function retval_range_within
>>    selftests/bpf: Avoid load failure for token_lsm.c
>>    selftests/bpf: Add return value checks and corrections for failed
>>      progs
> 
> This series does not apply cleanly on any of the following branches:
> 
> bpf-next
> bpf
> linux
> linux-next
> or Paul's lsm branches
> 
> There are just too many merge conflicts in the lsm_hook_defs.h file.
>

Oh, the series is a bit out of date, will rebase to the latest bpf-next branch.

> - KP


^ permalink raw reply	[flat|nested] 13+ messages in thread

end of thread, other threads:[~2024-04-10 12:34 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-03-25  9:56 [PATCH bpf-next v2 0/7] Add check for bpf lsm return value Xu Kuohai
2024-03-25  9:56 ` [PATCH bpf-next v2 1/7] bpf, lsm: Annotate lsm hook return integer with new macro LSM_RET_INT Xu Kuohai
2024-03-25  9:56 ` [PATCH bpf-next v2 2/7] bpf, lsm: Add return value range description for lsm hook Xu Kuohai
2024-04-08 17:09   ` KP Singh
2024-04-08 22:15     ` KP Singh
2024-04-10 12:30       ` Xu Kuohai
2024-03-25  9:56 ` [PATCH bpf-next v2 3/7] bpf, lsm: Add function to read lsm hook return value range Xu Kuohai
2024-03-25  9:56 ` [PATCH bpf-next v2 4/7] bpf, lsm: Check bpf lsm hook return values in verifier Xu Kuohai
2024-03-25  9:56 ` [PATCH bpf-next v2 5/7] bpf: Fix compare error in function retval_range_within Xu Kuohai
2024-03-25  9:56 ` [PATCH bpf-next v2 6/7] selftests/bpf: Avoid load failure for token_lsm.c Xu Kuohai
2024-03-25  9:56 ` [PATCH bpf-next v2 7/7] selftests/bpf: Add return value checks and corrections for failed progs Xu Kuohai
2024-04-08 21:45 ` [PATCH bpf-next v2 0/7] Add check for bpf lsm return value KP Singh
2024-04-10 12:34   ` Xu Kuohai

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).