Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ACPI: debug: fix signedness issues in read/write helpers

In the ACPI debugger interface, the helper functions for read and write
operations use "int" as the length parameter data type. When a large
"size_t count" is passed from the file operations, this cast to "int"
results in truncation and a negative value due to signed integer
representation.

Logically, this negative number propagates to the min() calculation,
where it is selected over the positive buffer space value, leading to
unexpected behavior. Subsequently, when this negative value is used in
copy_to_user() or copy_from_user(), it is interpreted as a large positive
value due to the unsigned nature of the size parameter in these functions,
causing the copy operations to attempt handling sizes far beyond the
intended buffer limits.

Address the issue by:
- Changing the length parameters in acpi_aml_read_user() and
acpi_aml_write_user() from "int" to "size_t", aligning with the
expected unsigned size semantics.
- Updating return types and local variables in acpi_aml_read() and
acpi_aml_write() to "ssize_t" for consistency with kernel file
operation conventions.
- Using "size_t" for the "n" variable to ensure calculations remain
unsigned.
- Using min_t() for circ_count_to_end() and circ_space_to_end() to
ensure type-safe comparisons and prevent integer overflow.

Signed-off-by: Amir Mohammad Jahangirzad <a.jahangirzad@gmail.com>
Link: https://patch.msgid.link/20250923013113.20615-1-a.jahangirzad@gmail.com
[ rjw: Changelog tweaks, local variable definitions ordering adjustments ]
Fixes: 8cfb0cdf07e2 ("ACPI / debugger: Add IO interface to access debugger functionalities")
Cc: 4.5+ <stable@vger.kernel.org> # 4.5+
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>

authored by

Amir Mohammad Jahangirzad and committed by
Rafael J. Wysocki
496f9372 07e27ad1

+13 -13
+13 -13
drivers/acpi/acpi_dbg.c
··· 569 569 return 0; 570 570 } 571 571 572 - static int acpi_aml_read_user(char __user *buf, int len) 572 + static ssize_t acpi_aml_read_user(char __user *buf, size_t len) 573 573 { 574 - int ret; 575 574 struct circ_buf *crc = &acpi_aml_io.out_crc; 576 - int n; 575 + ssize_t ret; 576 + size_t n; 577 577 char *p; 578 578 579 579 ret = acpi_aml_lock_read(crc, ACPI_AML_OUT_USER); ··· 582 582 /* sync head before removing logs */ 583 583 smp_rmb(); 584 584 p = &crc->buf[crc->tail]; 585 - n = min(len, circ_count_to_end(crc)); 585 + n = min_t(size_t, len, circ_count_to_end(crc)); 586 586 if (copy_to_user(buf, p, n)) { 587 587 ret = -EFAULT; 588 588 goto out; ··· 599 599 static ssize_t acpi_aml_read(struct file *file, char __user *buf, 600 600 size_t count, loff_t *ppos) 601 601 { 602 - int ret = 0; 603 - int size = 0; 602 + ssize_t ret = 0; 603 + ssize_t size = 0; 604 604 605 605 if (!count) 606 606 return 0; ··· 639 639 return size > 0 ? size : ret; 640 640 } 641 641 642 - static int acpi_aml_write_user(const char __user *buf, int len) 642 + static ssize_t acpi_aml_write_user(const char __user *buf, size_t len) 643 643 { 644 - int ret; 645 644 struct circ_buf *crc = &acpi_aml_io.in_crc; 646 - int n; 645 + ssize_t ret; 646 + size_t n; 647 647 char *p; 648 648 649 649 ret = acpi_aml_lock_write(crc, ACPI_AML_IN_USER); ··· 652 652 /* sync tail before inserting cmds */ 653 653 smp_mb(); 654 654 p = &crc->buf[crc->head]; 655 - n = min(len, circ_space_to_end(crc)); 655 + n = min_t(size_t, len, circ_space_to_end(crc)); 656 656 if (copy_from_user(p, buf, n)) { 657 657 ret = -EFAULT; 658 658 goto out; ··· 663 663 ret = n; 664 664 out: 665 665 acpi_aml_unlock_fifo(ACPI_AML_IN_USER, ret >= 0); 666 - return n; 666 + return ret; 667 667 } 668 668 669 669 static ssize_t acpi_aml_write(struct file *file, const char __user *buf, 670 670 size_t count, loff_t *ppos) 671 671 { 672 - int ret = 0; 673 - int size = 0; 672 + ssize_t ret = 0; 673 + ssize_t size = 0; 674 674 675 675 if (!count) 676 676 return 0;