Commit 3dc58c9c authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag 'mm-hotfixes-stable-2026-02-06-12-37' of...

Merge tag 'mm-hotfixes-stable-2026-02-06-12-37' of git://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm

Pull hotfixes from Andrew Morton:
 "A couple of late-breaking MM fixes. One against a new-in-this-cycle
  patch and the other addresses a locking issue which has been there for
  over a year"

* tag 'mm-hotfixes-stable-2026-02-06-12-37' of git://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm:
  mm/memory-failure: reject unsupported non-folio compound page
  procfs: avoid fetching build ID while holding VMA lock
parents bab849a9 ae9fd76c
Loading
Loading
Loading
Loading
+27 −15
Original line number Diff line number Diff line
@@ -656,6 +656,7 @@ static int do_procmap_query(struct mm_struct *mm, void __user *uarg)
	struct proc_maps_locking_ctx lock_ctx = { .mm = mm };
	struct procmap_query karg;
	struct vm_area_struct *vma;
	struct file *vm_file = NULL;
	const char *name = NULL;
	char build_id_buf[BUILD_ID_SIZE_MAX], *name_buf = NULL;
	__u64 usize;
@@ -727,21 +728,6 @@ static int do_procmap_query(struct mm_struct *mm, void __user *uarg)
		karg.inode = 0;
	}

	if (karg.build_id_size) {
		__u32 build_id_sz;

		err = build_id_parse(vma, build_id_buf, &build_id_sz);
		if (err) {
			karg.build_id_size = 0;
		} else {
			if (karg.build_id_size < build_id_sz) {
				err = -ENAMETOOLONG;
				goto out;
			}
			karg.build_id_size = build_id_sz;
		}
	}

	if (karg.vma_name_size) {
		size_t name_buf_sz = min_t(size_t, PATH_MAX, karg.vma_name_size);
		const struct path *path;
@@ -775,10 +761,34 @@ static int do_procmap_query(struct mm_struct *mm, void __user *uarg)
		karg.vma_name_size = name_sz;
	}

	if (karg.build_id_size && vma->vm_file)
		vm_file = get_file(vma->vm_file);

	/* unlock vma or mmap_lock, and put mm_struct before copying data to user */
	query_vma_teardown(&lock_ctx);
	mmput(mm);

	if (karg.build_id_size) {
		__u32 build_id_sz;

		if (vm_file)
			err = build_id_parse_file(vm_file, build_id_buf, &build_id_sz);
		else
			err = -ENOENT;
		if (err) {
			karg.build_id_size = 0;
		} else {
			if (karg.build_id_size < build_id_sz) {
				err = -ENAMETOOLONG;
				goto out;
			}
			karg.build_id_size = build_id_sz;
		}
	}

	if (vm_file)
		fput(vm_file);

	if (karg.vma_name_size && copy_to_user(u64_to_user_ptr(karg.vma_name_addr),
					       name, karg.vma_name_size)) {
		kfree(name_buf);
@@ -798,6 +808,8 @@ static int do_procmap_query(struct mm_struct *mm, void __user *uarg)
out:
	query_vma_teardown(&lock_ctx);
	mmput(mm);
	if (vm_file)
		fput(vm_file);
	kfree(name_buf);
	return err;
}
+3 −0
Original line number Diff line number Diff line
@@ -7,7 +7,10 @@
#define BUILD_ID_SIZE_MAX 20

struct vm_area_struct;
struct file;

int build_id_parse(struct vm_area_struct *vma, unsigned char *build_id, __u32 *size);
int build_id_parse_file(struct file *file, unsigned char *build_id, __u32 *size);
int build_id_parse_nofault(struct vm_area_struct *vma, unsigned char *build_id, __u32 *size);
int build_id_parse_buf(const void *buf, unsigned char *build_id, u32 buf_size);

