From 97f576eb38ae219a6fb337d13586d8acbf01d3f8 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Thu, 17 Aug 2023 13:35:02 -0700 Subject: [PATCH 01/28] audit: Annotate struct audit_chunk with __counted_by Prepare for the coming implementation by GCC and Clang of the __counted_by attribute. Flexible array members annotated with __counted_by can have their accesses bounds-checked at run-time checking via CONFIG_UBSAN_BOUNDS (for array indexing) and CONFIG_FORTIFY_SOURCE (for strcpy/memcpy-family functions). As found with Coccinelle[1], add __counted_by for struct audit_chunk. [1] https://github.com/kees/kernel-tools/blob/trunk/coccinelle/examples/counted_by.cocci Cc: Paul Moore Cc: Eric Paris Cc: audit@vger.kernel.org Signed-off-by: Kees Cook Reviewed-by: "Gustavo A. R. Silva" Signed-off-by: Paul Moore --- kernel/audit_tree.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/audit_tree.c b/kernel/audit_tree.c index e867c17d3f84..85a5b306733b 100644 --- a/kernel/audit_tree.c +++ b/kernel/audit_tree.c @@ -34,7 +34,7 @@ struct audit_chunk { struct list_head list; struct audit_tree *owner; unsigned index; /* index; upper bit indicates 'will prune' */ - } owners[]; + } owners[] __counted_by(count); }; struct audit_tree_mark { From 34df25517a9bbec3436ab6f53074bcce9dc3eafc Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Thu, 17 Aug 2023 13:22:17 -0700 Subject: [PATCH 02/28] selinux: Annotate struct sidtab_str_cache with __counted_by Prepare for the coming implementation by GCC and Clang of the __counted_by attribute. Flexible array members annotated with __counted_by can have their accesses bounds-checked at run-time checking via CONFIG_UBSAN_BOUNDS (for array indexing) and CONFIG_FORTIFY_SOURCE (for strcpy/memcpy-family functions). As found with Coccinelle[1], add __counted_by for struct sidtab_str_cache. [1] https://github.com/kees/kernel-tools/blob/trunk/coccinelle/examples/counted_by.cocci Cc: Paul Moore Cc: Stephen Smalley Cc: Eric Paris Cc: Ondrej Mosnacek Cc: selinux@vger.kernel.org Signed-off-by: Kees Cook Reviewed-by: "Gustavo A. R. Silva" Signed-off-by: Paul Moore --- security/selinux/ss/sidtab.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/security/selinux/ss/sidtab.c b/security/selinux/ss/sidtab.c index d8ead463b8df..732fd8e22a12 100644 --- a/security/selinux/ss/sidtab.c +++ b/security/selinux/ss/sidtab.c @@ -25,7 +25,7 @@ struct sidtab_str_cache { struct list_head lru_member; struct sidtab_entry *parent; u32 len; - char str[]; + char str[] __counted_by(len); }; #define index_to_sid(index) ((index) + SECINITSID_NUM + 1) From fb8142ff4a642f14c4805980efb7531854c5dbdf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20G=C3=B6ttsche?= Date: Fri, 18 Aug 2023 17:12:18 +0200 Subject: [PATCH 03/28] selinux: print sum of chain lengths^2 for hash tables MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Print the sum of chain lengths squared as a metric for hash tables to provide more insights, similar to avtabs. While on it add a comma in the avtab message to improve readability of the output. Signed-off-by: Christian Göttsche Reviewed-by: Stephen Smalley Signed-off-by: Paul Moore --- security/selinux/ss/avtab.c | 2 +- security/selinux/ss/hashtab.c | 5 +++++ security/selinux/ss/hashtab.h | 1 + security/selinux/ss/policydb.c | 4 ++-- 4 files changed, 9 insertions(+), 3 deletions(-) diff --git a/security/selinux/ss/avtab.c b/security/selinux/ss/avtab.c index 86d98a8e291b..955cfe495606 100644 --- a/security/selinux/ss/avtab.c +++ b/security/selinux/ss/avtab.c @@ -349,7 +349,7 @@ void avtab_hash_eval(struct avtab *h, const char *tag) } pr_debug("SELinux: %s: %d entries and %d/%d buckets used, " - "longest chain length %d sum of chain length^2 %llu\n", + "longest chain length %d, sum of chain length^2 %llu\n", tag, h->nel, slots_used, h->nslot, max_chain_len, chain2_len_sum); } diff --git a/security/selinux/ss/hashtab.c b/security/selinux/ss/hashtab.c index ac5cdddfbf78..c05d8346a94a 100644 --- a/security/selinux/ss/hashtab.c +++ b/security/selinux/ss/hashtab.c @@ -107,10 +107,12 @@ int hashtab_map(struct hashtab *h, void hashtab_stat(struct hashtab *h, struct hashtab_info *info) { u32 i, chain_len, slots_used, max_chain_len; + u64 chain2_len_sum; struct hashtab_node *cur; slots_used = 0; max_chain_len = 0; + chain2_len_sum = 0; for (i = 0; i < h->size; i++) { cur = h->htable[i]; if (cur) { @@ -123,11 +125,14 @@ void hashtab_stat(struct hashtab *h, struct hashtab_info *info) if (chain_len > max_chain_len) max_chain_len = chain_len; + + chain2_len_sum += (u64)chain_len * chain_len; } } info->slots_used = slots_used; info->max_chain_len = max_chain_len; + info->chain2_len_sum = chain2_len_sum; } #endif /* CONFIG_SECURITY_SELINUX_DEBUG */ diff --git a/security/selinux/ss/hashtab.h b/security/selinux/ss/hashtab.h index f9713b56d3d0..09b0a3744937 100644 --- a/security/selinux/ss/hashtab.h +++ b/security/selinux/ss/hashtab.h @@ -38,6 +38,7 @@ struct hashtab { struct hashtab_info { u32 slots_used; u32 max_chain_len; + u64 chain2_len_sum; }; /* diff --git a/security/selinux/ss/policydb.c b/security/selinux/ss/policydb.c index 2d528f699a22..d420c6c12f54 100644 --- a/security/selinux/ss/policydb.c +++ b/security/selinux/ss/policydb.c @@ -684,9 +684,9 @@ static void hash_eval(struct hashtab *h, const char *hash_name) struct hashtab_info info; hashtab_stat(h, &info); - pr_debug("SELinux: %s: %d entries and %d/%d buckets used, longest chain length %d\n", + pr_debug("SELinux: %s: %d entries and %d/%d buckets used, longest chain length %d, sum of chain length^2 %llu\n", hash_name, h->nel, info.slots_used, h->size, - info.max_chain_len); + info.max_chain_len, info.chain2_len_sum); } static void symtab_hash_eval(struct symtab *s) From 6f594f5a3dc4917be1556e524673420197ca471d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20G=C3=B6ttsche?= Date: Fri, 18 Aug 2023 17:12:14 +0200 Subject: [PATCH 04/28] selinux: improve debug configuration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If the SELinux debug configuration is enabled define the macro DEBUG such that pr_debug() calls are always enabled, regardless of CONFIG_DYNAMIC_DEBUG, since those message are the main reason for this configuration in the first place. Mention example usage in case CONFIG_DYNAMIC_DEBUG is enabled in the help section of the configuration. Signed-off-by: Christian Göttsche Reviewed-by: Stephen Smalley Signed-off-by: Paul Moore --- security/selinux/Kconfig | 10 ++++++++++ security/selinux/Makefile | 2 ++ 2 files changed, 12 insertions(+) diff --git a/security/selinux/Kconfig b/security/selinux/Kconfig index d30348fbe0df..61abc1e094a8 100644 --- a/security/selinux/Kconfig +++ b/security/selinux/Kconfig @@ -77,3 +77,13 @@ config SECURITY_SELINUX_DEBUG This enables debugging code designed to help SELinux kernel developers, unless you know what this does in the kernel code you should leave this disabled. + + To fine control the messages to be printed enable + CONFIG_DYNAMIC_DEBUG and see + Documentation/admin-guide/dynamic-debug-howto.rst for additional + information. + + Example usage: + + echo -n 'file "security/selinux/*" +p' > \ + /proc/dynamic_debug/control diff --git a/security/selinux/Makefile b/security/selinux/Makefile index 836379639058..c47519ed8156 100644 --- a/security/selinux/Makefile +++ b/security/selinux/Makefile @@ -12,6 +12,8 @@ obj-$(CONFIG_SECURITY_SELINUX) := selinux.o ccflags-y := -I$(srctree)/security/selinux -I$(srctree)/security/selinux/include +ccflags-$(CONFIG_SECURITY_SELINUX_DEBUG) += -DDEBUG + selinux-y := avc.o hooks.o selinuxfs.o netlink.o nlmsgtab.o netif.o \ netnode.o netport.o status.o \ ss/ebitmap.o ss/hashtab.o ss/symtab.o ss/sidtab.o ss/avtab.o \ From 7969ba577636a83553baf95882eb310b39e1c742 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20G=C3=B6ttsche?= Date: Fri, 18 Aug 2023 17:12:15 +0200 Subject: [PATCH 05/28] selinux: simplify avtab slot calculation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of dividing by 8 and then performing log2 by hand, use a more readable calculation. The behavior of rounddown_pow_of_two() for an input of 0 is undefined, so handle that case and small values manually to achieve the same results. Signed-off-by: Christian Göttsche Reviewed-by: Stephen Smalley Signed-off-by: Paul Moore --- security/selinux/ss/avtab.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/security/selinux/ss/avtab.c b/security/selinux/ss/avtab.c index 955cfe495606..1d1ffe085b35 100644 --- a/security/selinux/ss/avtab.c +++ b/security/selinux/ss/avtab.c @@ -298,13 +298,7 @@ int avtab_alloc(struct avtab *h, u32 nrules) u32 nslot = 0; if (nrules != 0) { - u32 shift = 1; - u32 work = nrules >> 3; - while (work) { - work >>= 1; - shift++; - } - nslot = 1 << shift; + nslot = nrules > 3 ? rounddown_pow_of_two(nrules / 2) : 2; if (nslot > MAX_AVTAB_HASH_BUCKETS) nslot = MAX_AVTAB_HASH_BUCKETS; From 37b7ea3ca3062f5b7f02c2b335f203e4d411793d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20G=C3=B6ttsche?= Date: Fri, 18 Aug 2023 17:12:16 +0200 Subject: [PATCH 06/28] selinux: improve role transition hashing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The number of buckets is calculated by performing a binary AND against the mask of the hash table, which is one less than its size (which is a power of two). This leads to all top bits being discarded, e.g. with the Reference Policy on Debian there exists 376 entries, leading to a size of 512, discarding the top 23 bits. Use jhash to improve the hash table utilization: # current roletr: 376 entries and 124/512 buckets used, longest chain length 8, sum of chain length^2 1496 # patch roletr: 376 entries and 266/512 buckets used, longest chain length 4, sum of chain length^2 646 Signed-off-by: Christian Göttsche Reviewed-by: Stephen Smalley [PM: line wrap in the commit description] Signed-off-by: Paul Moore --- security/selinux/ss/policydb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/security/selinux/ss/policydb.c b/security/selinux/ss/policydb.c index d420c6c12f54..595a435ea9c8 100644 --- a/security/selinux/ss/policydb.c +++ b/security/selinux/ss/policydb.c @@ -491,7 +491,7 @@ static u32 role_trans_hash(const void *k) { const struct role_trans_key *key = k; - return key->role + (key->type << 3) + (key->tclass << 5); + return jhash_3words(key->role, key->type, (u32)key->tclass << 16 | key->tclass, 0); } static int role_trans_cmp(const void *k1, const void *k2) From 9d140885e35dac6dff2c56eccacc13f4fc96188a Mon Sep 17 00:00:00 2001 From: Jacob Satterfield Date: Wed, 6 Sep 2023 15:46:06 +0000 Subject: [PATCH 07/28] selinux: hweight optimization in avtab_read_item avtab_read_item() is a hot function called when reading each rule in a binary policydb. With the current Fedora policy and refpolicy, this function is called nearly 100,000 times per policy load. A single avtab node is only permitted to have a single specifier to describe the data it holds. As such, a check is performed to make sure only one specifier is set. Previously this was done via a for-loop. However, there is already an optimal function for finding the number of bits set (hamming weight) and on some architectures, dedicated instructions (popcount) which can be executed much more efficiently. Even when using -mcpu=generic on a x86-64 Fedora 38 VM, this commit results in a modest 2-4% speedup for policy loading due to a substantial reduction in the number of instructions executed. Signed-off-by: Jacob Satterfield Reviewed-by: Stephen Smalley Signed-off-by: Paul Moore --- security/selinux/ss/avtab.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/security/selinux/ss/avtab.c b/security/selinux/ss/avtab.c index 1d1ffe085b35..095b8cd24806 100644 --- a/security/selinux/ss/avtab.c +++ b/security/selinux/ss/avtab.c @@ -17,6 +17,7 @@ * Tuned number of hash slots for avtab to reduce memory usage */ +#include #include #include #include @@ -471,11 +472,7 @@ int avtab_read_item(struct avtab *a, void *fp, struct policydb *pol, return -EINVAL; } - set = 0; - for (i = 0; i < ARRAY_SIZE(spec_order); i++) { - if (key.specified & spec_order[i]) - set++; - } + set = hweight16(key.specified & (AVTAB_XPERMS | AVTAB_TYPE | AVTAB_AV)); if (!set || set > 1) { pr_err("SELinux: avtab: more than one specifier\n"); return -EINVAL; From 25cc71d1527b55c880d333e7cc1dc37aeef9843f Mon Sep 17 00:00:00 2001 From: Khadija Kamran Date: Wed, 23 Aug 2023 11:44:41 +0500 Subject: [PATCH 08/28] lsm: constify 'sb' parameter in security_quotactl() SELinux registers the implementation for the "quotactl" hook. Looking at the function implementation we observe that the parameter "sb" is not changing. Mark the "sb" parameter of LSM hook security_quotactl() as "const" since it will not be changing in the LSM hook. Signed-off-by: Khadija Kamran Signed-off-by: Paul Moore --- include/linux/lsm_hook_defs.h | 2 +- include/linux/security.h | 4 ++-- security/security.c | 2 +- security/selinux/hooks.c | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/include/linux/lsm_hook_defs.h b/include/linux/lsm_hook_defs.h index ac962c4cb44b..b464f9c1894f 100644 --- a/include/linux/lsm_hook_defs.h +++ b/include/linux/lsm_hook_defs.h @@ -43,7 +43,7 @@ LSM_HOOK(int, 0, capset, struct cred *new, const struct cred *old, const kernel_cap_t *permitted) LSM_HOOK(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, struct super_block *sb) +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, diff --git a/include/linux/security.h b/include/linux/security.h index 5f16eecde00b..1a02e67e682f 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -284,7 +284,7 @@ int security_capable(const struct cred *cred, struct user_namespace *ns, int cap, unsigned int opts); -int security_quotactl(int cmds, int type, int id, struct super_block *sb); +int security_quotactl(int cmds, int type, int id, const struct super_block *sb); int security_quota_on(struct dentry *dentry); int security_syslog(int type); int security_settime64(const struct timespec64 *ts, const struct timezone *tz); @@ -581,7 +581,7 @@ static inline int security_capable(const struct cred *cred, } static inline int security_quotactl(int cmds, int type, int id, - struct super_block *sb) + const struct super_block *sb) { return 0; } diff --git a/security/security.c b/security/security.c index 23b129d482a7..b944b19e4512 100644 --- a/security/security.c +++ b/security/security.c @@ -957,7 +957,7 @@ int security_capable(const struct cred *cred, * * Return: Returns 0 if permission is granted. */ -int security_quotactl(int cmds, int type, int id, struct super_block *sb) +int security_quotactl(int cmds, int type, int id, const struct super_block *sb) { return call_int_hook(quotactl, 0, cmds, type, id, sb); } diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 10350534de6d..e1c7640a5df1 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -1937,7 +1937,7 @@ static inline int may_rename(struct inode *old_dir, /* Check whether a task can perform a filesystem operation. */ static int superblock_has_perm(const struct cred *cred, - struct super_block *sb, + const struct super_block *sb, u32 perms, struct common_audit_data *ad) { @@ -2139,7 +2139,7 @@ static int selinux_capable(const struct cred *cred, struct user_namespace *ns, return cred_has_capability(cred, cap, opts, ns == &init_user_ns); } -static int selinux_quotactl(int cmds, int type, int id, struct super_block *sb) +static int selinux_quotactl(int cmds, int type, int id, const struct super_block *sb) { const struct cred *cred = current_cred(); int rc = 0; From 4a00c673068e72c12d243f5c31000246d6984e44 Mon Sep 17 00:00:00 2001 From: Khadija Kamran Date: Wed, 23 Aug 2023 12:17:29 +0500 Subject: [PATCH 09/28] lsm: constify 'file' parameter in security_bprm_creds_from_file() The 'bprm_creds_from_file' hook has implementation registered in commoncap. Looking at the function implementation we observe that the 'file' parameter is not changing. Mark the 'file' parameter of LSM hook security_bprm_creds_from_file() as 'const' since it will not be changing in the LSM hook. Signed-off-by: Khadija Kamran Signed-off-by: Paul Moore --- include/linux/fs.h | 2 +- include/linux/lsm_hook_defs.h | 2 +- include/linux/security.h | 6 +++--- security/commoncap.c | 4 ++-- security/security.c | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/include/linux/fs.h b/include/linux/fs.h index 4aeb3fa11927..f69d085e531f 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -2450,7 +2450,7 @@ struct filename { }; static_assert(offsetof(struct filename, iname) % sizeof(long) == 0); -static inline struct mnt_idmap *file_mnt_idmap(struct file *file) +static inline struct mnt_idmap *file_mnt_idmap(const struct file *file) { return mnt_idmap(file->f_path.mnt); } diff --git a/include/linux/lsm_hook_defs.h b/include/linux/lsm_hook_defs.h index b464f9c1894f..5dfe67d69aba 100644 --- a/include/linux/lsm_hook_defs.h +++ b/include/linux/lsm_hook_defs.h @@ -50,7 +50,7 @@ LSM_HOOK(int, 0, settime, const struct timespec64 *ts, const struct timezone *tz) LSM_HOOK(int, 0, 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, struct file *file) +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(void, LSM_RET_VOID, bprm_committing_creds, struct linux_binprm *bprm) LSM_HOOK(void, LSM_RET_VOID, bprm_committed_creds, struct linux_binprm *bprm) diff --git a/include/linux/security.h b/include/linux/security.h index 1a02e67e682f..edbea3e0a13f 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -151,7 +151,7 @@ extern int cap_capset(struct cred *new, const struct cred *old, const kernel_cap_t *effective, const kernel_cap_t *inheritable, const kernel_cap_t *permitted); -extern int cap_bprm_creds_from_file(struct linux_binprm *bprm, struct file *file); +extern int cap_bprm_creds_from_file(struct linux_binprm *bprm, const struct file *file); int cap_inode_setxattr(struct dentry *dentry, const char *name, const void *value, size_t size, int flags); int cap_inode_removexattr(struct mnt_idmap *idmap, @@ -290,7 +290,7 @@ int security_syslog(int type); int security_settime64(const struct timespec64 *ts, const struct timezone *tz); int security_vm_enough_memory_mm(struct mm_struct *mm, long pages); int security_bprm_creds_for_exec(struct linux_binprm *bprm); -int security_bprm_creds_from_file(struct linux_binprm *bprm, struct file *file); +int security_bprm_creds_from_file(struct linux_binprm *bprm, const struct file *file); int security_bprm_check(struct linux_binprm *bprm); void security_bprm_committing_creds(struct linux_binprm *bprm); void security_bprm_committed_creds(struct linux_binprm *bprm); @@ -613,7 +613,7 @@ static inline int security_bprm_creds_for_exec(struct linux_binprm *bprm) } static inline int security_bprm_creds_from_file(struct linux_binprm *bprm, - struct file *file) + const struct file *file) { return cap_bprm_creds_from_file(bprm, file); } diff --git a/security/commoncap.c b/security/commoncap.c index bc0521104197..8e8c630ce204 100644 --- a/security/commoncap.c +++ b/security/commoncap.c @@ -720,7 +720,7 @@ int get_vfs_caps_from_disk(struct mnt_idmap *idmap, * its xattrs and, if present, apply them to the proposed credentials being * constructed by execve(). */ -static int get_file_caps(struct linux_binprm *bprm, struct file *file, +static int get_file_caps(struct linux_binprm *bprm, const struct file *file, bool *effective, bool *has_fcap) { int rc = 0; @@ -882,7 +882,7 @@ static inline bool nonroot_raised_pE(struct cred *new, const struct cred *old, * * Return: 0 if successful, -ve on error. */ -int cap_bprm_creds_from_file(struct linux_binprm *bprm, struct file *file) +int cap_bprm_creds_from_file(struct linux_binprm *bprm, const struct file *file) { /* Process setpcap binaries and capabilities for uid 0 */ const struct cred *old = current_cred(); diff --git a/security/security.c b/security/security.c index b944b19e4512..bde8813e89ff 100644 --- a/security/security.c +++ b/security/security.c @@ -1079,7 +1079,7 @@ int security_bprm_creds_for_exec(struct linux_binprm *bprm) * * Return: Returns 0 if the hook is successful and permission is granted. */ -int security_bprm_creds_from_file(struct linux_binprm *bprm, struct file *file) +int security_bprm_creds_from_file(struct linux_binprm *bprm, const struct file *file) { return call_int_hook(bprm_creds_from_file, 0, bprm, file); } From 64fc9526147c7fc14535134d8ea79b9c8dc549a7 Mon Sep 17 00:00:00 2001 From: Khadija Kamran Date: Wed, 23 Aug 2023 12:47:56 +0500 Subject: [PATCH 10/28] lsm: constify 'bprm' parameter in security_bprm_committing_creds() The 'bprm_committing_creds' hook has implementations registered in SELinux and Apparmor. Looking at the function implementations we observe that the 'bprm' parameter is not changing. Mark the 'bprm' parameter of LSM hook security_bprm_committing_creds() as 'const' since it will not be changing in the LSM hook. Signed-off-by: Khadija Kamran Signed-off-by: Paul Moore --- include/linux/lsm_hook_defs.h | 2 +- include/linux/security.h | 4 ++-- security/apparmor/lsm.c | 2 +- security/security.c | 2 +- security/selinux/hooks.c | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/include/linux/lsm_hook_defs.h b/include/linux/lsm_hook_defs.h index 5dfe67d69aba..f6acc3ed66a3 100644 --- a/include/linux/lsm_hook_defs.h +++ b/include/linux/lsm_hook_defs.h @@ -52,7 +52,7 @@ LSM_HOOK(int, 0, 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(void, LSM_RET_VOID, bprm_committing_creds, 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, 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, diff --git a/include/linux/security.h b/include/linux/security.h index edbea3e0a13f..885053f81019 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -292,7 +292,7 @@ int security_vm_enough_memory_mm(struct mm_struct *mm, long pages); int security_bprm_creds_for_exec(struct linux_binprm *bprm); int security_bprm_creds_from_file(struct linux_binprm *bprm, const struct file *file); int security_bprm_check(struct linux_binprm *bprm); -void security_bprm_committing_creds(struct linux_binprm *bprm); +void security_bprm_committing_creds(const struct linux_binprm *bprm); void security_bprm_committed_creds(struct linux_binprm *bprm); int security_fs_context_submount(struct fs_context *fc, struct super_block *reference); int security_fs_context_dup(struct fs_context *fc, struct fs_context *src_fc); @@ -623,7 +623,7 @@ static inline int security_bprm_check(struct linux_binprm *bprm) return 0; } -static inline void security_bprm_committing_creds(struct linux_binprm *bprm) +static inline void security_bprm_committing_creds(const struct linux_binprm *bprm) { } diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c index 108eccc5ada5..b03f46e0f6c5 100644 --- a/security/apparmor/lsm.c +++ b/security/apparmor/lsm.c @@ -734,7 +734,7 @@ fail: * apparmor_bprm_committing_creds - do task cleanup on committing new creds * @bprm: binprm for the exec (NOT NULL) */ -static void apparmor_bprm_committing_creds(struct linux_binprm *bprm) +static void apparmor_bprm_committing_creds(const struct linux_binprm *bprm) { struct aa_label *label = aa_current_raw_label(); struct aa_label *new_label = cred_label(bprm->cred); diff --git a/security/security.c b/security/security.c index bde8813e89ff..77a1601ead36 100644 --- a/security/security.c +++ b/security/security.c @@ -1118,7 +1118,7 @@ int security_bprm_check(struct linux_binprm *bprm) * open file descriptors to which access will no longer be granted when the * attributes are changed. This is called immediately before commit_creds(). */ -void security_bprm_committing_creds(struct linux_binprm *bprm) +void security_bprm_committing_creds(const struct linux_binprm *bprm) { call_void_hook(bprm_committing_creds, bprm); } diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index e1c7640a5df1..f42a1b78bc43 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -2455,7 +2455,7 @@ static inline void flush_unauthorized_files(const struct cred *cred, /* * Prepare a process for imminent new credential changes due to exec */ -static void selinux_bprm_committing_creds(struct linux_binprm *bprm) +static void selinux_bprm_committing_creds(const struct linux_binprm *bprm) { struct task_security_struct *new_tsec; struct rlimit *rlim, *initrlim; From a721f7b8c3548e943e514a957f2a37f4763b9888 Mon Sep 17 00:00:00 2001 From: Khadija Kamran Date: Wed, 23 Aug 2023 13:16:40 +0500 Subject: [PATCH 11/28] lsm: constify 'bprm' parameter in security_bprm_committed_creds() Three LSMs register the implementations for the 'bprm_committed_creds()' hook: AppArmor, SELinux and tomoyo. Looking at the function implementations we may observe that the 'bprm' parameter is not changing. Mark the 'bprm' parameter of LSM hook security_bprm_committed_creds() as 'const' since it will not be changing in the LSM hook. Signed-off-by: Khadija Kamran [PM: minor merge fuzzing due to other constification patches] Signed-off-by: Paul Moore --- include/linux/lsm_hook_defs.h | 2 +- include/linux/security.h | 4 ++-- security/apparmor/lsm.c | 2 +- security/security.c | 2 +- security/selinux/hooks.c | 2 +- security/tomoyo/tomoyo.c | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/include/linux/lsm_hook_defs.h b/include/linux/lsm_hook_defs.h index f6acc3ed66a3..3b0f5cfca464 100644 --- a/include/linux/lsm_hook_defs.h +++ b/include/linux/lsm_hook_defs.h @@ -53,7 +53,7 @@ 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(void, LSM_RET_VOID, bprm_committing_creds, const struct linux_binprm *bprm) -LSM_HOOK(void, LSM_RET_VOID, bprm_committed_creds, 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, struct fs_context *src_sc) diff --git a/include/linux/security.h b/include/linux/security.h index 885053f81019..3148103123fb 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -293,7 +293,7 @@ int security_bprm_creds_for_exec(struct linux_binprm *bprm); int security_bprm_creds_from_file(struct linux_binprm *bprm, const struct file *file); int security_bprm_check(struct linux_binprm *bprm); void security_bprm_committing_creds(const struct linux_binprm *bprm); -void security_bprm_committed_creds(struct linux_binprm *bprm); +void security_bprm_committed_creds(const struct linux_binprm *bprm); int security_fs_context_submount(struct fs_context *fc, struct super_block *reference); int security_fs_context_dup(struct fs_context *fc, struct fs_context *src_fc); int security_fs_context_parse_param(struct fs_context *fc, struct fs_parameter *param); @@ -627,7 +627,7 @@ static inline void security_bprm_committing_creds(const struct linux_binprm *bpr { } -static inline void security_bprm_committed_creds(struct linux_binprm *bprm) +static inline void security_bprm_committed_creds(const struct linux_binprm *bprm) { } diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c index b03f46e0f6c5..3fa325d5efac 100644 --- a/security/apparmor/lsm.c +++ b/security/apparmor/lsm.c @@ -756,7 +756,7 @@ static void apparmor_bprm_committing_creds(const struct linux_binprm *bprm) * apparmor_bprm_committed_creds() - do cleanup after new creds committed * @bprm: binprm for the exec (NOT NULL) */ -static void apparmor_bprm_committed_creds(struct linux_binprm *bprm) +static void apparmor_bprm_committed_creds(const struct linux_binprm *bprm) { /* clear out temporary/transitional state from the context */ aa_clear_task_ctx_trans(task_ctx(current)); diff --git a/security/security.c b/security/security.c index 77a1601ead36..e4aec0f65f75 100644 --- a/security/security.c +++ b/security/security.c @@ -1134,7 +1134,7 @@ void security_bprm_committing_creds(const struct linux_binprm *bprm) * process such as clearing out non-inheritable signal state. This is called * immediately after commit_creds(). */ -void security_bprm_committed_creds(struct linux_binprm *bprm) +void security_bprm_committed_creds(const struct linux_binprm *bprm) { call_void_hook(bprm_committed_creds, bprm); } diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index f42a1b78bc43..e9ee008a9537 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -2501,7 +2501,7 @@ static void selinux_bprm_committing_creds(const struct linux_binprm *bprm) * Clean up the process immediately after the installation of new credentials * due to exec */ -static void selinux_bprm_committed_creds(struct linux_binprm *bprm) +static void selinux_bprm_committed_creds(const struct linux_binprm *bprm) { const struct task_security_struct *tsec = selinux_cred(current_cred()); u32 osid, sid; diff --git a/security/tomoyo/tomoyo.c b/security/tomoyo/tomoyo.c index 25006fddc964..255f1b470295 100644 --- a/security/tomoyo/tomoyo.c +++ b/security/tomoyo/tomoyo.c @@ -52,7 +52,7 @@ static int tomoyo_cred_prepare(struct cred *new, const struct cred *old, * * @bprm: Pointer to "struct linux_binprm". */ -static void tomoyo_bprm_committed_creds(struct linux_binprm *bprm) +static void tomoyo_bprm_committed_creds(const struct linux_binprm *bprm) { /* Clear old_domain_info saved by execve() request. */ struct tomoyo_task *s = tomoyo_task(current); From 20a2aa47097aae7016209c4dbe392b3b25e0d883 Mon Sep 17 00:00:00 2001 From: Khadija Kamran Date: Wed, 23 Aug 2023 14:01:28 +0500 Subject: [PATCH 12/28] lsm: constify 'sb' parameter in security_sb_kern_mount() The "sb_kern_mount" hook has implementation registered in SELinux. Looking at the function implementation we observe that the "sb" parameter is not changing. Mark the "sb" parameter of LSM hook security_sb_kern_mount() as "const" since it will not be changing in the LSM hook. Signed-off-by: Khadija Kamran [PM: minor merge fuzzing due to other constification patches] Signed-off-by: Paul Moore --- include/linux/lsm_hook_defs.h | 2 +- include/linux/security.h | 2 +- security/security.c | 2 +- security/selinux/hooks.c | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/include/linux/lsm_hook_defs.h b/include/linux/lsm_hook_defs.h index 3b0f5cfca464..99b8176c3738 100644 --- a/include/linux/lsm_hook_defs.h +++ b/include/linux/lsm_hook_defs.h @@ -66,7 +66,7 @@ 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, struct super_block *sb) +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, diff --git a/include/linux/security.h b/include/linux/security.h index 3148103123fb..1d1df326c881 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -304,7 +304,7 @@ void security_free_mnt_opts(void **mnt_opts); int security_sb_eat_lsm_opts(char *options, void **mnt_opts); int security_sb_mnt_opts_compat(struct super_block *sb, void *mnt_opts); int security_sb_remount(struct super_block *sb, void *mnt_opts); -int security_sb_kern_mount(struct super_block *sb); +int security_sb_kern_mount(const struct super_block *sb); int security_sb_show_options(struct seq_file *m, struct super_block *sb); int security_sb_statfs(struct dentry *dentry); int security_sb_mount(const char *dev_name, const struct path *path, diff --git a/security/security.c b/security/security.c index e4aec0f65f75..7b0052e96806 100644 --- a/security/security.c +++ b/security/security.c @@ -1319,7 +1319,7 @@ EXPORT_SYMBOL(security_sb_remount); * * Return: Returns 0 if permission is granted. */ -int security_sb_kern_mount(struct super_block *sb) +int security_sb_kern_mount(const struct super_block *sb) { return call_int_hook(sb_kern_mount, 0, sb); } diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index e9ee008a9537..195db92ac99c 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -2721,7 +2721,7 @@ out_bad_option: return -EINVAL; } -static int selinux_sb_kern_mount(struct super_block *sb) +static int selinux_sb_kern_mount(const struct super_block *sb) { const struct cred *cred = current_cred(); struct common_audit_data ad; From 41e845628511878d6e89e2a9249c095e72aab7eb Mon Sep 17 00:00:00 2001 From: Mateusz Guzik Date: Sat, 9 Sep 2023 21:19:32 +0200 Subject: [PATCH 13/28] cred: add get_cred_many and put_cred_many Some of the frequent consumers of get_cred and put_cred operate on 2 references on the same creds back-to-back. Switch them to doing the work in one go instead. Signed-off-by: Mateusz Guzik [PM: removed changelog from commit description] Signed-off-by: Paul Moore --- include/linux/cred.h | 59 +++++++++++++++++++++++++++++++++++++------- kernel/cred.c | 26 ++++++++++--------- 2 files changed, 65 insertions(+), 20 deletions(-) diff --git a/include/linux/cred.h b/include/linux/cred.h index f923528d5cc4..56bc432fe49b 100644 --- a/include/linux/cred.h +++ b/include/linux/cred.h @@ -218,6 +218,20 @@ static inline bool cap_ambient_invariant_ok(const struct cred *cred) cred->cap_inheritable)); } +/** + * get_new_cred_many - Get references on a new set of credentials + * @cred: The new credentials to reference + * @nr: Number of references to acquire + * + * Get references on the specified set of new credentials. The caller must + * release all acquired references. + */ +static inline struct cred *get_new_cred_many(struct cred *cred, int nr) +{ + atomic_add(nr, &cred->usage); + return cred; +} + /** * get_new_cred - Get a reference on a new set of credentials * @cred: The new credentials to reference @@ -227,16 +241,16 @@ static inline bool cap_ambient_invariant_ok(const struct cred *cred) */ static inline struct cred *get_new_cred(struct cred *cred) { - atomic_inc(&cred->usage); - return cred; + return get_new_cred_many(cred, 1); } /** - * get_cred - Get a reference on a set of credentials + * get_cred_many - Get references on a set of credentials * @cred: The credentials to reference + * @nr: Number of references to acquire * - * Get a reference on the specified set of credentials. The caller must - * release the reference. If %NULL is passed, it is returned with no action. + * Get references on the specified set of credentials. The caller must release + * all acquired reference. If %NULL is passed, it is returned with no action. * * This is used to deal with a committed set of credentials. Although the * pointer is const, this will temporarily discard the const and increment the @@ -244,14 +258,28 @@ static inline struct cred *get_new_cred(struct cred *cred) * accidental alteration of a set of credentials that should be considered * immutable. */ -static inline const struct cred *get_cred(const struct cred *cred) +static inline const struct cred *get_cred_many(const struct cred *cred, int nr) { struct cred *nonconst_cred = (struct cred *) cred; if (!cred) return cred; validate_creds(cred); nonconst_cred->non_rcu = 0; - return get_new_cred(nonconst_cred); + return get_new_cred_many(nonconst_cred, nr); +} + +/* + * get_cred - Get a reference on a set of credentials + * @cred: The credentials to reference + * + * Get a reference on the specified set of credentials. The caller must + * release the reference. If %NULL is passed, it is returned with no action. + * + * This is used to deal with a committed set of credentials. + */ +static inline const struct cred *get_cred(const struct cred *cred) +{ + return get_cred_many(cred, 1); } static inline const struct cred *get_cred_rcu(const struct cred *cred) @@ -269,6 +297,7 @@ static inline const struct cred *get_cred_rcu(const struct cred *cred) /** * put_cred - Release a reference to a set of credentials * @cred: The credentials to release + * @nr: Number of references to release * * Release a reference to a set of credentials, deleting them when the last ref * is released. If %NULL is passed, nothing is done. @@ -277,17 +306,29 @@ static inline const struct cred *get_cred_rcu(const struct cred *cred) * on task_struct are attached by const pointers to prevent accidental * alteration of otherwise immutable credential sets. */ -static inline void put_cred(const struct cred *_cred) +static inline void put_cred_many(const struct cred *_cred, int nr) { struct cred *cred = (struct cred *) _cred; if (cred) { validate_creds(cred); - if (atomic_dec_and_test(&(cred)->usage)) + if (atomic_sub_and_test(nr, &cred->usage)) __put_cred(cred); } } +/* + * put_cred - Release a reference to a set of credentials + * @cred: The credentials to release + * + * Release a reference to a set of credentials, deleting them when the last ref + * is released. If %NULL is passed, nothing is done. + */ +static inline void put_cred(const struct cred *cred) +{ + put_cred_many(cred, 1); +} + /** * current_cred - Access the current task's subjective credentials * diff --git a/kernel/cred.c b/kernel/cred.c index 98cb4eca23fb..9398e534b997 100644 --- a/kernel/cred.c +++ b/kernel/cred.c @@ -162,23 +162,29 @@ EXPORT_SYMBOL(__put_cred); */ void exit_creds(struct task_struct *tsk) { - struct cred *cred; + struct cred *real_cred, *cred; kdebug("exit_creds(%u,%p,%p,{%d,%d})", tsk->pid, tsk->real_cred, tsk->cred, atomic_read(&tsk->cred->usage), read_cred_subscribers(tsk->cred)); - cred = (struct cred *) tsk->real_cred; + real_cred = (struct cred *) tsk->real_cred; tsk->real_cred = NULL; - validate_creds(cred); - alter_cred_subscribers(cred, -1); - put_cred(cred); cred = (struct cred *) tsk->cred; tsk->cred = NULL; + validate_creds(cred); - alter_cred_subscribers(cred, -1); - put_cred(cred); + if (real_cred == cred) { + alter_cred_subscribers(cred, -2); + put_cred_many(cred, 2); + } else { + validate_creds(real_cred); + alter_cred_subscribers(real_cred, -1); + put_cred(real_cred); + alter_cred_subscribers(cred, -1); + put_cred(cred); + } #ifdef CONFIG_KEYS_REQUEST_CACHE key_put(tsk->cached_requested_key); @@ -355,8 +361,7 @@ int copy_creds(struct task_struct *p, unsigned long clone_flags) #endif clone_flags & CLONE_THREAD ) { - p->real_cred = get_cred(p->cred); - get_cred(p->cred); + p->real_cred = get_cred_many(p->cred, 2); alter_cred_subscribers(p->cred, 2); kdebug("share_creds(%p{%d,%d})", p->cred, atomic_read(&p->cred->usage), @@ -520,8 +525,7 @@ int commit_creds(struct cred *new) proc_id_connector(task, PROC_EVENT_GID); /* release the old obj and subj refs both */ - put_cred(old); - put_cred(old); + put_cred_many(old, 2); return 0; } EXPORT_SYMBOL(commit_creds); From 19c1c9916dbf9b05157a0c4970f61f952c0cb86a Mon Sep 17 00:00:00 2001 From: Jacob Satterfield Date: Fri, 29 Sep 2023 19:56:12 +0000 Subject: [PATCH 14/28] selinux: simplify avtab_insert_node() prototype __hashtab_insert() in hashtab.h has a cleaner interface that allows the caller to specify the chain node location that the new node is being inserted into so that it can update the node that currently occupies it. Signed-off-by: Jacob Satterfield Reviewed-by: Stephen Smalley Signed-off-by: Paul Moore --- security/selinux/ss/avtab.c | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/security/selinux/ss/avtab.c b/security/selinux/ss/avtab.c index 095b8cd24806..8751a602ead2 100644 --- a/security/selinux/ss/avtab.c +++ b/security/selinux/ss/avtab.c @@ -67,8 +67,7 @@ static inline u32 avtab_hash(const struct avtab_key *keyp, u32 mask) } static struct avtab_node* -avtab_insert_node(struct avtab *h, u32 hvalue, - struct avtab_node *prev, +avtab_insert_node(struct avtab *h, struct avtab_node **dst, const struct avtab_key *key, const struct avtab_datum *datum) { struct avtab_node *newnode; @@ -90,15 +89,8 @@ avtab_insert_node(struct avtab *h, u32 hvalue, newnode->datum.u.data = datum->u.data; } - if (prev) { - newnode->next = prev->next; - prev->next = newnode; - } else { - struct avtab_node **n = &h->htable[hvalue]; - - newnode->next = *n; - *n = newnode; - } + newnode->next = *dst; + *dst = newnode; h->nel++; return newnode; @@ -138,7 +130,8 @@ static int avtab_insert(struct avtab *h, const struct avtab_key *key, break; } - newnode = avtab_insert_node(h, hvalue, prev, key, datum); + newnode = avtab_insert_node(h, prev ? &prev->next : &h->htable[hvalue], + key, datum); if (!newnode) return -ENOMEM; @@ -178,7 +171,8 @@ struct avtab_node *avtab_insert_nonunique(struct avtab *h, key->target_class < cur->key.target_class) break; } - return avtab_insert_node(h, hvalue, prev, key, datum); + return avtab_insert_node(h, prev ? &prev->next : &h->htable[hvalue], + key, datum); } /* This search function returns a node pointer, and can be used in From e508560672890b2873c89258b88fade1356392ce Mon Sep 17 00:00:00 2001 From: Paul Moore Date: Wed, 4 Oct 2023 16:08:09 -0400 Subject: [PATCH 15/28] lsm: fix a spelling mistake Fix a spelling mistake in the security_inode_notifysecctx() kdoc header block. Signed-off-by: Paul Moore --- security/security.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/security/security.c b/security/security.c index 7b0052e96806..dcb3e7014f9b 100644 --- a/security/security.c +++ b/security/security.c @@ -3957,7 +3957,7 @@ void security_inode_invalidate_secctx(struct inode *inode) EXPORT_SYMBOL(security_inode_invalidate_secctx); /** - * security_inode_notifysecctx() - Nofify the LSM of an inode's security label + * security_inode_notifysecctx() - Notify the LSM of an inode's security label * @inode: inode * @ctx: secctx * @ctxlen: length of secctx From 828176d037e29f813792a8b3ac1591834240e96f Mon Sep 17 00:00:00 2001 From: Miguel Ojeda Date: Wed, 23 Aug 2023 18:02:42 +0200 Subject: [PATCH 16/28] rust: arc: add explicit `drop()` around `Box::from_raw()` MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `Box::from_raw()` is `#[must_use]`, which means the result cannot go unused. In Rust 1.71.0, this was not detected because the block expression swallows the diagnostic [1]: unsafe { Box::from_raw(self.ptr.as_ptr()) }; It would have been detected, however, if the line had been instead: unsafe { Box::from_raw(self.ptr.as_ptr()); } i.e. the semicolon being inside the `unsafe` block, rather than outside. In Rust 1.72.0, the compiler started warning about this [2], so without this patch we will get: error: unused return value of `alloc::boxed::Box::::from_raw` that must be used --> rust/kernel/sync/arc.rs:302:22 | 302 | unsafe { Box::from_raw(self.ptr.as_ptr()) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: call `drop(Box::from_raw(ptr))` if you intend to drop the `Box` = note: `-D unused-must-use` implied by `-D warnings` help: use `let _ = ...` to ignore the resulting value | 302 | unsafe { let _ = Box::from_raw(self.ptr.as_ptr()); }; | +++++++ + Thus add an add an explicit `drop()` as the `#[must_use]`'s annotation suggests (instead of the more general help line). Link: https://github.com/rust-lang/rust/issues/104253 [1] Link: https://github.com/rust-lang/rust/pull/112529 [2] Reviewed-by: Martin Rodriguez Reboredo Reviewed-by: Gary Guo Reviewed-by: Alice Ryhl Reviewed-by: Andreas Hindborg Reviewed-by: Björn Roy Baron Link: https://lore.kernel.org/r/20230823160244.188033-2-ojeda@kernel.org Signed-off-by: Miguel Ojeda --- rust/kernel/sync/arc.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust/kernel/sync/arc.rs b/rust/kernel/sync/arc.rs index 3d496391a9bd..7f04e4f00a2c 100644 --- a/rust/kernel/sync/arc.rs +++ b/rust/kernel/sync/arc.rs @@ -302,7 +302,7 @@ impl Drop for Arc { // The count reached zero, we must free the memory. // // SAFETY: The pointer was initialised from the result of `Box::leak`. - unsafe { Box::from_raw(self.ptr.as_ptr()) }; + unsafe { drop(Box::from_raw(self.ptr.as_ptr())) }; } } } From ae6df65dabc3f8bd89663d96203963323e266d90 Mon Sep 17 00:00:00 2001 From: Miguel Ojeda Date: Wed, 23 Aug 2023 18:02:43 +0200 Subject: [PATCH 17/28] rust: upgrade to Rust 1.72.1 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is the third upgrade to the Rust toolchain, from 1.71.1 to 1.72.1 (i.e. the latest) [1]. See the upgrade policy [2] and the comments on the first upgrade in commit 3ed03f4da06e ("rust: upgrade to Rust 1.68.2"). # Unstable features No unstable features (that we use) were stabilized. Therefore, the only unstable feature allowed to be used outside the `kernel` crate is still `new_uninit`, though other code to be upstreamed may increase the list. Please see [3] for details. # Other improvements Previously, the compiler could incorrectly generate a `.eh_frame` section under `-Cpanic=abort`. We were hitting this bug when debug assertions were enabled (`CONFIG_RUST_DEBUG_ASSERTIONS=y`) [4]: LD .tmp_vmlinux.kallsyms1 ld.lld: error: :(.eh_frame) is being placed in '.eh_frame' Gary fixed the issue in Rust 1.72.0 [5]. # Required changes For the upgrade, the following changes are required: - A call to `Box::from_raw` in `rust/kernel/sync/arc.rs` now requires an explicit `drop()` call. See previous patch for details. # `alloc` upgrade and reviewing The vast majority of changes are due to our `alloc` fork being upgraded at once. There are two kinds of changes to be aware of: the ones coming from upstream, which we should follow as closely as possible, and the updates needed in our added fallible APIs to keep them matching the newer infallible APIs coming from upstream. Instead of taking a look at the diff of this patch, an alternative approach is reviewing a diff of the changes between upstream `alloc` and the kernel's. This allows to easily inspect the kernel additions only, especially to check if the fallible methods we already have still match the infallible ones in the new version coming from upstream. Another approach is reviewing the changes introduced in the additions in the kernel fork between the two versions. This is useful to spot potentially unintended changes to our additions. To apply these approaches, one may follow steps similar to the following to generate a pair of patches that show the differences between upstream Rust and the kernel (for the subset of `alloc` we use) before and after applying this patch: # Get the difference with respect to the old version. git -C rust checkout $(linux/scripts/min-tool-version.sh rustc) git -C linux ls-tree -r --name-only HEAD -- rust/alloc | cut -d/ -f3- | grep -Fv README.md | xargs -IPATH cp rust/library/alloc/src/PATH linux/rust/alloc/PATH git -C linux diff --patch-with-stat --summary -R > old.patch git -C linux restore rust/alloc # Apply this patch. git -C linux am rust-upgrade.patch # Get the difference with respect to the new version. git -C rust checkout $(linux/scripts/min-tool-version.sh rustc) git -C linux ls-tree -r --name-only HEAD -- rust/alloc | cut -d/ -f3- | grep -Fv README.md | xargs -IPATH cp rust/library/alloc/src/PATH linux/rust/alloc/PATH git -C linux diff --patch-with-stat --summary -R > new.patch git -C linux restore rust/alloc Now one may check the `new.patch` to take a look at the additions (first approach) or at the difference between those two patches (second approach). For the latter, a side-by-side tool is recommended. Link: https://github.com/rust-lang/rust/blob/stable/RELEASES.md#version-1721-2023-09-19 [1] Link: https://rust-for-linux.com/rust-version-policy [2] Link: https://github.com/Rust-for-Linux/linux/issues/2 [3] Closes: https://github.com/Rust-for-Linux/linux/issues/1012 [4] Link: https://github.com/rust-lang/rust/pull/112403 [5] Reviewed-by: Martin Rodriguez Reboredo Reviewed-by: Gary Guo Reviewed-by: Alice Ryhl Reviewed-by: Björn Roy Baron Link: https://lore.kernel.org/r/20230823160244.188033-3-ojeda@kernel.org [ Used 1.72.1 instead of .0 (no changes in `alloc`) and reworded to mention that we hit the `.eh_frame` bug under debug assertions. ] Signed-off-by: Miguel Ojeda --- Documentation/process/changes.rst | 2 +- rust/alloc/alloc.rs | 9 +- rust/alloc/boxed.rs | 10 +- rust/alloc/lib.rs | 10 +- rust/alloc/vec/drain_filter.rs | 199 ------------------------------ rust/alloc/vec/extract_if.rs | 115 +++++++++++++++++ rust/alloc/vec/mod.rs | 106 ++++++++-------- scripts/min-tool-version.sh | 2 +- 8 files changed, 187 insertions(+), 266 deletions(-) delete mode 100644 rust/alloc/vec/drain_filter.rs create mode 100644 rust/alloc/vec/extract_if.rs diff --git a/Documentation/process/changes.rst b/Documentation/process/changes.rst index b48da698d6f2..731cc104c56f 100644 --- a/Documentation/process/changes.rst +++ b/Documentation/process/changes.rst @@ -31,7 +31,7 @@ you probably needn't concern yourself with pcmciautils. ====================== =============== ======================================== GNU C 5.1 gcc --version Clang/LLVM (optional) 11.0.0 clang --version -Rust (optional) 1.71.1 rustc --version +Rust (optional) 1.72.1 rustc --version bindgen (optional) 0.65.1 bindgen --version GNU make 3.82 make --version bash 4.2 bash --version diff --git a/rust/alloc/alloc.rs b/rust/alloc/alloc.rs index 0b6bf5b6da43..51821feb20b1 100644 --- a/rust/alloc/alloc.rs +++ b/rust/alloc/alloc.rs @@ -6,8 +6,10 @@ #[cfg(not(test))] use core::intrinsics; +#[cfg(all(bootstrap, not(test)))] use core::intrinsics::{min_align_of_val, size_of_val}; +#[cfg(all(bootstrap, not(test)))] use core::ptr::Unique; #[cfg(not(test))] use core::ptr::{self, NonNull}; @@ -40,7 +42,6 @@ extern "Rust" { #[rustc_nounwind] fn __rust_alloc_zeroed(size: usize, align: usize) -> *mut u8; - #[cfg(not(bootstrap))] static __rust_no_alloc_shim_is_unstable: u8; } @@ -98,7 +99,6 @@ pub unsafe fn alloc(layout: Layout) -> *mut u8 { unsafe { // Make sure we don't accidentally allow omitting the allocator shim in // stable code until it is actually stabilized. - #[cfg(not(bootstrap))] core::ptr::read_volatile(&__rust_no_alloc_shim_is_unstable); __rust_alloc(layout.size(), layout.align()) @@ -339,14 +339,15 @@ unsafe fn exchange_malloc(size: usize, align: usize) -> *mut u8 { } } -#[cfg_attr(not(test), lang = "box_free")] +#[cfg(all(bootstrap, not(test)))] +#[lang = "box_free"] #[inline] // This signature has to be the same as `Box`, otherwise an ICE will happen. // When an additional parameter to `Box` is added (like `A: Allocator`), this has to be added here as // well. // For example if `Box` is changed to `struct Box(Unique, A)`, // this function has to be changed to `fn box_free(Unique, A)` as well. -pub(crate) unsafe fn box_free(ptr: Unique, alloc: A) { +unsafe fn box_free(ptr: Unique, alloc: A) { unsafe { let size = size_of_val(ptr.as_ref()); let align = min_align_of_val(ptr.as_ref()); diff --git a/rust/alloc/boxed.rs b/rust/alloc/boxed.rs index c8173cea8317..bdab710f7737 100644 --- a/rust/alloc/boxed.rs +++ b/rust/alloc/boxed.rs @@ -1215,8 +1215,16 @@ impl Box { #[stable(feature = "rust1", since = "1.0.0")] unsafe impl<#[may_dangle] T: ?Sized, A: Allocator> Drop for Box { + #[inline] fn drop(&mut self) { - // FIXME: Do nothing, drop is currently performed by compiler. + // the T in the Box is dropped by the compiler before the destructor is run + + let ptr = self.0; + + unsafe { + let layout = Layout::for_value_raw(ptr.as_ptr()); + self.1.deallocate(From::from(ptr.cast()), layout) + } } } diff --git a/rust/alloc/lib.rs b/rust/alloc/lib.rs index 85e91356ecb3..115fcb053e73 100644 --- a/rust/alloc/lib.rs +++ b/rust/alloc/lib.rs @@ -58,6 +58,11 @@ //! [`Rc`]: rc //! [`RefCell`]: core::cell +// To run alloc tests without x.py without ending up with two copies of alloc, Miri needs to be +// able to "empty" this crate. See . +// rustc itself never sets the feature, so this line has no affect there. +#![cfg(any(not(feature = "miri-test-libstd"), test, doctest))] +// #![allow(unused_attributes)] #![stable(feature = "alloc", since = "1.36.0")] #![doc( @@ -77,11 +82,6 @@ ))] #![no_std] #![needs_allocator] -// To run alloc tests without x.py without ending up with two copies of alloc, Miri needs to be -// able to "empty" this crate. See . -// rustc itself never sets the feature, so this line has no affect there. -#![cfg(any(not(feature = "miri-test-libstd"), test, doctest))] -// // Lints: #![deny(unsafe_op_in_unsafe_fn)] #![deny(fuzzy_provenance_casts)] diff --git a/rust/alloc/vec/drain_filter.rs b/rust/alloc/vec/drain_filter.rs deleted file mode 100644 index 09efff090e42..000000000000 --- a/rust/alloc/vec/drain_filter.rs +++ /dev/null @@ -1,199 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 OR MIT - -use crate::alloc::{Allocator, Global}; -use core::mem::{ManuallyDrop, SizedTypeProperties}; -use core::ptr; -use core::slice; - -use super::Vec; - -/// An iterator which uses a closure to determine if an element should be removed. -/// -/// This struct is created by [`Vec::drain_filter`]. -/// See its documentation for more. -/// -/// # Example -/// -/// ``` -/// #![feature(drain_filter)] -/// -/// let mut v = vec![0, 1, 2]; -/// let iter: std::vec::DrainFilter<'_, _, _> = v.drain_filter(|x| *x % 2 == 0); -/// ``` -#[unstable(feature = "drain_filter", reason = "recently added", issue = "43244")] -#[derive(Debug)] -pub struct DrainFilter< - 'a, - T, - F, - #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, -> where - F: FnMut(&mut T) -> bool, -{ - pub(super) vec: &'a mut Vec, - /// The index of the item that will be inspected by the next call to `next`. - pub(super) idx: usize, - /// The number of items that have been drained (removed) thus far. - pub(super) del: usize, - /// The original length of `vec` prior to draining. - pub(super) old_len: usize, - /// The filter test predicate. - pub(super) pred: F, - /// A flag that indicates a panic has occurred in the filter test predicate. - /// This is used as a hint in the drop implementation to prevent consumption - /// of the remainder of the `DrainFilter`. Any unprocessed items will be - /// backshifted in the `vec`, but no further items will be dropped or - /// tested by the filter predicate. - pub(super) panic_flag: bool, -} - -impl DrainFilter<'_, T, F, A> -where - F: FnMut(&mut T) -> bool, -{ - /// Returns a reference to the underlying allocator. - #[unstable(feature = "allocator_api", issue = "32838")] - #[inline] - pub fn allocator(&self) -> &A { - self.vec.allocator() - } - - /// Keep unyielded elements in the source `Vec`. - /// - /// # Examples - /// - /// ``` - /// #![feature(drain_filter)] - /// #![feature(drain_keep_rest)] - /// - /// let mut vec = vec!['a', 'b', 'c']; - /// let mut drain = vec.drain_filter(|_| true); - /// - /// assert_eq!(drain.next().unwrap(), 'a'); - /// - /// // This call keeps 'b' and 'c' in the vec. - /// drain.keep_rest(); - /// - /// // If we wouldn't call `keep_rest()`, - /// // `vec` would be empty. - /// assert_eq!(vec, ['b', 'c']); - /// ``` - #[unstable(feature = "drain_keep_rest", issue = "101122")] - pub fn keep_rest(self) { - // At this moment layout looks like this: - // - // _____________________/-- old_len - // / \ - // [kept] [yielded] [tail] - // \_______/ ^-- idx - // \-- del - // - // Normally `Drop` impl would drop [tail] (via .for_each(drop), ie still calling `pred`) - // - // 1. Move [tail] after [kept] - // 2. Update length of the original vec to `old_len - del` - // a. In case of ZST, this is the only thing we want to do - // 3. Do *not* drop self, as everything is put in a consistent state already, there is nothing to do - let mut this = ManuallyDrop::new(self); - - unsafe { - // ZSTs have no identity, so we don't need to move them around. - if !T::IS_ZST && this.idx < this.old_len && this.del > 0 { - let ptr = this.vec.as_mut_ptr(); - let src = ptr.add(this.idx); - let dst = src.sub(this.del); - let tail_len = this.old_len - this.idx; - src.copy_to(dst, tail_len); - } - - let new_len = this.old_len - this.del; - this.vec.set_len(new_len); - } - } -} - -#[unstable(feature = "drain_filter", reason = "recently added", issue = "43244")] -impl Iterator for DrainFilter<'_, T, F, A> -where - F: FnMut(&mut T) -> bool, -{ - type Item = T; - - fn next(&mut self) -> Option { - unsafe { - while self.idx < self.old_len { - let i = self.idx; - let v = slice::from_raw_parts_mut(self.vec.as_mut_ptr(), self.old_len); - self.panic_flag = true; - let drained = (self.pred)(&mut v[i]); - self.panic_flag = false; - // Update the index *after* the predicate is called. If the index - // is updated prior and the predicate panics, the element at this - // index would be leaked. - self.idx += 1; - if drained { - self.del += 1; - return Some(ptr::read(&v[i])); - } else if self.del > 0 { - let del = self.del; - let src: *const T = &v[i]; - let dst: *mut T = &mut v[i - del]; - ptr::copy_nonoverlapping(src, dst, 1); - } - } - None - } - } - - fn size_hint(&self) -> (usize, Option) { - (0, Some(self.old_len - self.idx)) - } -} - -#[unstable(feature = "drain_filter", reason = "recently added", issue = "43244")] -impl Drop for DrainFilter<'_, T, F, A> -where - F: FnMut(&mut T) -> bool, -{ - fn drop(&mut self) { - struct BackshiftOnDrop<'a, 'b, T, F, A: Allocator> - where - F: FnMut(&mut T) -> bool, - { - drain: &'b mut DrainFilter<'a, T, F, A>, - } - - impl<'a, 'b, T, F, A: Allocator> Drop for BackshiftOnDrop<'a, 'b, T, F, A> - where - F: FnMut(&mut T) -> bool, - { - fn drop(&mut self) { - unsafe { - if self.drain.idx < self.drain.old_len && self.drain.del > 0 { - // This is a pretty messed up state, and there isn't really an - // obviously right thing to do. We don't want to keep trying - // to execute `pred`, so we just backshift all the unprocessed - // elements and tell the vec that they still exist. The backshift - // is required to prevent a double-drop of the last successfully - // drained item prior to a panic in the predicate. - let ptr = self.drain.vec.as_mut_ptr(); - let src = ptr.add(self.drain.idx); - let dst = src.sub(self.drain.del); - let tail_len = self.drain.old_len - self.drain.idx; - src.copy_to(dst, tail_len); - } - self.drain.vec.set_len(self.drain.old_len - self.drain.del); - } - } - } - - let backshift = BackshiftOnDrop { drain: self }; - - // Attempt to consume any remaining elements if the filter predicate - // has not yet panicked. We'll backshift any remaining elements - // whether we've already panicked or if the consumption here panics. - if !backshift.drain.panic_flag { - backshift.drain.for_each(drop); - } - } -} diff --git a/rust/alloc/vec/extract_if.rs b/rust/alloc/vec/extract_if.rs new file mode 100644 index 000000000000..f314a51d4d3d --- /dev/null +++ b/rust/alloc/vec/extract_if.rs @@ -0,0 +1,115 @@ +// SPDX-License-Identifier: Apache-2.0 OR MIT + +use crate::alloc::{Allocator, Global}; +use core::ptr; +use core::slice; + +use super::Vec; + +/// An iterator which uses a closure to determine if an element should be removed. +/// +/// This struct is created by [`Vec::extract_if`]. +/// See its documentation for more. +/// +/// # Example +/// +/// ``` +/// #![feature(extract_if)] +/// +/// let mut v = vec![0, 1, 2]; +/// let iter: std::vec::ExtractIf<'_, _, _> = v.extract_if(|x| *x % 2 == 0); +/// ``` +#[unstable(feature = "extract_if", reason = "recently added", issue = "43244")] +#[derive(Debug)] +#[must_use = "iterators are lazy and do nothing unless consumed"] +pub struct ExtractIf< + 'a, + T, + F, + #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, +> where + F: FnMut(&mut T) -> bool, +{ + pub(super) vec: &'a mut Vec, + /// The index of the item that will be inspected by the next call to `next`. + pub(super) idx: usize, + /// The number of items that have been drained (removed) thus far. + pub(super) del: usize, + /// The original length of `vec` prior to draining. + pub(super) old_len: usize, + /// The filter test predicate. + pub(super) pred: F, +} + +impl ExtractIf<'_, T, F, A> +where + F: FnMut(&mut T) -> bool, +{ + /// Returns a reference to the underlying allocator. + #[unstable(feature = "allocator_api", issue = "32838")] + #[inline] + pub fn allocator(&self) -> &A { + self.vec.allocator() + } +} + +#[unstable(feature = "extract_if", reason = "recently added", issue = "43244")] +impl Iterator for ExtractIf<'_, T, F, A> +where + F: FnMut(&mut T) -> bool, +{ + type Item = T; + + fn next(&mut self) -> Option { + unsafe { + while self.idx < self.old_len { + let i = self.idx; + let v = slice::from_raw_parts_mut(self.vec.as_mut_ptr(), self.old_len); + let drained = (self.pred)(&mut v[i]); + // Update the index *after* the predicate is called. If the index + // is updated prior and the predicate panics, the element at this + // index would be leaked. + self.idx += 1; + if drained { + self.del += 1; + return Some(ptr::read(&v[i])); + } else if self.del > 0 { + let del = self.del; + let src: *const T = &v[i]; + let dst: *mut T = &mut v[i - del]; + ptr::copy_nonoverlapping(src, dst, 1); + } + } + None + } + } + + fn size_hint(&self) -> (usize, Option) { + (0, Some(self.old_len - self.idx)) + } +} + +#[unstable(feature = "extract_if", reason = "recently added", issue = "43244")] +impl Drop for ExtractIf<'_, T, F, A> +where + F: FnMut(&mut T) -> bool, +{ + fn drop(&mut self) { + unsafe { + if self.idx < self.old_len && self.del > 0 { + // This is a pretty messed up state, and there isn't really an + // obviously right thing to do. We don't want to keep trying + // to execute `pred`, so we just backshift all the unprocessed + // elements and tell the vec that they still exist. The backshift + // is required to prevent a double-drop of the last successfully + // drained item prior to a panic in the predicate. + let ptr = self.vec.as_mut_ptr(); + let src = ptr.add(self.idx); + let dst = src.sub(self.del); + let tail_len = self.old_len - self.idx; + src.copy_to(dst, tail_len); + } + self.vec.set_len(self.old_len - self.del); + } + } +} diff --git a/rust/alloc/vec/mod.rs b/rust/alloc/vec/mod.rs index 05c70de0227e..a4e9a5002a6d 100644 --- a/rust/alloc/vec/mod.rs +++ b/rust/alloc/vec/mod.rs @@ -74,10 +74,10 @@ use crate::boxed::Box; use crate::collections::{TryReserveError, TryReserveErrorKind}; use crate::raw_vec::RawVec; -#[unstable(feature = "drain_filter", reason = "recently added", issue = "43244")] -pub use self::drain_filter::DrainFilter; +#[unstable(feature = "extract_if", reason = "recently added", issue = "43244")] +pub use self::extract_if::ExtractIf; -mod drain_filter; +mod extract_if; #[cfg(not(no_global_oom_handling))] #[stable(feature = "vec_splice", since = "1.21.0")] @@ -618,22 +618,20 @@ impl Vec { /// Using memory that was allocated elsewhere: /// /// ```rust - /// #![feature(allocator_api)] - /// - /// use std::alloc::{AllocError, Allocator, Global, Layout}; + /// use std::alloc::{alloc, Layout}; /// /// fn main() { /// let layout = Layout::array::(16).expect("overflow cannot happen"); /// /// let vec = unsafe { - /// let mem = match Global.allocate(layout) { - /// Ok(mem) => mem.cast::().as_ptr(), - /// Err(AllocError) => return, - /// }; + /// let mem = alloc(layout).cast::(); + /// if mem.is_null() { + /// return; + /// } /// /// mem.write(1_000_000); /// - /// Vec::from_raw_parts_in(mem, 1, 16, Global) + /// Vec::from_raw_parts(mem, 1, 16) /// }; /// /// assert_eq!(vec, &[1_000_000]); @@ -876,19 +874,22 @@ impl Vec { /// Using memory that was allocated elsewhere: /// /// ```rust - /// use std::alloc::{alloc, Layout}; + /// #![feature(allocator_api)] + /// + /// use std::alloc::{AllocError, Allocator, Global, Layout}; /// /// fn main() { /// let layout = Layout::array::(16).expect("overflow cannot happen"); + /// /// let vec = unsafe { - /// let mem = alloc(layout).cast::(); - /// if mem.is_null() { - /// return; - /// } + /// let mem = match Global.allocate(layout) { + /// Ok(mem) => mem.cast::().as_ptr(), + /// Err(AllocError) => return, + /// }; /// /// mem.write(1_000_000); /// - /// Vec::from_raw_parts(mem, 1, 16) + /// Vec::from_raw_parts_in(mem, 1, 16, Global) /// }; /// /// assert_eq!(vec, &[1_000_000]); @@ -2507,7 +2508,7 @@ impl Vec { let len = self.len(); if new_len > len { - self.extend_with(new_len - len, ExtendElement(value)) + self.extend_with(new_len - len, value) } else { self.truncate(new_len); } @@ -2545,7 +2546,7 @@ impl Vec { let len = self.len(); if new_len > len { - self.try_extend_with(new_len - len, ExtendElement(value)) + self.try_extend_with(new_len - len, value) } else { self.truncate(new_len); Ok(()) @@ -2684,26 +2685,10 @@ impl Vec<[T; N], A> { } } -// This code generalizes `extend_with_{element,default}`. -trait ExtendWith { - fn next(&mut self) -> T; - fn last(self) -> T; -} - -struct ExtendElement(T); -impl ExtendWith for ExtendElement { - fn next(&mut self) -> T { - self.0.clone() - } - fn last(self) -> T { - self.0 - } -} - -impl Vec { +impl Vec { #[cfg(not(no_global_oom_handling))] - /// Extend the vector by `n` values, using the given generator. - fn extend_with>(&mut self, n: usize, mut value: E) { + /// Extend the vector by `n` clones of value. + fn extend_with(&mut self, n: usize, value: T) { self.reserve(n); unsafe { @@ -2715,15 +2700,15 @@ impl Vec { // Write all elements except the last one for _ in 1..n { - ptr::write(ptr, value.next()); + ptr::write(ptr, value.clone()); ptr = ptr.add(1); - // Increment the length in every step in case next() panics + // Increment the length in every step in case clone() panics local_len.increment_len(1); } if n > 0 { // We can write the last element directly without cloning needlessly - ptr::write(ptr, value.last()); + ptr::write(ptr, value); local_len.increment_len(1); } @@ -2731,8 +2716,8 @@ impl Vec { } } - /// Try to extend the vector by `n` values, using the given generator. - fn try_extend_with>(&mut self, n: usize, mut value: E) -> Result<(), TryReserveError> { + /// Try to extend the vector by `n` clones of value. + fn try_extend_with(&mut self, n: usize, value: T) -> Result<(), TryReserveError> { self.try_reserve(n)?; unsafe { @@ -2744,15 +2729,15 @@ impl Vec { // Write all elements except the last one for _ in 1..n { - ptr::write(ptr, value.next()); + ptr::write(ptr, value.clone()); ptr = ptr.add(1); - // Increment the length in every step in case next() panics + // Increment the length in every step in case clone() panics local_len.increment_len(1); } if n > 0 { // We can write the last element directly without cloning needlessly - ptr::write(ptr, value.last()); + ptr::write(ptr, value); local_len.increment_len(1); } @@ -3210,6 +3195,12 @@ impl Vec { /// If the closure returns false, the element will remain in the vector and will not be yielded /// by the iterator. /// + /// If the returned `ExtractIf` is not exhausted, e.g. because it is dropped without iterating + /// or the iteration short-circuits, then the remaining elements will be retained. + /// Use [`retain`] with a negated predicate if you do not need the returned iterator. + /// + /// [`retain`]: Vec::retain + /// /// Using this method is equivalent to the following code: /// /// ``` @@ -3228,10 +3219,10 @@ impl Vec { /// # assert_eq!(vec, vec![1, 4, 5]); /// ``` /// - /// But `drain_filter` is easier to use. `drain_filter` is also more efficient, + /// But `extract_if` is easier to use. `extract_if` is also more efficient, /// because it can backshift the elements of the array in bulk. /// - /// Note that `drain_filter` also lets you mutate every element in the filter closure, + /// Note that `extract_if` also lets you mutate every element in the filter closure, /// regardless of whether you choose to keep or remove it. /// /// # Examples @@ -3239,17 +3230,17 @@ impl Vec { /// Splitting an array into evens and odds, reusing the original allocation: /// /// ``` - /// #![feature(drain_filter)] + /// #![feature(extract_if)] /// let mut numbers = vec![1, 2, 3, 4, 5, 6, 8, 9, 11, 13, 14, 15]; /// - /// let evens = numbers.drain_filter(|x| *x % 2 == 0).collect::>(); + /// let evens = numbers.extract_if(|x| *x % 2 == 0).collect::>(); /// let odds = numbers; /// /// assert_eq!(evens, vec![2, 4, 6, 8, 14]); /// assert_eq!(odds, vec![1, 3, 5, 9, 11, 13, 15]); /// ``` - #[unstable(feature = "drain_filter", reason = "recently added", issue = "43244")] - pub fn drain_filter(&mut self, filter: F) -> DrainFilter<'_, T, F, A> + #[unstable(feature = "extract_if", reason = "recently added", issue = "43244")] + pub fn extract_if(&mut self, filter: F) -> ExtractIf<'_, T, F, A> where F: FnMut(&mut T) -> bool, { @@ -3260,7 +3251,7 @@ impl Vec { self.set_len(0); } - DrainFilter { vec: self, idx: 0, del: 0, old_len, pred: filter, panic_flag: false } + ExtractIf { vec: self, idx: 0, del: 0, old_len, pred: filter } } } @@ -3290,9 +3281,14 @@ impl<'a, T: Copy + 'a, A: Allocator + 'a> Extend<&'a T> for Vec { /// Implements comparison of vectors, [lexicographically](Ord#lexicographical-comparison). #[stable(feature = "rust1", since = "1.0.0")] -impl PartialOrd for Vec { +impl PartialOrd> for Vec +where + T: PartialOrd, + A1: Allocator, + A2: Allocator, +{ #[inline] - fn partial_cmp(&self, other: &Self) -> Option { + fn partial_cmp(&self, other: &Vec) -> Option { PartialOrd::partial_cmp(&**self, &**other) } } diff --git a/scripts/min-tool-version.sh b/scripts/min-tool-version.sh index d65ab8bfeaf4..dc819612ff6a 100755 --- a/scripts/min-tool-version.sh +++ b/scripts/min-tool-version.sh @@ -31,7 +31,7 @@ llvm) fi ;; rustc) - echo 1.71.1 + echo 1.72.1 ;; bindgen) echo 0.65.1 From bb97dbfaf936fba43dc7b66004bbf4c0386a84c0 Mon Sep 17 00:00:00 2001 From: Miguel Ojeda Date: Wed, 30 Aug 2023 18:59:48 +0200 Subject: [PATCH 18/28] MAINTAINERS: update Rust webpage A few months ago we started a webpage for the Rust subsystem and the overall Rust for Linux project [1]. The current `W:` field of the Rust entry points to the GitHub repository, since originally we kept information in a `README.md` file that got rendered by GitHub when visiting that URL. That information was moved into the webpage and got expanded. The webpage is also nowadays the entry point to the project, and we pointed the "Website" GitHub metadata field to it. Thus update the `W:` field to point to the actual webpage. Link: https://rust-for-linux.com [1] Reviewed-by: Vincenzo Palazzo Reviewed-by: Andreas Hindborg Reviewed-by: Benno Lossin Reviewed-by: Alice Ryhl Reviewed-by: Geert Stappers Reviewed-by: Boqun Feng Link: https://lore.kernel.org/r/20230830165949.127475-1-ojeda@kernel.org Signed-off-by: Miguel Ojeda --- MAINTAINERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index 35977b269d5e..b28a2d8f21b4 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -18709,7 +18709,7 @@ R: Andreas Hindborg R: Alice Ryhl L: rust-for-linux@vger.kernel.org S: Supported -W: https://github.com/Rust-for-Linux/linux +W: https://rust-for-linux.com B: https://github.com/Rust-for-Linux/linux/issues C: zulip://rust-for-linux.zulipchat.com T: git https://github.com/Rust-for-Linux/linux.git rust-next From fc388bea85f88cb9117eda808ed9237af65f3041 Mon Sep 17 00:00:00 2001 From: Miguel Ojeda Date: Wed, 30 Aug 2023 18:59:49 +0200 Subject: [PATCH 19/28] MAINTAINERS: add Maintainer Entry Profile field for Rust The `P:` field allows a URI, and we have been adding information on how to contribute to the Rust subsystem to our webpage for a while now (and other relevant topics, e.g. branches, third-party crates, Rust unstable features...). The webpage/document does not currently follow the headings of the Maintainer Entry Profile, but it does nevertheless answer some of the questions we have got so far from contributors and it covers partially some of the topics there. Thus link to our "Contributing" document [1]. Link: https://rust-for-linux.com/contributing [1] Reviewed-by: Andreas Hindborg Reviewed-by: Alice Ryhl Reviewed-by: Vincenzo Palazzo Reviewed-by: Benno Lossin Link: https://lore.kernel.org/r/20230830165949.127475-2-ojeda@kernel.org Signed-off-by: Miguel Ojeda --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index b28a2d8f21b4..1a5b0bda2b05 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -18712,6 +18712,7 @@ S: Supported W: https://rust-for-linux.com B: https://github.com/Rust-for-Linux/linux/issues C: zulip://rust-for-linux.zulipchat.com +P: https://rust-for-linux.com/contributing T: git https://github.com/Rust-for-Linux/linux.git rust-next F: Documentation/rust/ F: rust/ From b2516f7af9d238ebc391bdbdae01ac9528f1109e Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Sat, 23 Sep 2023 10:46:50 +0800 Subject: [PATCH 20/28] rust: kernel: remove `#[allow(clippy::new_ret_no_self)]` Clippy triggered a false positive on its `new_ret_no_self` lint when using the `pin_init!` macro. Since Rust 1.67.0, that does not happen anymore, since Clippy learnt to not warn about `-> impl Trait` [1][2]. The kernel nowadays uses Rust 1.72.1, thus remove the `#[allow]`. Signed-off-by: Gary Guo Reviewed-by: Alice Ryhl Reviewed-by: Benno Lossin Reviewed-by: Finn Behrens Reviewed-by: Martin Rodriguez Reboredo Link: https://github.com/rust-lang/rust-clippy/issues/7344 [1] Link: https://github.com/rust-lang/rust-clippy/pull/9733 [2] Link: https://lore.kernel.org/r/20230923024707.47610-1-gary@garyguo.net [ Reworded slightly and added a couple `Link`s. ] Signed-off-by: Miguel Ojeda --- rust/kernel/init.rs | 20 ++++++++++---------- rust/kernel/sync/condvar.rs | 1 - rust/kernel/sync/lock.rs | 1 - 3 files changed, 10 insertions(+), 12 deletions(-) diff --git a/rust/kernel/init.rs b/rust/kernel/init.rs index 4ebb6f23fc2e..65be9ae57b80 100644 --- a/rust/kernel/init.rs +++ b/rust/kernel/init.rs @@ -35,7 +35,7 @@ //! that you need to write `<-` instead of `:` for fields that you want to initialize in-place. //! //! ```rust -//! # #![allow(clippy::disallowed_names, clippy::new_ret_no_self)] +//! # #![allow(clippy::disallowed_names)] //! use kernel::{prelude::*, sync::Mutex, new_mutex}; //! # use core::pin::Pin; //! #[pin_data] @@ -55,7 +55,7 @@ //! (or just the stack) to actually initialize a `Foo`: //! //! ```rust -//! # #![allow(clippy::disallowed_names, clippy::new_ret_no_self)] +//! # #![allow(clippy::disallowed_names)] //! # use kernel::{prelude::*, sync::Mutex, new_mutex}; //! # use core::pin::Pin; //! # #[pin_data] @@ -86,7 +86,7 @@ //! To declare an init macro/function you just return an [`impl PinInit`]: //! //! ```rust -//! # #![allow(clippy::disallowed_names, clippy::new_ret_no_self)] +//! # #![allow(clippy::disallowed_names)] //! # use kernel::{sync::Mutex, prelude::*, new_mutex, init::PinInit, try_pin_init}; //! #[pin_data] //! struct DriverData { @@ -236,7 +236,7 @@ pub mod macros; /// # Examples /// /// ```rust -/// # #![allow(clippy::disallowed_names, clippy::new_ret_no_self)] +/// # #![allow(clippy::disallowed_names)] /// # use kernel::{init, macros::pin_data, pin_init, stack_pin_init, init::*, sync::Mutex, new_mutex}; /// # use core::pin::Pin; /// #[pin_data] @@ -288,7 +288,7 @@ macro_rules! stack_pin_init { /// # Examples /// /// ```rust,ignore -/// # #![allow(clippy::disallowed_names, clippy::new_ret_no_self)] +/// # #![allow(clippy::disallowed_names)] /// # use kernel::{init, pin_init, stack_try_pin_init, init::*, sync::Mutex, new_mutex}; /// # use macros::pin_data; /// # use core::{alloc::AllocError, pin::Pin}; @@ -314,7 +314,7 @@ macro_rules! stack_pin_init { /// ``` /// /// ```rust,ignore -/// # #![allow(clippy::disallowed_names, clippy::new_ret_no_self)] +/// # #![allow(clippy::disallowed_names)] /// # use kernel::{init, pin_init, stack_try_pin_init, init::*, sync::Mutex, new_mutex}; /// # use macros::pin_data; /// # use core::{alloc::AllocError, pin::Pin}; @@ -366,7 +366,7 @@ macro_rules! stack_try_pin_init { /// The syntax is almost identical to that of a normal `struct` initializer: /// /// ```rust -/// # #![allow(clippy::disallowed_names, clippy::new_ret_no_self)] +/// # #![allow(clippy::disallowed_names)] /// # use kernel::{init, pin_init, macros::pin_data, init::*}; /// # use core::pin::Pin; /// #[pin_data] @@ -411,7 +411,7 @@ macro_rules! stack_try_pin_init { /// To create an initializer function, simply declare it like this: /// /// ```rust -/// # #![allow(clippy::disallowed_names, clippy::new_ret_no_self)] +/// # #![allow(clippy::disallowed_names)] /// # use kernel::{init, pin_init, prelude::*, init::*}; /// # use core::pin::Pin; /// # #[pin_data] @@ -438,7 +438,7 @@ macro_rules! stack_try_pin_init { /// Users of `Foo` can now create it like this: /// /// ```rust -/// # #![allow(clippy::disallowed_names, clippy::new_ret_no_self)] +/// # #![allow(clippy::disallowed_names)] /// # use kernel::{init, pin_init, macros::pin_data, init::*}; /// # use core::pin::Pin; /// # #[pin_data] @@ -466,7 +466,7 @@ macro_rules! stack_try_pin_init { /// They can also easily embed it into their own `struct`s: /// /// ```rust -/// # #![allow(clippy::disallowed_names, clippy::new_ret_no_self)] +/// # #![allow(clippy::disallowed_names)] /// # use kernel::{init, pin_init, macros::pin_data, init::*}; /// # use core::pin::Pin; /// # #[pin_data] diff --git a/rust/kernel/sync/condvar.rs b/rust/kernel/sync/condvar.rs index ed353399c4e5..b679b6f6dbeb 100644 --- a/rust/kernel/sync/condvar.rs +++ b/rust/kernel/sync/condvar.rs @@ -91,7 +91,6 @@ unsafe impl Sync for CondVar {} impl CondVar { /// Constructs a new condvar initialiser. - #[allow(clippy::new_ret_no_self)] pub fn new(name: &'static CStr, key: &'static LockClassKey) -> impl PinInit { pin_init!(Self { _pin: PhantomPinned, diff --git a/rust/kernel/sync/lock.rs b/rust/kernel/sync/lock.rs index 70a785f04754..f12a684bc957 100644 --- a/rust/kernel/sync/lock.rs +++ b/rust/kernel/sync/lock.rs @@ -99,7 +99,6 @@ unsafe impl Sync for Lock {} impl Lock { /// Constructs a new lock initialiser. - #[allow(clippy::new_ret_no_self)] pub fn new(t: T, name: &'static CStr, key: &'static LockClassKey) -> impl PinInit { pin_init!(Self { data: UnsafeCell::new(t), From c61bcc278b1924da13fd52edbd46b08a518c11ef Mon Sep 17 00:00:00 2001 From: Miguel Ojeda Date: Thu, 5 Oct 2023 23:05:53 +0200 Subject: [PATCH 21/28] rust: task: remove redundant explicit link Starting with Rust 1.73.0, `rustdoc` detects redundant explicit links with its new lint `redundant_explicit_links` [1]: error: redundant explicit link target --> rust/kernel/task.rs:85:21 | 85 | /// [`current`](crate::current) macro because it is safe. | --------- ^^^^^^^^^^^^^^ explicit target is redundant | | | because label contains path that resolves to same destination | = note: when a link's destination is not specified, the label is used to resolve intra-doc links = note: `-D rustdoc::redundant-explicit-links` implied by `-D warnings` help: remove explicit link target | 85 | /// [`current`] macro because it is safe. In order to avoid the warning in the compiler upgrade commit, make it an intra-doc link as the tool suggests. Link: https://github.com/rust-lang/rust/pull/113167 [1] Reviewed-by: Finn Behrens Reviewed-by: Alice Ryhl Reviewed-by: Martin Rodriguez Reboredo Reviewed-by: Vincenzo Palazzo Link: https://lore.kernel.org/r/20231005210556.466856-2-ojeda@kernel.org Signed-off-by: Miguel Ojeda --- rust/kernel/task.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust/kernel/task.rs b/rust/kernel/task.rs index 7eda15e5f1b3..b2299bc7ac1f 100644 --- a/rust/kernel/task.rs +++ b/rust/kernel/task.rs @@ -82,7 +82,7 @@ impl Task { /// Returns a task reference for the currently executing task/thread. /// /// The recommended way to get the current task/thread is to use the - /// [`current`](crate::current) macro because it is safe. + /// [`current`] macro because it is safe. /// /// # Safety /// From a53d8cdd5a0aec75ae32badc2d8995c59ea6e3f0 Mon Sep 17 00:00:00 2001 From: Miguel Ojeda Date: Thu, 5 Oct 2023 23:05:54 +0200 Subject: [PATCH 22/28] rust: print: use explicit link in documentation The future `rustdoc` in the Rust 1.73.0 upgrade requires an explicit link for `pr_info!`: error: unresolved link to `pr_info` --> rust/kernel/print.rs:395:63 | 395 | /// Use only when continuing a previous `pr_*!` macro (e.g. [`pr_info!`]). | ^^^^^^^^ no item named `pr_info` in scope | = note: `macro_rules` named `pr_info` exists in this crate, but it is not in scope at this link's location = note: `-D rustdoc::broken-intra-doc-links` implied by `-D warnings` Thus do so to avoid a broken link while upgrading. Reviewed-by: Alice Ryhl Reviewed-by: Vincenzo Palazzo Reviewed-by: Finn Behrens Reviewed-by: Martin Rodriguez Reboredo Link: https://lore.kernel.org/r/20231005210556.466856-3-ojeda@kernel.org Signed-off-by: Miguel Ojeda --- rust/kernel/print.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/rust/kernel/print.rs b/rust/kernel/print.rs index 8009184bf6d7..f48926e3e9fe 100644 --- a/rust/kernel/print.rs +++ b/rust/kernel/print.rs @@ -399,6 +399,7 @@ macro_rules! pr_debug ( /// Mimics the interface of [`std::print!`]. See [`core::fmt`] and /// `alloc::format!` for information about the formatting syntax. /// +/// [`pr_info!`]: crate::pr_info! /// [`pr_cont`]: https://www.kernel.org/doc/html/latest/core-api/printk-basics.html#c.pr_cont /// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html /// From e08ff622c91af997cb89bc47e90a1a383e938bd0 Mon Sep 17 00:00:00 2001 From: Miguel Ojeda Date: Thu, 5 Oct 2023 23:05:55 +0200 Subject: [PATCH 23/28] rust: upgrade to Rust 1.73.0 This is the next upgrade to the Rust toolchain, from 1.72.1 to 1.73.0 (i.e. the latest) [1]. See the upgrade policy [2] and the comments on the first upgrade in commit 3ed03f4da06e ("rust: upgrade to Rust 1.68.2"). # Unstable features No unstable features (that we use) were stabilized. Therefore, the only unstable feature allowed to be used outside the `kernel` crate is still `new_uninit`, though other code to be upstreamed may increase the list. Please see [3] for details. # Required changes For the upgrade, the following changes are required: - Allow `internal_features` for `feature(compiler_builtins)` since now Rust warns about using internal compiler and standard library features (similar to how it also warns about incomplete ones) [4]. - A cleanup for a documentation link thanks to a new `rustdoc` lint. See previous commits for details. - A need to make an intra-doc link to a macro explicit, due to a change in behavior in `rustdoc`. See previous commits for details. # `alloc` upgrade and reviewing The vast majority of changes are due to our `alloc` fork being upgraded at once. There are two kinds of changes to be aware of: the ones coming from upstream, which we should follow as closely as possible, and the updates needed in our added fallible APIs to keep them matching the newer infallible APIs coming from upstream. Instead of taking a look at the diff of this patch, an alternative approach is reviewing a diff of the changes between upstream `alloc` and the kernel's. This allows to easily inspect the kernel additions only, especially to check if the fallible methods we already have still match the infallible ones in the new version coming from upstream. Another approach is reviewing the changes introduced in the additions in the kernel fork between the two versions. This is useful to spot potentially unintended changes to our additions. To apply these approaches, one may follow steps similar to the following to generate a pair of patches that show the differences between upstream Rust and the kernel (for the subset of `alloc` we use) before and after applying this patch: # Get the difference with respect to the old version. git -C rust checkout $(linux/scripts/min-tool-version.sh rustc) git -C linux ls-tree -r --name-only HEAD -- rust/alloc | cut -d/ -f3- | grep -Fv README.md | xargs -IPATH cp rust/library/alloc/src/PATH linux/rust/alloc/PATH git -C linux diff --patch-with-stat --summary -R > old.patch git -C linux restore rust/alloc # Apply this patch. git -C linux am rust-upgrade.patch # Get the difference with respect to the new version. git -C rust checkout $(linux/scripts/min-tool-version.sh rustc) git -C linux ls-tree -r --name-only HEAD -- rust/alloc | cut -d/ -f3- | grep -Fv README.md | xargs -IPATH cp rust/library/alloc/src/PATH linux/rust/alloc/PATH git -C linux diff --patch-with-stat --summary -R > new.patch git -C linux restore rust/alloc Now one may check the `new.patch` to take a look at the additions (first approach) or at the difference between those two patches (second approach). For the latter, a side-by-side tool is recommended. Link: https://github.com/rust-lang/rust/blob/stable/RELEASES.md#version-1730-2023-10-05 [1] Link: https://rust-for-linux.com/rust-version-policy [2] Link: https://github.com/Rust-for-Linux/linux/issues/2 [3] Link: https://github.com/rust-lang/compiler-team/issues/596 [4] Reviewed-by: Martin Rodriguez Reboredo Reviewed-by: Vincenzo Palazzo Reviewed-by: Alice Ryhl Link: https://lore.kernel.org/r/20231005210556.466856-4-ojeda@kernel.org Signed-off-by: Miguel Ojeda --- Documentation/process/changes.rst | 2 +- rust/alloc/alloc.rs | 22 -------------- rust/alloc/boxed.rs | 48 ++++++++++++++++++++----------- rust/alloc/lib.rs | 5 ++-- rust/alloc/raw_vec.rs | 30 ++++++++++++------- rust/alloc/vec/mod.rs | 4 +-- rust/alloc/vec/spec_extend.rs | 8 +++--- rust/compiler_builtins.rs | 1 + scripts/min-tool-version.sh | 2 +- 9 files changed, 63 insertions(+), 59 deletions(-) diff --git a/Documentation/process/changes.rst b/Documentation/process/changes.rst index 731cc104c56f..bb96ca0f774b 100644 --- a/Documentation/process/changes.rst +++ b/Documentation/process/changes.rst @@ -31,7 +31,7 @@ you probably needn't concern yourself with pcmciautils. ====================== =============== ======================================== GNU C 5.1 gcc --version Clang/LLVM (optional) 11.0.0 clang --version -Rust (optional) 1.72.1 rustc --version +Rust (optional) 1.73.0 rustc --version bindgen (optional) 0.65.1 bindgen --version GNU make 3.82 make --version bash 4.2 bash --version diff --git a/rust/alloc/alloc.rs b/rust/alloc/alloc.rs index 51821feb20b1..8cb4a31cf6e5 100644 --- a/rust/alloc/alloc.rs +++ b/rust/alloc/alloc.rs @@ -6,11 +6,7 @@ #[cfg(not(test))] use core::intrinsics; -#[cfg(all(bootstrap, not(test)))] -use core::intrinsics::{min_align_of_val, size_of_val}; -#[cfg(all(bootstrap, not(test)))] -use core::ptr::Unique; #[cfg(not(test))] use core::ptr::{self, NonNull}; @@ -339,23 +335,6 @@ unsafe fn exchange_malloc(size: usize, align: usize) -> *mut u8 { } } -#[cfg(all(bootstrap, not(test)))] -#[lang = "box_free"] -#[inline] -// This signature has to be the same as `Box`, otherwise an ICE will happen. -// When an additional parameter to `Box` is added (like `A: Allocator`), this has to be added here as -// well. -// For example if `Box` is changed to `struct Box(Unique, A)`, -// this function has to be changed to `fn box_free(Unique, A)` as well. -unsafe fn box_free(ptr: Unique, alloc: A) { - unsafe { - let size = size_of_val(ptr.as_ref()); - let align = min_align_of_val(ptr.as_ref()); - let layout = Layout::from_size_align_unchecked(size, align); - alloc.deallocate(From::from(ptr.cast()), layout) - } -} - // # Allocation error handler #[cfg(not(no_global_oom_handling))] @@ -415,7 +394,6 @@ pub mod __alloc_error_handler { static __rust_alloc_error_handler_should_panic: u8; } - #[allow(unused_unsafe)] if unsafe { __rust_alloc_error_handler_should_panic != 0 } { panic!("memory allocation of {size} bytes failed") } else { diff --git a/rust/alloc/boxed.rs b/rust/alloc/boxed.rs index bdab710f7737..9620eba17268 100644 --- a/rust/alloc/boxed.rs +++ b/rust/alloc/boxed.rs @@ -159,12 +159,12 @@ use core::hash::{Hash, Hasher}; use core::iter::FusedIterator; use core::marker::Tuple; use core::marker::Unsize; -use core::mem; +use core::mem::{self, SizedTypeProperties}; use core::ops::{ CoerceUnsized, Deref, DerefMut, DispatchFromDyn, Generator, GeneratorState, Receiver, }; use core::pin::Pin; -use core::ptr::{self, Unique}; +use core::ptr::{self, NonNull, Unique}; use core::task::{Context, Poll}; #[cfg(not(no_global_oom_handling))] @@ -483,8 +483,12 @@ impl Box { where A: Allocator, { - let layout = Layout::new::>(); - let ptr = alloc.allocate(layout)?.cast(); + let ptr = if T::IS_ZST { + NonNull::dangling() + } else { + let layout = Layout::new::>(); + alloc.allocate(layout)?.cast() + }; unsafe { Ok(Box::from_raw_in(ptr.as_ptr(), alloc)) } } @@ -553,8 +557,12 @@ impl Box { where A: Allocator, { - let layout = Layout::new::>(); - let ptr = alloc.allocate_zeroed(layout)?.cast(); + let ptr = if T::IS_ZST { + NonNull::dangling() + } else { + let layout = Layout::new::>(); + alloc.allocate_zeroed(layout)?.cast() + }; unsafe { Ok(Box::from_raw_in(ptr.as_ptr(), alloc)) } } @@ -679,14 +687,16 @@ impl Box<[T]> { #[unstable(feature = "allocator_api", issue = "32838")] #[inline] pub fn try_new_uninit_slice(len: usize) -> Result]>, AllocError> { - unsafe { + let ptr = if T::IS_ZST || len == 0 { + NonNull::dangling() + } else { let layout = match Layout::array::>(len) { Ok(l) => l, Err(_) => return Err(AllocError), }; - let ptr = Global.allocate(layout)?; - Ok(RawVec::from_raw_parts_in(ptr.as_mut_ptr() as *mut _, len, Global).into_box(len)) - } + Global.allocate(layout)?.cast() + }; + unsafe { Ok(RawVec::from_raw_parts_in(ptr.as_ptr(), len, Global).into_box(len)) } } /// Constructs a new boxed slice with uninitialized contents, with the memory @@ -711,14 +721,16 @@ impl Box<[T]> { #[unstable(feature = "allocator_api", issue = "32838")] #[inline] pub fn try_new_zeroed_slice(len: usize) -> Result]>, AllocError> { - unsafe { + let ptr = if T::IS_ZST || len == 0 { + NonNull::dangling() + } else { let layout = match Layout::array::>(len) { Ok(l) => l, Err(_) => return Err(AllocError), }; - let ptr = Global.allocate_zeroed(layout)?; - Ok(RawVec::from_raw_parts_in(ptr.as_mut_ptr() as *mut _, len, Global).into_box(len)) - } + Global.allocate_zeroed(layout)?.cast() + }; + unsafe { Ok(RawVec::from_raw_parts_in(ptr.as_ptr(), len, Global).into_box(len)) } } } @@ -1223,7 +1235,9 @@ unsafe impl<#[may_dangle] T: ?Sized, A: Allocator> Drop for Box { unsafe { let layout = Layout::for_value_raw(ptr.as_ptr()); - self.1.deallocate(From::from(ptr.cast()), layout) + if layout.size() != 0 { + self.1.deallocate(From::from(ptr.cast()), layout); + } } } } @@ -2173,7 +2187,7 @@ impl dyn Error + Send { let err: Box = self; ::downcast(err).map_err(|s| unsafe { // Reapply the `Send` marker. - mem::transmute::, Box>(s) + Box::from_raw(Box::into_raw(s) as *mut (dyn Error + Send)) }) } } @@ -2187,7 +2201,7 @@ impl dyn Error + Send + Sync { let err: Box = self; ::downcast(err).map_err(|s| unsafe { // Reapply the `Send + Sync` marker. - mem::transmute::, Box>(s) + Box::from_raw(Box::into_raw(s) as *mut (dyn Error + Send + Sync)) }) } } diff --git a/rust/alloc/lib.rs b/rust/alloc/lib.rs index 115fcb053e73..73b9ffd845d9 100644 --- a/rust/alloc/lib.rs +++ b/rust/alloc/lib.rs @@ -60,7 +60,7 @@ // To run alloc tests without x.py without ending up with two copies of alloc, Miri needs to be // able to "empty" this crate. See . -// rustc itself never sets the feature, so this line has no affect there. +// rustc itself never sets the feature, so this line has no effect there. #![cfg(any(not(feature = "miri-test-libstd"), test, doctest))] // #![allow(unused_attributes)] @@ -90,6 +90,8 @@ #![warn(missing_docs)] #![allow(explicit_outlives_requirements)] #![warn(multiple_supertrait_upcastable)] +#![cfg_attr(not(bootstrap), allow(internal_features))] +#![cfg_attr(not(bootstrap), allow(rustdoc::redundant_explicit_links))] // // Library features: // tidy-alphabetical-start @@ -139,7 +141,6 @@ #![feature(maybe_uninit_uninit_array_transpose)] #![feature(pattern)] #![feature(pointer_byte_offsets)] -#![feature(provide_any)] #![feature(ptr_internals)] #![feature(ptr_metadata)] #![feature(ptr_sub_ptr)] diff --git a/rust/alloc/raw_vec.rs b/rust/alloc/raw_vec.rs index 65d5ce15828e..a7425582a323 100644 --- a/rust/alloc/raw_vec.rs +++ b/rust/alloc/raw_vec.rs @@ -471,16 +471,26 @@ impl RawVec { let (ptr, layout) = if let Some(mem) = self.current_memory() { mem } else { return Ok(()) }; // See current_memory() why this assert is here let _: () = const { assert!(mem::size_of::() % mem::align_of::() == 0) }; - let ptr = unsafe { - // `Layout::array` cannot overflow here because it would have - // overflowed earlier when capacity was larger. - let new_size = mem::size_of::().unchecked_mul(cap); - let new_layout = Layout::from_size_align_unchecked(new_size, layout.align()); - self.alloc - .shrink(ptr, layout, new_layout) - .map_err(|_| AllocError { layout: new_layout, non_exhaustive: () })? - }; - self.set_ptr_and_cap(ptr, cap); + + // If shrinking to 0, deallocate the buffer. We don't reach this point + // for the T::IS_ZST case since current_memory() will have returned + // None. + if cap == 0 { + unsafe { self.alloc.deallocate(ptr, layout) }; + self.ptr = Unique::dangling(); + self.cap = 0; + } else { + let ptr = unsafe { + // `Layout::array` cannot overflow here because it would have + // overflowed earlier when capacity was larger. + let new_size = mem::size_of::().unchecked_mul(cap); + let new_layout = Layout::from_size_align_unchecked(new_size, layout.align()); + self.alloc + .shrink(ptr, layout, new_layout) + .map_err(|_| AllocError { layout: new_layout, non_exhaustive: () })? + }; + self.set_ptr_and_cap(ptr, cap); + } Ok(()) } } diff --git a/rust/alloc/vec/mod.rs b/rust/alloc/vec/mod.rs index a4e9a5002a6d..209a88cfe598 100644 --- a/rust/alloc/vec/mod.rs +++ b/rust/alloc/vec/mod.rs @@ -216,7 +216,7 @@ mod spec_extend; /// /// # Indexing /// -/// The `Vec` type allows to access values by index, because it implements the +/// The `Vec` type allows access to values by index, because it implements the /// [`Index`] trait. An example will be more explicit: /// /// ``` @@ -3263,7 +3263,7 @@ impl Vec { /// [`copy_from_slice`]: slice::copy_from_slice #[cfg(not(no_global_oom_handling))] #[stable(feature = "extend_ref", since = "1.2.0")] -impl<'a, T: Copy + 'a, A: Allocator + 'a> Extend<&'a T> for Vec { +impl<'a, T: Copy + 'a, A: Allocator> Extend<&'a T> for Vec { fn extend>(&mut self, iter: I) { self.spec_extend(iter.into_iter()) } diff --git a/rust/alloc/vec/spec_extend.rs b/rust/alloc/vec/spec_extend.rs index a6a735201e59..ada919537446 100644 --- a/rust/alloc/vec/spec_extend.rs +++ b/rust/alloc/vec/spec_extend.rs @@ -77,7 +77,7 @@ impl TrySpecExtend> for Vec { } #[cfg(not(no_global_oom_handling))] -impl<'a, T: 'a, I, A: Allocator + 'a> SpecExtend<&'a T, I> for Vec +impl<'a, T: 'a, I, A: Allocator> SpecExtend<&'a T, I> for Vec where I: Iterator, T: Clone, @@ -87,7 +87,7 @@ where } } -impl<'a, T: 'a, I, A: Allocator + 'a> TrySpecExtend<&'a T, I> for Vec +impl<'a, T: 'a, I, A: Allocator> TrySpecExtend<&'a T, I> for Vec where I: Iterator, T: Clone, @@ -98,7 +98,7 @@ where } #[cfg(not(no_global_oom_handling))] -impl<'a, T: 'a, A: Allocator + 'a> SpecExtend<&'a T, slice::Iter<'a, T>> for Vec +impl<'a, T: 'a, A: Allocator> SpecExtend<&'a T, slice::Iter<'a, T>> for Vec where T: Copy, { @@ -108,7 +108,7 @@ where } } -impl<'a, T: 'a, A: Allocator + 'a> TrySpecExtend<&'a T, slice::Iter<'a, T>> for Vec +impl<'a, T: 'a, A: Allocator> TrySpecExtend<&'a T, slice::Iter<'a, T>> for Vec where T: Copy, { diff --git a/rust/compiler_builtins.rs b/rust/compiler_builtins.rs index fb8ac3f211de..bba2922c6ef7 100644 --- a/rust/compiler_builtins.rs +++ b/rust/compiler_builtins.rs @@ -19,6 +19,7 @@ //! [`compiler_builtins`]: https://github.com/rust-lang/compiler-builtins //! [`compiler-rt`]: https://compiler-rt.llvm.org/ +#![allow(internal_features)] #![feature(compiler_builtins)] #![compiler_builtins] #![no_builtins] diff --git a/scripts/min-tool-version.sh b/scripts/min-tool-version.sh index dc819612ff6a..fd5ffdb81bab 100755 --- a/scripts/min-tool-version.sh +++ b/scripts/min-tool-version.sh @@ -31,7 +31,7 @@ llvm) fi ;; rustc) - echo 1.72.1 + echo 1.73.0 ;; bindgen) echo 0.65.1 From 45f97e6385cad6d0e48a27ddcd08793bb4d35851 Mon Sep 17 00:00:00 2001 From: Matthew Maurer Date: Thu, 28 Sep 2023 20:49:25 +0000 Subject: [PATCH 24/28] rust: Use awk instead of recent xargs `awk` is already required by the kernel build, and the `xargs` feature used in current Rust detection is not present in all `xargs` (notably, toybox based xargs, used in the Android kernel build). Signed-off-by: Matthew Maurer Reviewed-by: Alice Ryhl Tested-by: Alice Ryhl Reviewed-by: Martin Rodriguez Reboredo Link: https://lore.kernel.org/r/20230928205045.2375899-1-mmaurer@google.com Signed-off-by: Miguel Ojeda --- rust/Makefile | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/rust/Makefile b/rust/Makefile index 87958e864be0..c4e583e9e443 100644 --- a/rust/Makefile +++ b/rust/Makefile @@ -364,9 +364,7 @@ $(obj)/bindings/bindings_helpers_generated.rs: $(src)/helpers.c FORCE quiet_cmd_exports = EXPORTS $@ cmd_exports = \ $(NM) -p --defined-only $< \ - | grep -E ' (T|R|D) ' | cut -d ' ' -f 3 \ - | xargs -Isymbol \ - echo 'EXPORT_SYMBOL_RUST_GPL(symbol);' > $@ + | awk '/ (T|R|D) / {printf "EXPORT_SYMBOL_RUST_GPL(%s);\n",$$3}' > $@ $(obj)/exports_core_generated.h: $(obj)/core.o FORCE $(call if_changed,exports) From a7135d10754760f0c038497b44c2c2f2b0fb5651 Mon Sep 17 00:00:00 2001 From: Matthew Maurer Date: Thu, 28 Sep 2023 20:14:20 +0000 Subject: [PATCH 25/28] rust: Use grep -Ev rather than relying on GNU grep While GNU grep supports '\|' when in basic regular expression mode, not all grep implementations do (notably toybox grep, used to build the Android kernel, does not). Switching to grep -Ev enables extended regular expressions which includes support for the '|' operator. Signed-off-by: Matthew Maurer Reviewed-by: Martin Rodriguez Reboredo Reviewed-by: Trevor Gross Reviewed-by: Alice Ryhl Tested-by: Alice Ryhl Link: https://lore.kernel.org/r/20230928201421.2296518-1-mmaurer@google.com [ Reworded for typo. ] Signed-off-by: Miguel Ojeda --- rust/Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rust/Makefile b/rust/Makefile index c4e583e9e443..a27f35f924ec 100644 --- a/rust/Makefile +++ b/rust/Makefile @@ -336,13 +336,13 @@ quiet_cmd_bindgen = BINDGEN $@ $(bindgen_target_cflags) $(bindgen_target_extra) $(obj)/bindings/bindings_generated.rs: private bindgen_target_flags = \ - $(shell grep -v '^#\|^$$' $(srctree)/$(src)/bindgen_parameters) + $(shell grep -Ev '^#|^$$' $(srctree)/$(src)/bindgen_parameters) $(obj)/bindings/bindings_generated.rs: $(src)/bindings/bindings_helper.h \ $(src)/bindgen_parameters FORCE $(call if_changed_dep,bindgen) $(obj)/uapi/uapi_generated.rs: private bindgen_target_flags = \ - $(shell grep -v '^#\|^$$' $(srctree)/$(src)/bindgen_parameters) + $(shell grep -Ev '^#|^$$' $(srctree)/$(src)/bindgen_parameters) $(obj)/uapi/uapi_generated.rs: $(src)/uapi/uapi_helper.h \ $(src)/bindgen_parameters FORCE $(call if_changed_dep,bindgen) From 6a5c032c4b7e4262488703086ab280406dc51298 Mon Sep 17 00:00:00 2001 From: Matthew Maurer Date: Mon, 9 Oct 2023 22:42:54 +0000 Subject: [PATCH 26/28] x86: Enable IBT in Rust if enabled in C These flags are not made conditional on compiler support because at the moment exactly one version of rustc supported, and that one supports these flags. Building without these additional flags will manifest as objtool printing a large number of errors about missing ENDBR and if CFI is enabled (not currently possible) will result in incorrectly structured function prefixes. Signed-off-by: Matthew Maurer Reviewed-by: Nick Desaulniers Acked-by: "Peter Zijlstra (Intel)" Link: https://lore.kernel.org/r/20231009224347.2076221-1-mmaurer@google.com Signed-off-by: Miguel Ojeda --- arch/x86/Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/x86/Makefile b/arch/x86/Makefile index 5bfe5caaa444..941f7abf6dbf 100644 --- a/arch/x86/Makefile +++ b/arch/x86/Makefile @@ -81,6 +81,7 @@ ifeq ($(CONFIG_X86_KERNEL_IBT),y) # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=104816 # KBUILD_CFLAGS += $(call cc-option,-fcf-protection=branch -fno-jump-tables) +KBUILD_RUSTFLAGS += -Zcf-protection=branch -Zno-jump-tables else KBUILD_CFLAGS += $(call cc-option,-fcf-protection=none) endif From 3857af38e57a80b15b994e19d1f4301cac796481 Mon Sep 17 00:00:00 2001 From: Miguel Ojeda Date: Wed, 18 Oct 2023 18:09:22 +0200 Subject: [PATCH 27/28] docs: rust: add "The Rust experiment" section Clarify that the Rust experiment is still going on to avoid confusion for both kernel maintainers and end users. Reviewed-by: Carlos Bilbao Link: https://lore.kernel.org/r/20231018160922.1018962-1-ojeda@kernel.org [ Changed last paragraph as discussed in the mailing list. ] Signed-off-by: Miguel Ojeda --- Documentation/rust/index.rst | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/Documentation/rust/index.rst b/Documentation/rust/index.rst index e599be2cec9b..965f2db529e0 100644 --- a/Documentation/rust/index.rst +++ b/Documentation/rust/index.rst @@ -6,6 +6,25 @@ Rust Documentation related to Rust within the kernel. To start using Rust in the kernel, please read the quick-start.rst guide. + +The Rust experiment +------------------- + +The Rust support was merged in v6.1 into mainline in order to help in +determining whether Rust as a language was suitable for the kernel, i.e. worth +the tradeoffs. + +Currently, the Rust support is primarily intended for kernel developers and +maintainers interested in the Rust support, so that they can start working on +abstractions and drivers, as well as helping the development of infrastructure +and tools. + +If you are an end user, please note that there are currently no in-tree +drivers/modules suitable or intended for production use, and that the Rust +support is still in development/experimental, especially for certain kernel +configurations. + + .. only:: rustdoc and html You can also browse `rustdoc documentation `_. From 47846d51348dd62e5231a83be040981b17c955fa Mon Sep 17 00:00:00 2001 From: Paul Moore Date: Mon, 9 Oct 2023 13:18:49 -0400 Subject: [PATCH 28/28] audit: don't take task_lock() in audit_exe_compare() code path The get_task_exe_file() function locks the given task with task_lock() which when used inside audit_exe_compare() can cause deadlocks on systems that generate audit records when the task_lock() is held. We resolve this problem with two changes: ignoring those cases where the task being audited is not the current task, and changing our approach to obtaining the executable file struct to not require task_lock(). With the intent of the audit exe filter being to filter on audit events generated by processes started by the specified executable, it makes sense that we would only want to use the exe filter on audit records associated with the currently executing process, e.g. @current. If we are asked to filter records using a non-@current task_struct we can safely ignore the exe filter without negatively impacting the admin's expectations for the exe filter. Knowing that we only have to worry about filtering the currently executing task in audit_exe_compare() we can do away with the task_lock() and call get_mm_exe_file() with @current->mm directly. Cc: Fixes: 5efc244346f9 ("audit: fix exe_file access in audit_exe_compare") Reported-by: Andreas Steinmetz Reviewed-by: John Johansen Reviewed-by: Mateusz Guzik Signed-off-by: Paul Moore --- kernel/audit_watch.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/kernel/audit_watch.c b/kernel/audit_watch.c index 65075f1e4ac8..91e82e34b51e 100644 --- a/kernel/audit_watch.c +++ b/kernel/audit_watch.c @@ -527,11 +527,18 @@ int audit_exe_compare(struct task_struct *tsk, struct audit_fsnotify_mark *mark) unsigned long ino; dev_t dev; - exe_file = get_task_exe_file(tsk); + /* only do exe filtering if we are recording @current events/records */ + if (tsk != current) + return 0; + + if (WARN_ON_ONCE(!current->mm)) + return 0; + exe_file = get_mm_exe_file(current->mm); if (!exe_file) return 0; ino = file_inode(exe_file)->i_ino; dev = file_inode(exe_file)->i_sb->s_dev; fput(exe_file); + return audit_mark_compare(mark, ino, dev); }