+30 −12
Original line number Diff line number Diff line
@@ -279,7 +279,7 @@ static int get_build_id_64(struct freader *r, unsigned char *build_id, __u32 *si
/* enough for Elf64_Ehdr, Elf64_Phdr, and all the smaller requests */
#define MAX_FREADER_BUF_SZ 64

static int __build_id_parse(struct vm_area_struct *vma, unsigned char *build_id,
static int __build_id_parse(struct file *file, unsigned char *build_id,
			    __u32 *size, bool may_fault)
{
	const Elf32_Ehdr *ehdr;
@@ -287,11 +287,7 @@ static int __build_id_parse(struct vm_area_struct *vma, unsigned char *build_id,
	char buf[MAX_FREADER_BUF_SZ];
	int ret;

	/* only works for page backed storage  */
	if (!vma->vm_file)
		return -EINVAL;

	freader_init_from_file(&r, buf, sizeof(buf), vma->vm_file, may_fault);
	freader_init_from_file(&r, buf, sizeof(buf), file, may_fault);

	/* fetch first 18 bytes of ELF header for checks */
	ehdr = freader_fetch(&r, 0, offsetofend(Elf32_Ehdr, e_type));
@@ -319,8 +315,8 @@ static int __build_id_parse(struct vm_area_struct *vma, unsigned char *build_id,
	return ret;
}

/*
 * Parse build ID of ELF file mapped to vma
/**
 * build_id_parse_nofault() - Parse build ID of ELF file mapped to vma
 * @vma:      vma object
 * @build_id: buffer to store build id, at least BUILD_ID_SIZE long
 * @size:     returns actual build id size in case of success
@@ -332,11 +328,14 @@ static int __build_id_parse(struct vm_area_struct *vma, unsigned char *build_id,
 */
int build_id_parse_nofault(struct vm_area_struct *vma, unsigned char *build_id, __u32 *size)
{
	return __build_id_parse(vma, build_id, size, false /* !may_fault */);
	if (!vma->vm_file)
		return -EINVAL;

	return __build_id_parse(vma->vm_file, build_id, size, false /* !may_fault */);
}

/*
 * Parse build ID of ELF file mapped to VMA
/**
 * build_id_parse() - Parse build ID of ELF file mapped to VMA
 * @vma:      vma object
 * @build_id: buffer to store build id, at least BUILD_ID_SIZE long
 * @size:     returns actual build id size in case of success
@@ -348,7 +347,26 @@ int build_id_parse_nofault(struct vm_area_struct *vma, unsigned char *build_id,
 */
int build_id_parse(struct vm_area_struct *vma, unsigned char *build_id, __u32 *size)
{
	return __build_id_parse(vma, build_id, size, true /* may_fault */);
	if (!vma->vm_file)
		return -EINVAL;

	return __build_id_parse(vma->vm_file, build_id, size, true /* may_fault */);
}

/**
 * build_id_parse_file() - Parse build ID of ELF file
 * @file:      file object
 * @build_id: buffer to store build id, at least BUILD_ID_SIZE long
 * @size:     returns actual build id size in case of success
 *
 * Assumes faultable context and can cause page faults to bring in file data
 * into page cache.
 *
 * Return: 0 on success; negative error, otherwise
 */
int build_id_parse_file(struct file *file, unsigned char *build_id, __u32 *size)
{
	return __build_id_parse(file, build_id, size, true /* may_fault */);
}

/**
+20 −22
Original line number Diff line number Diff line
@@ -2411,7 +2411,6 @@ int memory_failure(unsigned long pfn, int flags)
	 * In fact it's dangerous to directly bump up page count from 0,
	 * that may make page_ref_freeze()/page_ref_unfreeze() mismatch.
	 */
	if (!(flags & MF_COUNT_INCREASED)) {
	res = get_hwpoison_page(p, flags);
	if (!res) {
		if (is_free_buddy_page(p)) {
@@ -2436,7 +2435,6 @@ int memory_failure(unsigned long pfn, int flags)
		res = action_result(pfn, MF_MSG_GET_HWPOISON, MF_IGNORED);
		goto unlock_mutex;
	}
	}

	folio = page_folio(p);