From nobody Sun Feb 8 08:44:39 2026 Received: from out-172.mta1.migadu.com (out-172.mta1.migadu.com [95.215.58.172]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id BDF03D2FF for ; Sun, 15 Sep 2024 02:09:40 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=95.215.58.172 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1726366183; cv=none; b=sqC0TWF1YSR4QYaKKt85REOBbZb2xFIobfiMEzKCOSt4d8qcwY2FJQeZOVCMVlR3xNgRb5jTHYqsh06GKcwci60HiL8z4RuotlBhibg1XleOjVlj2M2t+lMl1l/yXAWWm7qcW6Ffasa5/2b81OGA+bSc6RqYm15R7MU57UQaoqI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1726366183; c=relaxed/simple; bh=mNz6SJ0qIET1HZIfM2/2YEL+90Dv8kw5sh7UAsMhTOQ=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=UF3KKYj/1dJgsrVnvrMQ0BxmQ0sZ06xkY6AdWcOql4Tl/6NFi41AHbVceQEg/R3XhgtzaVnYyq0dZmSswXQCABZq9oAlISzN930Uy9wD1sCVaVfcN2IIseWVlOHFTe6tvTUiFnkzg9ImPKW/F1hRHVN5IwQbcQxj9X1i9S5uWek= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev; spf=pass smtp.mailfrom=linux.dev; dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev header.b=kOsP00wX; arc=none smtp.client-ip=95.215.58.172 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linux.dev Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev header.b="kOsP00wX" X-Report-Abuse: Please report any abuse attempt to abuse@migadu.com and include these headers. DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.dev; s=key1; t=1726366178; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=ljC/VBRr3GFRZnta2fsCZG7zwZAbaP9X3IzNuE/5UMY=; b=kOsP00wXsLWwMVpU9Gyfy7CBlD4aCOX28BlpIqXTfVWVyI58nJRSPzQBYpXCf79mdmiLk3 +oeHVeo2rU9trwA3eUBTBwm3R0NjvcgoyNGmZr+ZU9Ty6tdbKWvDhuYInGj/H8qJDVr1qZ ZaAZH4I3WO2Nj38/1zV1tw18u4UDVg4= From: Wen Yang To: "Eric W . Biederman" , Luis Chamberlain , Kees Cook , Joel Granados Cc: Christian Brauner , linux-kernel@vger.kernel.org, Wen Yang , Dave Young Subject: [PATCH v3 1/5] sysctl: add helper functions to extract table->extra1/extra2 Date: Sun, 15 Sep 2024 10:08:27 +0800 Message-Id: <364936c4a83abcddabb08504b4e26a7b92daef68.1726365007.git.wen.yang@linux.dev> In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Migadu-Flow: FLOW_OUT Content-Type: text/plain; charset="utf-8" Add some sysctl helper functions to avoid direct access to table->extra1/extra2. Signed-off-by: Wen Yang Cc: Luis Chamberlain Cc: Kees Cook Cc: Joel Granados Cc: Eric W. Biederman Cc: Christian Brauner Cc: Dave Young Cc: linux-kernel@vger.kernel.org --- fs/proc/proc_sysctl.c | 21 +++++++++------------ include/linux/sysctl.h | 40 ++++++++++++++++++++++++++++++++++++++++ kernel/sysctl.c | 20 ++++++++++---------- 3 files changed, 59 insertions(+), 22 deletions(-) diff --git a/fs/proc/proc_sysctl.c b/fs/proc/proc_sysctl.c index fac566065ed5..90c99eb1abf6 100644 --- a/fs/proc/proc_sysctl.c +++ b/fs/proc/proc_sysctl.c @@ -1115,18 +1115,15 @@ static int sysctl_check_table_array(const char *pat= h, const struct ctl_table *ta if (table->maxlen !=3D sizeof(u8)) err |=3D sysctl_err(path, table, "array not allowed"); =20 - if (table->extra1) { - extra =3D *(unsigned int *) table->extra1; - if (extra > 255U) - err |=3D sysctl_err(path, table, - "range value too large for proc_dou8vec_minmax"); - } - if (table->extra2) { - extra =3D *(unsigned int *) table->extra2; - if (extra > 255U) - err |=3D sysctl_err(path, table, - "range value too large for proc_dou8vec_minmax"); - } + extra =3D sysctl_range_min_u8(table); + if (extra > 255U) + err |=3D sysctl_err(path, table, + "range value too large for proc_dou8vec_minmax\n"); + + extra =3D sysctl_range_max_u8(table); + if (extra > 255U) + err |=3D sysctl_err(path, table, + "range value too large for proc_dou8vec_minmax\n"); } =20 if (table->proc_handler =3D=3D proc_dobool) { diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h index 202855befa8b..20e3914ec53f 100644 --- a/include/linux/sysctl.h +++ b/include/linux/sysctl.h @@ -212,6 +212,46 @@ struct ctl_table_root { #define register_sysctl(path, table) \ register_sysctl_sz(path, table, ARRAY_SIZE(table)) =20 +static inline unsigned int sysctl_range_min_u8(const struct ctl_table *tab= le) +{ + return (table->extra1) ? *(unsigned int *) table->extra1 : 0; +} + +static inline unsigned int sysctl_range_max_u8(const struct ctl_table *tab= le) +{ + return (table->extra2) ? *(unsigned int *) table->extra2 : U8_MAX; +} + +static inline int sysctl_range_min_int(const struct ctl_table *table) +{ + return (table->extra1) ? *(int *) table->extra1 : INT_MIN; +} + +static inline int sysctl_range_max_int(const struct ctl_table *table) +{ + return (table->extra2) ? *(int *) table->extra2 : INT_MAX; +} + +static inline unsigned int sysctl_range_min_uint(const struct ctl_table *t= able) +{ + return (table->extra1) ? *(unsigned int *) table->extra1 : 0; +} + +static inline unsigned int sysctl_range_max_uint(const struct ctl_table *t= able) +{ + return (table->extra2) ? *(unsigned int *) table->extra2 : UINT_MAX; +} + +static inline unsigned long sysctl_range_min_ulong(const struct ctl_table = *table) +{ + return (table->extra1) ? *(unsigned long *) table->extra1 : 0; +} + +static inline unsigned long sysctl_range_max_ulong(const struct ctl_table = *table) +{ + return (table->extra2) ? *(unsigned long *) table->extra2 : ULONG_MAX; +} + #ifdef CONFIG_SYSCTL =20 void proc_sys_poll_notify(struct ctl_table_poll *poll); diff --git a/kernel/sysctl.c b/kernel/sysctl.c index 92305cdbb94a..86de15638e31 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -869,8 +869,8 @@ int proc_dointvec_minmax(const struct ctl_table *table,= int write, { struct proc_minmax_conv_param param; =20 - param.min =3D (table->extra1) ? *(int *) table->extra1 : INT_MIN; - param.max =3D (table->extra2) ? *(int *) table->extra2 : INT_MAX; + param.min =3D sysctl_range_min_int(table); + param.max =3D sysctl_range_max_int(table); return do_proc_dointvec(table, write, buffer, lenp, ppos, do_proc_dointvec_minmax_conv, ¶m); } @@ -923,8 +923,8 @@ int proc_douintvec_minmax(const struct ctl_table *table= , int write, { struct proc_minmax_conv_param param; =20 - param.min =3D (table->extra1) ? *(unsigned int *) table->extra1 : 0; - param.max =3D (table->extra2) ? *(unsigned int *) table->extra2 : UINT_MA= X; + param.min =3D sysctl_range_min_uint(table); + param.max =3D sysctl_range_max_uint(table); return do_proc_douintvec(table, write, buffer, lenp, ppos, do_proc_douintvec_minmax_conv, ¶m); } @@ -959,8 +959,8 @@ int proc_dou8vec_minmax(const struct ctl_table *table, = int write, if (table->maxlen !=3D sizeof(u8)) return -EINVAL; =20 - param.min =3D (table->extra1) ? *(unsigned int *) table->extra1 : 0; - param.max =3D (table->extra2) ? *(unsigned int *) table->extra2 : 255U; + param.min =3D sysctl_range_min_u8(table); + param.max =3D sysctl_range_max_u8(table); tmp =3D *table; =20 tmp.maxlen =3D sizeof(val); @@ -1012,8 +1012,8 @@ static int __do_proc_doulongvec_minmax(void *data, } =20 i =3D data; - min =3D (table->extra1) ? *(unsigned long *) table->extra1 : 0; - max =3D (table->extra2) ? *(unsigned long *) table->extra2 : ULONG_MAX; + min =3D sysctl_range_min_ulong(table); + max =3D sysctl_range_max_ulong(table); =20 vleft =3D table->maxlen / sizeof(unsigned long); left =3D *lenp; @@ -1250,8 +1250,8 @@ int proc_dointvec_ms_jiffies_minmax(const struct ctl_= table *table, int write, { struct proc_minmax_conv_param param; =20 - param.min =3D (table->extra1) ? *(int *) table->extra1 : INT_MIN; - param.max =3D (table->extra2) ? *(int *) table->extra2 : INT_MAX; + param.min =3D sysctl_range_min_int(table); + param.max =3D sysctl_range_max_int(table); return do_proc_dointvec(table, write, buffer, lenp, ppos, do_proc_dointvec_ms_jiffies_minmax_conv, ¶m); } --=20 2.25.1 From nobody Sun Feb 8 08:44:39 2026 Received: from out-184.mta1.migadu.com (out-184.mta1.migadu.com [95.215.58.184]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 38FDAC13C for ; Sun, 15 Sep 2024 02:09:56 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=95.215.58.184 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1726366198; cv=none; b=tqBVfeg/Mx51eWpXGB80o1r4JYZbeEbwUJIIKghambMfMLEGMrWeizxp2n0WtiyX+mw5w+hsSqA5ddQCcCgrLOZRidqSCcr13XOAjXb/crRtfMFSuHpnPGBpdGJiHAcGlpVn6k6N4ry9CpHbK/DxQQR5pETZqWYsJ7ZR2V6l9LU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1726366198; c=relaxed/simple; bh=GavEkcXd9c3vz/G1j2NLzaxTPQ6ejVelOF6MbIHiY2E=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=HYJ7Gty3ScVi20ITkqZpDg1qlOGH9k+UDeXusKpv1HhujaANEfeGy3ReYTdljJCm/EtteOCF6NIcBYWu/nNVcDI95PeC0/SspXU4BrtSSQznfGYA/nCgr1HjbU9MFSfDRJumlzm5LbVqwtkrD7uQQe2ChoRWbgP35ZfshM24oY8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev; spf=pass smtp.mailfrom=linux.dev; dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev header.b=pI7NM/cB; arc=none smtp.client-ip=95.215.58.184 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linux.dev Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev header.b="pI7NM/cB" X-Report-Abuse: Please report any abuse attempt to abuse@migadu.com and include these headers. DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.dev; s=key1; t=1726366194; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=zPj8nhNA6eGz4EXLuhlodi7+Ono5En/R+NSw2UbBf8k=; b=pI7NM/cB05QlVPJh70cgWhaByM1J2SIfEka6mX4uxcc/w45p7AqSSeX/MtiNN4rBwnWVFs wBLjGaD1wPeCPDh8H0AkrS21rMNQxF3BqWTr9C5gsF7FYgHfvWo5I9Y835fWokiWWkcW6h F1UN9rkQeDuR0OR1ZiKQVl+m75VKo6I= From: Wen Yang To: "Eric W . Biederman" , Luis Chamberlain , Kees Cook , Joel Granados Cc: Christian Brauner , linux-kernel@vger.kernel.org, Wen Yang , Dave Young Subject: [PATCH v3 2/5] sysctl: support encoding values directly in the table entry Date: Sun, 15 Sep 2024 10:08:28 +0800 Message-Id: <95ca2bfb46a3aaef026623cd1a08c3c39366d5df.1726365007.git.wen.yang@linux.dev> In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Migadu-Flow: FLOW_OUT Content-Type: text/plain; charset="utf-8" Eric points out: "by turning .extra1 and .extra2 into longs instead of keeping them as pointers and needing constants to be pointed at somewhere .. The only people I can see who find a significant benefit by consolidating all of the constants into one place are people who know how to stomp kernel memory." This patch supports encoding values directly in table entries through the following work: - extra1/extra2 and min/max are placed in one union to ensure that the previous code is not broken, then we have time to gradually remove these unnecessary extra1/extra2; - two bits were used to represent the information of the above union: SYSCTL_FLAG_MIN: 0, using extra1. 1, using min. SYSCTL_FLAG_MAX: 0, using extra2. 1, using max. - since the proc file's mode field only uses 9 bits(777), we could use the additional two bits(S_ISUID and S_ISGID) to temporarily represent SYSCTL_FLAG_MIN and SYSCTL_FLAG_MAX. - added some helper macros. By introducing long min/max to replace void * extra1/extra2 in most cases, unnecessary variables can be removed to save memory and avoid attacks. Signed-off-by: Wen Yang Cc: Luis Chamberlain Cc: Kees Cook Cc: Joel Granados Cc: Eric W. Biederman Cc: Christian Brauner Cc: Dave Young Cc: linux-kernel@vger.kernel.org --- fs/proc/proc_sysctl.c | 8 +++-- include/linux/sysctl.h | 71 ++++++++++++++++++++++++++++++++++++------ 2 files changed, 67 insertions(+), 12 deletions(-) diff --git a/fs/proc/proc_sysctl.c b/fs/proc/proc_sysctl.c index 90c99eb1abf6..e88d1dca2a80 100644 --- a/fs/proc/proc_sysctl.c +++ b/fs/proc/proc_sysctl.c @@ -848,8 +848,11 @@ static int proc_sys_getattr(struct mnt_idmap *idmap, return PTR_ERR(head); =20 generic_fillattr(&nop_mnt_idmap, request_mask, inode, stat); - if (table) + if (table) { stat->mode =3D (stat->mode & S_IFMT) | table->mode; + stat->mode &=3D ~SYSCTL_FLAG_MIN; + stat->mode &=3D ~SYSCTL_FLAG_MAX; + } =20 sysctl_head_finish(head); return 0; @@ -1163,7 +1166,8 @@ static int sysctl_check_table(const char *path, struc= t ctl_table_header *header) if (!entry->proc_handler) err |=3D sysctl_err(path, entry, "No proc_handler"); =20 - if ((entry->mode & (S_IRUGO|S_IWUGO)) !=3D entry->mode) + if ((entry->mode & (S_IRUGO|S_IWUGO|SYSCTL_FLAG_MIN|SYSCTL_FLAG_MAX)) + !=3D entry->mode) err |=3D sysctl_err(path, entry, "bogus .mode 0%o", entry->mode); } diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h index 20e3914ec53f..8e27e8350ca8 100644 --- a/include/linux/sysctl.h +++ b/include/linux/sysctl.h @@ -28,6 +28,7 @@ #include #include #include +#include =20 /* For the /proc/sys support */ struct completion; @@ -61,6 +62,37 @@ extern const int sysctl_vals[]; =20 extern const unsigned long sysctl_long_vals[]; =20 +#define SYSCTL_NUM_ZERO (0L) +#define SYSCTL_NUM_ONE (1L) +#define SYSCTL_NUM_TWO (2L) +#define SYSCTL_NUM_THREE (3L) +#define SYSCTL_NUM_FOUR (4L) +#define SYSCTL_NUM_FIVE (5L) +#define SYSCTL_NUM_SIX (6L) +#define SYSCTL_NUM_SEVEN (7L) +#define SYSCTL_NUM_EIGHT (8L) +#define SYSCTL_NUM_NINE (9L) +#define SYSCTL_NUM_TEN (10L) +#define SYSCTL_NUM_SIXTEEN (16L) +#define SYSCTL_NUM_THIRTY_ONE (31L) +#define SYSCTL_NUM_NEG_THIRTY_ONE (-31L) +#define SYSCTL_NUM_ONE_HUNDRED (100L) +#define SYSCTL_NUM_TWO_HUNDRED (200L) +#define SYSCTL_NUM_S8_MAX (127L) +#define SYSCTL_NUM_U8_MAX (255L) +#define SYSCTL_NUM_FIVE_HUNDRED (500L) +#define SYSCTL_NUM_ONE_THOUSAND (1000L) +#define SYSCTL_NUM_THREE_THOUSAND (3000L) +#define SYSCTL_NUM_16K (16 * 1024L) +#define SYSCTL_NUM_16M (16 * 1024 * 1024L) +#define SYSCTL_NUM_SEC_PER_HOUR (60 * 60L) +#define SYSCTL_NUM_U16_MAX (65535L) +#define SYSCTL_NUM_SEC_PER_DAY (24 * 60 * 60L) +#define SYSCTL_NUM_MS_PER_DAY (24 * 60 * 60 * 1000L) +#define SYSCTL_NUM_INT_MAX (INT_MAX) +#define SYSCTL_NUM_NEG_ONE (-1) +#define SYSCTL_NUM_LONG_MAX (LONG_MAX) + typedef int proc_handler(const struct ctl_table *ctl, int write, void *buf= fer, size_t *lenp, loff_t *ppos); =20 @@ -131,6 +163,9 @@ static inline void *proc_sys_poll_event(struct ctl_tabl= e_poll *poll) #define DEFINE_CTL_TABLE_POLL(name) \ struct ctl_table_poll name =3D __CTL_TABLE_POLL_INITIALIZER(name) =20 +#define SYSCTL_FLAG_MIN S_ISUID +#define SYSCTL_FLAG_MAX S_ISGID + /* A sysctl table is an array of struct ctl_table: */ struct ctl_table { const char *procname; /* Text ID for /proc/sys, or zero */ @@ -139,8 +174,16 @@ struct ctl_table { umode_t mode; proc_handler *proc_handler; /* Callback for text formatting */ struct ctl_table_poll *poll; - void *extra1; - void *extra2; + union { + struct { + void *extra1; + void *extra2; + }; + struct { + long min; + long max; + }; + }; } __randomize_layout; =20 struct ctl_node { @@ -214,42 +257,50 @@ struct ctl_table_root { =20 static inline unsigned int sysctl_range_min_u8(const struct ctl_table *tab= le) { - return (table->extra1) ? *(unsigned int *) table->extra1 : 0; + return (table->mode & SYSCTL_FLAG_MIN) ? table->min : + (table->extra1) ? *(unsigned int *) table->extra1 : 0; } =20 static inline unsigned int sysctl_range_max_u8(const struct ctl_table *tab= le) { - return (table->extra2) ? *(unsigned int *) table->extra2 : U8_MAX; + return (table->mode & SYSCTL_FLAG_MAX) ? table->max : + (table->extra2) ? *(unsigned int *) table->extra2 : U8_MAX; } =20 static inline int sysctl_range_min_int(const struct ctl_table *table) { - return (table->extra1) ? *(int *) table->extra1 : INT_MIN; + return (table->mode & SYSCTL_FLAG_MIN) ? table->min : + (table->extra1) ? *(int *) table->extra1 : INT_MIN; } =20 static inline int sysctl_range_max_int(const struct ctl_table *table) { - return (table->extra2) ? *(int *) table->extra2 : INT_MAX; + return (table->mode & SYSCTL_FLAG_MAX) ? table->max : + (table->extra2) ? *(int *) table->extra2 : INT_MAX; } =20 static inline unsigned int sysctl_range_min_uint(const struct ctl_table *t= able) { - return (table->extra1) ? *(unsigned int *) table->extra1 : 0; + return (table->mode & SYSCTL_FLAG_MIN) ? table->min : + (table->extra1) ? *(unsigned int *) table->extra1 : 0; } =20 static inline unsigned int sysctl_range_max_uint(const struct ctl_table *t= able) { - return (table->extra2) ? *(unsigned int *) table->extra2 : UINT_MAX; + return (table->mode & SYSCTL_FLAG_MAX) ? table->max : + (table->extra2) ? *(unsigned int *) table->extra2 : UINT_MAX; } =20 static inline unsigned long sysctl_range_min_ulong(const struct ctl_table = *table) { - return (table->extra1) ? *(unsigned long *) table->extra1 : 0; + return (table->mode & SYSCTL_FLAG_MIN) ? table->min : + (table->extra1) ? *(unsigned long *) table->extra1 : 0; } =20 static inline unsigned long sysctl_range_max_ulong(const struct ctl_table = *table) { - return (table->extra2) ? *(unsigned long *) table->extra2 : ULONG_MAX; + return (table->mode & SYSCTL_FLAG_MAX) ? table->max : + (table->extra2) ? *(unsigned long *) table->extra2 : ULONG_MAX; } =20 #ifdef CONFIG_SYSCTL --=20 2.25.1 From nobody Sun Feb 8 08:44:39 2026 Received: from out-171.mta1.migadu.com (out-171.mta1.migadu.com [95.215.58.171]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 3BDCDF9DA for ; Sun, 15 Sep 2024 02:10:09 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=95.215.58.171 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1726366211; cv=none; b=qAbhdladeIWPnH9QTkAqloGuP8B9+OKnj6+I+mXqdVFUlyyRr+aWpyyw9wNYTqunVAJsLCNZlN7e0cHwqQATugTLnWIWa2+Wv6B8eD/Ld36bebGuxcUVX22OYC0DMtZfS/A+8uLYwUq5NL6g547i+K71dktPcNhil23uhqpUI3o= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1726366211; c=relaxed/simple; bh=mx8S/PMGmEyP25ULKHhQjaUHnwckKKHa6YPwW0XZ1FU=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=eY0q9zExAiIbKrvtkgWBRIi5M245jcV4CtR0BIPU1g1JgNxFx148o/ExoS17fndLSiDiro6YUp1uHopVkZlyS4kUiyC7YjBmgy9J5GCj779eRLB18CvlMfkrpz491qZFiA/dL2MdE40s+BpU1kxngOrMwfTV7d2JqrVoroN59Bs= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev; spf=pass smtp.mailfrom=linux.dev; dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev header.b=v2UUO4tU; arc=none smtp.client-ip=95.215.58.171 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linux.dev Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev header.b="v2UUO4tU" X-Report-Abuse: Please report any abuse attempt to abuse@migadu.com and include these headers. DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.dev; s=key1; t=1726366207; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=eKhBMD9KZww0WhZ8G5CO8zfEECOwnyicqnrjfVKl/jc=; b=v2UUO4tU4QeFhBPBxYZUi63Uure6JD/4HAjTmli8gAYygw32sYnTkO9S6g3rhB4GG8S8mW eLMeNb4/pry4YJF2i9uRL8mLgDPsucmDchTS/dvPWhnchrhgAhcwx3RY9tX5Ywdb0x9c3E zIfKwYST5hFr+rpLjCpW7eGYPQ2DVgI= From: Wen Yang To: "Eric W . Biederman" , Luis Chamberlain , Kees Cook , Joel Granados Cc: Christian Brauner , linux-kernel@vger.kernel.org, Wen Yang , Dave Young Subject: [PATCH v3 3/5] sysctl: add KUnit test code to check for encoding min/max in table entries Date: Sun, 15 Sep 2024 10:08:29 +0800 Message-Id: <988454b2c7705283811c0bd70bfbf80052860479.1726365007.git.wen.yang@linux.dev> In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Migadu-Flow: FLOW_OUT Content-Type: text/plain; charset="utf-8" Add KUnit test code to check the impact of encoding the min/max values directly in table entries on functions such as proc_rointvec, proc_rou8vectminmax, proc_rouintvectminmax, and proc_roulongvectminmax, including basic parsing testing and min/max overflow testing. Signed-off-by: Wen Yang Cc: Luis Chamberlain Cc: Kees Cook Cc: Joel Granados Cc: Eric W. Biederman Cc: Christian Brauner Cc: Dave Young Cc: linux-kernel@vger.kernel.org --- kernel/sysctl-test.c | 581 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 581 insertions(+) diff --git a/kernel/sysctl-test.c b/kernel/sysctl-test.c index 3ac98bb7fb82..486240787103 100644 --- a/kernel/sysctl-test.c +++ b/kernel/sysctl-test.c @@ -415,6 +415,575 @@ static void sysctl_test_register_sysctl_sz_invalid_ex= tra_value( KUNIT_EXPECT_NOT_NULL(test, register_sysctl("foo", table_qux)); } =20 +static void sysctl_test_api_dointvec_write_with_minmax( + struct kunit *test) +{ + int data =3D 0; + struct ctl_table table =3D { + .procname =3D "foo", + .data =3D &data, + .maxlen =3D sizeof(int), + .mode =3D 0644 | SYSCTL_FLAG_MIN | SYSCTL_FLAG_MAX, + .proc_handler =3D proc_dointvec_minmax, + .min =3D SYSCTL_NUM_NEG_ONE, + .max =3D SYSCTL_NUM_ONE_HUNDRED, + }; + size_t max_len =3D 32, len =3D max_len; + loff_t pos =3D 0; + char *buffer =3D kunit_kzalloc(test, max_len, GFP_USER); + char __user *user_buffer =3D (char __user *)buffer; + char input1[] =3D "10"; + char input2[] =3D "-5"; + char input3[] =3D "200"; + + // test for input1 + len =3D sizeof(input1) - 1; + memcpy(buffer, input1, len); + KUNIT_EXPECT_EQ(test, 0, proc_dointvec_minmax(&table, KUNIT_PROC_WRITE, + user_buffer, &len, &pos)); + KUNIT_EXPECT_EQ(test, sizeof(input1) - 1, len); + KUNIT_EXPECT_EQ(test, 10, *((int *)table.data)); + + // test for input2 + len =3D sizeof(input2) - 1; + pos =3D 0; + memcpy(buffer, input2, len); + KUNIT_EXPECT_EQ(test, -EINVAL, proc_dointvec_minmax(&table, KUNIT_PROC_WR= ITE, + user_buffer, &len, &pos)); + KUNIT_EXPECT_EQ(test, 0, pos); + KUNIT_EXPECT_EQ(test, 10, *((int *)table.data)); + + // test for input3 + len =3D sizeof(input3) - 1; + pos =3D 0; + memcpy(buffer, input3, len); + KUNIT_EXPECT_EQ(test, -EINVAL, proc_dointvec_minmax(&table, KUNIT_PROC_WR= ITE, + user_buffer, &len, &pos)); + KUNIT_EXPECT_EQ(test, 0, pos); + KUNIT_EXPECT_EQ(test, 10, *((int *)table.data)); +} + +static void sysctl_test_api_dointvec_write_with_min( + struct kunit *test) +{ + int data =3D 0; + struct ctl_table table =3D { + .procname =3D "foo", + .data =3D &data, + .maxlen =3D sizeof(int), + .mode =3D 0644 | SYSCTL_FLAG_MIN, + .proc_handler =3D proc_dointvec_minmax, + .min =3D SYSCTL_NUM_NEG_ONE, + }; + size_t max_len =3D 32, len =3D max_len; + loff_t pos =3D 0; + char *buffer =3D kunit_kzalloc(test, max_len, GFP_USER); + char __user *user_buffer =3D (char __user *)buffer; + char input1[] =3D "10"; + char input2[] =3D "-5"; + char input3[] =3D "2147483647"; + + // test for input1 + len =3D sizeof(input1) - 1; + memcpy(buffer, input1, len); + KUNIT_EXPECT_EQ(test, 0, proc_dointvec_minmax(&table, KUNIT_PROC_WRITE, + user_buffer, &len, &pos)); + KUNIT_EXPECT_EQ(test, sizeof(input1) - 1, len); + KUNIT_EXPECT_EQ(test, 10, *((int *)table.data)); + + // test for input2 + len =3D sizeof(input2) - 1; + pos =3D 0; + memcpy(buffer, input2, len); + KUNIT_EXPECT_EQ(test, -EINVAL, proc_dointvec_minmax(&table, KUNIT_PROC_WR= ITE, + user_buffer, &len, &pos)); + KUNIT_EXPECT_EQ(test, 0, pos); + KUNIT_EXPECT_EQ(test, 10, *((int *)table.data)); + + // test for input3 + len =3D sizeof(input3) - 1; + pos =3D 0; + memcpy(buffer, input3, len); + KUNIT_EXPECT_EQ(test, 0, proc_dointvec_minmax(&table, KUNIT_PROC_WRITE, + user_buffer, &len, &pos)); + KUNIT_EXPECT_EQ(test, sizeof(input3) - 1, len); + KUNIT_EXPECT_EQ(test, 2147483647, *((int *)table.data)); +} + +static void sysctl_test_api_dointvec_write_with_max( + struct kunit *test) +{ + int data =3D 0; + struct ctl_table table =3D { + .procname =3D "foo", + .data =3D &data, + .maxlen =3D sizeof(int), + .mode =3D 0644 | SYSCTL_FLAG_MAX, + .proc_handler =3D proc_dointvec_minmax, + .max =3D SYSCTL_NUM_ONE_HUNDRED, + }; + size_t max_len =3D 32, len =3D max_len; + loff_t pos =3D 0; + char *buffer =3D kunit_kzalloc(test, max_len, GFP_USER); + char __user *user_buffer =3D (char __user *)buffer; + char input1[] =3D "10"; + char input2[] =3D "2147483647"; + char input3[] =3D "-2147483648"; + + // test for input1 + len =3D sizeof(input1) - 1; + memcpy(buffer, input1, len); + KUNIT_EXPECT_EQ(test, 0, proc_dointvec_minmax(&table, KUNIT_PROC_WRITE, + user_buffer, &len, &pos)); + KUNIT_EXPECT_EQ(test, sizeof(input1) - 1, len); + KUNIT_EXPECT_EQ(test, 10, *((int *)table.data)); + + // test for input2 + len =3D sizeof(input2) - 1; + pos =3D 0; + memcpy(buffer, input2, len); + KUNIT_EXPECT_EQ(test, -EINVAL, proc_dointvec_minmax(&table, KUNIT_PROC_WR= ITE, + user_buffer, &len, &pos)); + KUNIT_EXPECT_EQ(test, 0, pos); + KUNIT_EXPECT_EQ(test, 10, *((int *)table.data)); + + // test for input3 + len =3D sizeof(input3) - 1; + pos =3D 0; + memcpy(buffer, input3, len); + KUNIT_EXPECT_EQ(test, 0, proc_dointvec_minmax(&table, KUNIT_PROC_WRITE, + user_buffer, &len, &pos)); + KUNIT_EXPECT_EQ(test, sizeof(input3) - 1, len); + KUNIT_EXPECT_EQ(test, -2147483648, *((int *)table.data)); +} + +static void sysctl_test_api_douintvec_write_with_minmax( + struct kunit *test) +{ + unsigned int data =3D 0; + struct ctl_table table =3D { + .procname =3D "foo", + .data =3D &data, + .maxlen =3D sizeof(int), + .mode =3D 0644 | SYSCTL_FLAG_MIN | SYSCTL_FLAG_MAX, + .proc_handler =3D proc_douintvec_minmax, + .min =3D SYSCTL_NUM_FOUR, + .max =3D SYSCTL_NUM_TWO_HUNDRED, + }; + size_t max_len =3D 32, len =3D max_len; + loff_t pos =3D 0; + char *buffer =3D kunit_kzalloc(test, max_len, GFP_USER); + char __user *user_buffer =3D (char __user *)buffer; + char input1[] =3D "100"; + char input2[] =3D "3"; + char input3[] =3D "1000"; + + // test for input1 + len =3D sizeof(input1) - 1; + memcpy(buffer, input1, len); + KUNIT_EXPECT_EQ(test, 0, proc_douintvec_minmax(&table, KUNIT_PROC_WRITE, + user_buffer, &len, &pos)); + KUNIT_EXPECT_EQ(test, sizeof(input1) - 1, len); + KUNIT_EXPECT_EQ(test, 100, *((unsigned int *)table.data)); + + // test for input2 + len =3D sizeof(input2) - 1; + pos =3D 0; + memcpy(buffer, input2, len); + KUNIT_EXPECT_EQ(test, -EINVAL, proc_douintvec_minmax(&table, KUNIT_PROC_W= RITE, + user_buffer, &len, &pos)); + KUNIT_EXPECT_EQ(test, 0, pos); + KUNIT_EXPECT_EQ(test, 100, *((unsigned int *)table.data)); + + // test for input3 + len =3D sizeof(input3) - 1; + pos =3D 0; + memcpy(buffer, input3, len); + KUNIT_EXPECT_EQ(test, -EINVAL, proc_douintvec_minmax(&table, KUNIT_PROC_W= RITE, + user_buffer, &len, &pos)); + KUNIT_EXPECT_EQ(test, 0, pos); + KUNIT_EXPECT_EQ(test, 100, *((unsigned int *)table.data)); +} + +static void sysctl_test_api_douintvec_write_with_min( + struct kunit *test) +{ + unsigned int data =3D 0; + struct ctl_table table =3D { + .procname =3D "foo", + .data =3D &data, + .maxlen =3D sizeof(int), + .mode =3D 0644 | SYSCTL_FLAG_MIN, + .proc_handler =3D proc_douintvec_minmax, + .min =3D SYSCTL_NUM_FOUR, + }; + size_t max_len =3D 32, len =3D max_len; + loff_t pos =3D 0; + char *buffer =3D kunit_kzalloc(test, max_len, GFP_USER); + char __user *user_buffer =3D (char __user *)buffer; + char input1[] =3D "100"; + char input2[] =3D "3"; + char input3[] =3D "4294967295"; + + // test for input1 + len =3D sizeof(input1) - 1; + memcpy(buffer, input1, len); + KUNIT_EXPECT_EQ(test, 0, proc_douintvec_minmax(&table, KUNIT_PROC_WRITE, + user_buffer, &len, &pos)); + KUNIT_EXPECT_EQ(test, sizeof(input1) - 1, len); + KUNIT_EXPECT_EQ(test, 100, *((unsigned int *)table.data)); + + // test for input2 + len =3D sizeof(input2) - 1; + pos =3D 0; + memcpy(buffer, input2, len); + KUNIT_EXPECT_EQ(test, -EINVAL, proc_douintvec_minmax(&table, KUNIT_PROC_W= RITE, + user_buffer, &len, &pos)); + KUNIT_EXPECT_EQ(test, 0, pos); + KUNIT_EXPECT_EQ(test, 100, *((unsigned int *)table.data)); + + // test for input3 + len =3D sizeof(input3) - 1; + pos =3D 0; + memcpy(buffer, input3, len); + KUNIT_EXPECT_EQ(test, 0, proc_douintvec_minmax(&table, KUNIT_PROC_WRITE, + user_buffer, &len, &pos)); + KUNIT_EXPECT_EQ(test, sizeof(input3) - 1, len); + KUNIT_EXPECT_EQ(test, 4294967295, *((unsigned int *)table.data)); +} + +static void sysctl_test_api_douintvec_write_with_max( + struct kunit *test) +{ + unsigned int data =3D 0; + struct ctl_table table =3D { + .procname =3D "foo", + .data =3D &data, + .maxlen =3D sizeof(int), + .mode =3D 0644 | SYSCTL_FLAG_MAX, + .proc_handler =3D proc_douintvec_minmax, + .max =3D SYSCTL_NUM_ONE_THOUSAND, + }; + size_t max_len =3D 32, len =3D max_len; + loff_t pos =3D 0; + char *buffer =3D kunit_kzalloc(test, max_len, GFP_USER); + char __user *user_buffer =3D (char __user *)buffer; + char input1[] =3D "900"; + char input2[] =3D "10000"; + char input3[] =3D "0"; + + // test for input1 + len =3D sizeof(input1) - 1; + memcpy(buffer, input1, len); + KUNIT_EXPECT_EQ(test, 0, proc_douintvec_minmax(&table, KUNIT_PROC_WRITE, + user_buffer, &len, &pos)); + KUNIT_EXPECT_EQ(test, sizeof(input1) - 1, len); + KUNIT_EXPECT_EQ(test, 900, *((unsigned int *)table.data)); + + // test for input2 + len =3D sizeof(input2) - 1; + pos =3D 0; + memcpy(buffer, input2, len); + KUNIT_EXPECT_EQ(test, -EINVAL, proc_douintvec_minmax(&table, KUNIT_PROC_W= RITE, + user_buffer, &len, &pos)); + KUNIT_EXPECT_EQ(test, 0, pos); + KUNIT_EXPECT_EQ(test, 900, *((unsigned int *)table.data)); + + // test for input3 + len =3D sizeof(input3) - 1; + pos =3D 0; + memcpy(buffer, input3, len); + KUNIT_EXPECT_EQ(test, 0, proc_douintvec_minmax(&table, KUNIT_PROC_WRITE, + user_buffer, &len, &pos)); + KUNIT_EXPECT_EQ(test, sizeof(input3) - 1, len); + KUNIT_EXPECT_EQ(test, 0, *((unsigned int *)table.data)); +} + +static void sysctl_test_api_dou8vec_write_with_minmax( + struct kunit *test) +{ + unsigned char data =3D 0; + struct ctl_table table =3D { + .procname =3D "foo", + .data =3D &data, + .maxlen =3D sizeof(unsigned char), + .mode =3D 0644 | SYSCTL_FLAG_MIN | SYSCTL_FLAG_MAX, + .proc_handler =3D proc_dou8vec_minmax, + .min =3D SYSCTL_NUM_THREE, + .max =3D SYSCTL_NUM_ONE_HUNDRED, + }; + size_t max_len =3D 8, len =3D max_len; + loff_t pos =3D 0; + char *buffer =3D kunit_kzalloc(test, max_len, GFP_USER); + char __user *user_buffer =3D (char __user *)buffer; + char input1[] =3D "32"; + char input2[] =3D "1"; + char input3[] =3D "200"; + + // test for input1 + len =3D sizeof(input1) - 1; + memcpy(buffer, input1, len); + KUNIT_EXPECT_EQ(test, 0, proc_dou8vec_minmax(&table, KUNIT_PROC_WRITE, + user_buffer, &len, &pos)); + KUNIT_EXPECT_EQ(test, sizeof(input1) - 1, len); + KUNIT_EXPECT_EQ(test, 32, *((unsigned char *)table.data)); + + // test for input2 + len =3D sizeof(input2) - 1; + pos =3D 0; + memcpy(buffer, input2, len); + KUNIT_EXPECT_EQ(test, -EINVAL, proc_dou8vec_minmax(&table, KUNIT_PROC_WRI= TE, + user_buffer, &len, &pos)); + KUNIT_EXPECT_EQ(test, 0, pos); + KUNIT_EXPECT_EQ(test, 32, *((unsigned char *)table.data)); + + // test for input3 + len =3D sizeof(input3) - 1; + pos =3D 0; + memcpy(buffer, input3, len); + KUNIT_EXPECT_EQ(test, -EINVAL, proc_dou8vec_minmax(&table, KUNIT_PROC_WRI= TE, + user_buffer, &len, &pos)); + KUNIT_EXPECT_EQ(test, 0, pos); + KUNIT_EXPECT_EQ(test, 32, *((unsigned char *)table.data)); +} + +static void sysctl_test_api_dou8vec_write_with_min( + struct kunit *test) +{ + unsigned char data =3D 0; + struct ctl_table table =3D { + .procname =3D "foo", + .data =3D &data, + .maxlen =3D sizeof(unsigned char), + .mode =3D 0644 | SYSCTL_FLAG_MIN, + .proc_handler =3D proc_dou8vec_minmax, + .min =3D SYSCTL_NUM_THREE, + }; + size_t max_len =3D 8, len =3D max_len; + loff_t pos =3D 0; + char *buffer =3D kunit_kzalloc(test, max_len, GFP_USER); + char __user *user_buffer =3D (char __user *)buffer; + char input1[] =3D "32"; + char input2[] =3D "1"; + char input3[] =3D "255"; + + // test for input1 + len =3D sizeof(input1) - 1; + memcpy(buffer, input1, len); + KUNIT_EXPECT_EQ(test, 0, proc_dou8vec_minmax(&table, KUNIT_PROC_WRITE, + user_buffer, &len, &pos)); + KUNIT_EXPECT_EQ(test, sizeof(input1) - 1, len); + KUNIT_EXPECT_EQ(test, 32, *((unsigned char *)table.data)); + + // test for input2 + len =3D sizeof(input2) - 1; + pos =3D 0; + memcpy(buffer, input2, len); + KUNIT_EXPECT_EQ(test, -EINVAL, proc_dou8vec_minmax(&table, KUNIT_PROC_WRI= TE, + user_buffer, &len, &pos)); + KUNIT_EXPECT_EQ(test, 0, pos); + KUNIT_EXPECT_EQ(test, 32, *((unsigned char *)table.data)); + + // test for input3 + len =3D sizeof(input3) - 1; + pos =3D 0; + memcpy(buffer, input3, len); + KUNIT_EXPECT_EQ(test, 0, proc_dou8vec_minmax(&table, KUNIT_PROC_WRITE, + user_buffer, &len, &pos)); + KUNIT_EXPECT_EQ(test, sizeof(input3) - 1, len); + KUNIT_EXPECT_EQ(test, 255, *((unsigned char *)table.data)); +} + +static void sysctl_test_api_dou8vec_write_with_max( + struct kunit *test) +{ + unsigned char data =3D 0; + struct ctl_table table =3D { + .procname =3D "foo", + .data =3D &data, + .maxlen =3D sizeof(unsigned char), + .mode =3D 0644 | SYSCTL_FLAG_MAX, + .proc_handler =3D proc_dou8vec_minmax, + .max =3D SYSCTL_NUM_TWO_HUNDRED, + }; + size_t max_len =3D 8, len =3D max_len; + loff_t pos =3D 0; + char *buffer =3D kunit_kzalloc(test, max_len, GFP_USER); + char __user *user_buffer =3D (char __user *)buffer; + char input1[] =3D "32"; + char input2[] =3D "0"; + char input3[] =3D "255"; + + // test for input1 + len =3D sizeof(input1) - 1; + memcpy(buffer, input1, len); + KUNIT_EXPECT_EQ(test, 0, proc_dou8vec_minmax(&table, KUNIT_PROC_WRITE, + user_buffer, &len, &pos)); + KUNIT_EXPECT_EQ(test, sizeof(input1) - 1, len); + KUNIT_EXPECT_EQ(test, 32, *((unsigned char *)table.data)); + + // test for input2 + len =3D sizeof(input2) - 1; + pos =3D 0; + memcpy(buffer, input2, len); + KUNIT_EXPECT_EQ(test, 0, proc_dou8vec_minmax(&table, KUNIT_PROC_WRITE, + user_buffer, &len, &pos)); + KUNIT_EXPECT_EQ(test, sizeof(input2) - 1, len); + KUNIT_EXPECT_EQ(test, 0, *((unsigned char *)table.data)); + + // test for input3 + len =3D sizeof(input3) - 1; + pos =3D 0; + memcpy(buffer, input3, len); + KUNIT_EXPECT_EQ(test, -EINVAL, proc_dou8vec_minmax(&table, KUNIT_PROC_WRI= TE, + user_buffer, &len, &pos)); + KUNIT_EXPECT_EQ(test, 0, pos); + KUNIT_EXPECT_EQ(test, 0, *((unsigned char *)table.data)); +} + +static void sysctl_test_api_doulongvec_write_with_minmax( + struct kunit *test) +{ + unsigned long data =3D 0; + struct ctl_table table =3D { + .procname =3D "foo", + .data =3D &data, + .maxlen =3D sizeof(unsigned long), + .mode =3D 0644 | SYSCTL_FLAG_MIN | SYSCTL_FLAG_MAX, + .proc_handler =3D proc_doulongvec_minmax, + .min =3D SYSCTL_NUM_ONE_THOUSAND, + .max =3D SYSCTL_NUM_THREE_THOUSAND, + }; + size_t max_len =3D 64, len =3D max_len; + loff_t pos =3D 0; + char *buffer =3D kunit_kzalloc(test, max_len, GFP_USER); + char __user *user_buffer =3D (char __user *)buffer; + char input1[] =3D "1024"; + char input2[] =3D "100"; + char input3[] =3D "4096"; + + // test for input1 + len =3D sizeof(input1) - 1; + memcpy(buffer, input1, len); + KUNIT_EXPECT_EQ(test, 0, proc_doulongvec_minmax(&table, KUNIT_PROC_WRITE, + user_buffer, &len, &pos)); + KUNIT_EXPECT_EQ(test, sizeof(input1) - 1, len); + KUNIT_EXPECT_EQ(test, 1024, *((unsigned long *)table.data)); + + // test for input2 + len =3D sizeof(input2) - 1; + pos =3D 0; + memcpy(buffer, input2, len); + KUNIT_EXPECT_EQ(test, -EINVAL, proc_doulongvec_minmax(&table, KUNIT_PROC_= WRITE, + user_buffer, &len, &pos)); + KUNIT_EXPECT_EQ(test, 0, pos); + KUNIT_EXPECT_EQ(test, 1024, *((unsigned long *)table.data)); + + // test for input3 + len =3D sizeof(input3) - 1; + pos =3D 0; + memcpy(buffer, input3, len); + KUNIT_EXPECT_EQ(test, -EINVAL, proc_doulongvec_minmax(&table, KUNIT_PROC_= WRITE, + user_buffer, &len, &pos)); + KUNIT_EXPECT_EQ(test, 0, pos); + KUNIT_EXPECT_EQ(test, 1024, *((unsigned long *)table.data)); +} + +static void sysctl_test_api_doulongvec_write_with_min( + struct kunit *test) +{ + unsigned long data =3D 0; + struct ctl_table table =3D { + .procname =3D "foo", + .data =3D &data, + .maxlen =3D sizeof(unsigned long), + .mode =3D 0644 | SYSCTL_FLAG_MIN, + .proc_handler =3D proc_doulongvec_minmax, + .min =3D SYSCTL_NUM_ONE_THOUSAND, + }; + size_t max_len =3D 64, len =3D max_len; + loff_t pos =3D 0; + char *buffer =3D kunit_kzalloc(test, max_len, GFP_USER); + char __user *user_buffer =3D (char __user *)buffer; + char input1[] =3D "1000"; + char input2[] =3D "10"; + char input3[64] =3D {0}; + + // test for input1 + len =3D sizeof(input1) - 1; + memcpy(buffer, input1, len); + KUNIT_EXPECT_EQ(test, 0, proc_doulongvec_minmax(&table, KUNIT_PROC_WRITE, + user_buffer, &len, &pos)); + KUNIT_EXPECT_EQ(test, sizeof(input1) - 1, len); + KUNIT_EXPECT_EQ(test, 1000, *((unsigned long *)table.data)); + + // test for input2 + len =3D sizeof(input2) - 1; + pos =3D 0; + memcpy(buffer, input2, len); + KUNIT_EXPECT_EQ(test, -EINVAL, proc_doulongvec_minmax(&table, KUNIT_PROC_= WRITE, + user_buffer, &len, &pos)); + KUNIT_EXPECT_EQ(test, 0, pos); + KUNIT_EXPECT_EQ(test, 1000, *((unsigned long *)table.data)); + + // test for input3 + snprintf(input3, sizeof(input3), "%lu", ULONG_MAX); + len =3D strlen(input3); + pos =3D 0; + memcpy(buffer, input3, len); + KUNIT_EXPECT_EQ(test, 0, proc_doulongvec_minmax(&table, KUNIT_PROC_WRITE, + user_buffer, &len, &pos)); + KUNIT_EXPECT_EQ(test, strlen(input3), len); + KUNIT_EXPECT_EQ(test, ULONG_MAX, *((unsigned long *)table.data)); +} + +static void sysctl_test_api_doulongvec_write_with_max( + struct kunit *test) +{ + unsigned long data =3D 0; + struct ctl_table table =3D { + .procname =3D "foo", + .data =3D &data, + .maxlen =3D sizeof(unsigned long), + .mode =3D 0644 | SYSCTL_FLAG_MAX, + .proc_handler =3D proc_doulongvec_minmax, + .max =3D SYSCTL_NUM_THREE_THOUSAND, + }; + size_t max_len =3D 64, len =3D max_len; + loff_t pos =3D 0; + char *buffer =3D kunit_kzalloc(test, max_len, GFP_USER); + char __user *user_buffer =3D (char __user *)buffer; + char input1[] =3D "1024"; + char input2[] =3D "4096"; + char input3[] =3D "0"; + + // test for input1 + len =3D sizeof(input1) - 1; + memcpy(buffer, input1, len); + KUNIT_EXPECT_EQ(test, 0, proc_doulongvec_minmax(&table, KUNIT_PROC_WRITE, + user_buffer, &len, &pos)); + KUNIT_EXPECT_EQ(test, sizeof(input1) - 1, len); + KUNIT_EXPECT_EQ(test, 1024, *((unsigned long *)table.data)); + + // test for input2 + len =3D sizeof(input2) - 1; + pos =3D 0; + memcpy(buffer, input2, len); + KUNIT_EXPECT_EQ(test, -EINVAL, proc_doulongvec_minmax(&table, KUNIT_PROC_= WRITE, + user_buffer, &len, &pos)); + KUNIT_EXPECT_EQ(test, 0, pos); + KUNIT_EXPECT_EQ(test, 1024, *((unsigned long *)table.data)); + + // test for input3 + len =3D sizeof(input3) - 1; + pos =3D 0; + memcpy(buffer, input3, len); + KUNIT_EXPECT_EQ(test, 0, proc_doulongvec_minmax(&table, KUNIT_PROC_WRITE, + user_buffer, &len, &pos)); + KUNIT_EXPECT_EQ(test, sizeof(input3) - 1, len); + KUNIT_EXPECT_EQ(test, 0, *((unsigned long *)table.data)); +} + static struct kunit_case sysctl_test_cases[] =3D { KUNIT_CASE(sysctl_test_api_dointvec_null_tbl_data), KUNIT_CASE(sysctl_test_api_dointvec_table_maxlen_unset), @@ -427,6 +996,18 @@ static struct kunit_case sysctl_test_cases[] =3D { KUNIT_CASE(sysctl_test_api_dointvec_write_single_less_int_min), KUNIT_CASE(sysctl_test_api_dointvec_write_single_greater_int_max), KUNIT_CASE(sysctl_test_register_sysctl_sz_invalid_extra_value), + KUNIT_CASE(sysctl_test_api_dointvec_write_with_minmax), + KUNIT_CASE(sysctl_test_api_dointvec_write_with_min), + KUNIT_CASE(sysctl_test_api_dointvec_write_with_max), + KUNIT_CASE(sysctl_test_api_douintvec_write_with_minmax), + KUNIT_CASE(sysctl_test_api_douintvec_write_with_min), + KUNIT_CASE(sysctl_test_api_douintvec_write_with_max), + KUNIT_CASE(sysctl_test_api_dou8vec_write_with_minmax), + KUNIT_CASE(sysctl_test_api_dou8vec_write_with_min), + KUNIT_CASE(sysctl_test_api_dou8vec_write_with_max), + KUNIT_CASE(sysctl_test_api_doulongvec_write_with_minmax), + KUNIT_CASE(sysctl_test_api_doulongvec_write_with_min), + KUNIT_CASE(sysctl_test_api_doulongvec_write_with_max), {} }; =20 --=20 2.25.1 From nobody Sun Feb 8 08:44:39 2026 Received: from out-181.mta1.migadu.com (out-181.mta1.migadu.com [95.215.58.181]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 70F879460 for ; Sun, 15 Sep 2024 02:10:19 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=95.215.58.181 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1726366221; cv=none; b=O9rk8VSn8z4ODNtDK0y+Ej0t540NMzUOrlP6A60v+5xzZFZu+o9wfgc+q7DygNp+iKSuQkjmGjnf2wnbMkgP1nvtMaepJrRxtl/S/VbkrYvgYOpGBcz68xmqQQ1YVaEzB1kzxsh9sBAh0mRqeNv+ifol4v0W1+5PYxe+PXnqxIo= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1726366221; c=relaxed/simple; bh=C3265iemyrhxIzFF1YJpIsKQaxeFqQxMECIMXfeP3x8=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=f7SN/B35NuJt7ob7sGCASrB9scSTSTrcOErrbljr9JSxuHY2+txxoefoafX4Nj218AS8ybZbiw0izKXW+6Z5EbLkn6F8FO19FiQGoWv2wi5CRaQB5Ox/FUNLAU3qp2pIa69QBhKR9pUd/J22+1xniIel4sHk2aeBgSMUXhl9p8Q= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev; spf=pass smtp.mailfrom=linux.dev; dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev header.b=hRGDfIJh; arc=none smtp.client-ip=95.215.58.181 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linux.dev Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev header.b="hRGDfIJh" X-Report-Abuse: Please report any abuse attempt to abuse@migadu.com and include these headers. DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.dev; s=key1; t=1726366217; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=daH29qHYE0MCAAnhFtSLBrnxdN20NU+0savZS+vkNn0=; b=hRGDfIJhqZUJmmGpi22Jg3B9Vmkzn1eXQv3UhNka4nXgdn9ljbZGlokqZMCbS6m1yFtrNW iZfaHl1m/kG1+ns8QRAn/O3LO4AMWRAYSCpPPCtKiaUPiDKQx3nC7trFrkbZlx2XU2r2sg sFVoFbz+qsdOcZSqiWVah9n8mlOrou0= From: Wen Yang To: "Eric W . Biederman" , Luis Chamberlain , Kees Cook , Joel Granados Cc: Christian Brauner , linux-kernel@vger.kernel.org, Wen Yang , Dave Young Subject: [PATCH v3 4/5] sysctl: delete mmap_rnd_bits_{min/max} and mmap_rnd_compat_bits_{min/max} to save 16 bytes Date: Sun, 15 Sep 2024 10:08:30 +0800 Message-Id: <6456666b2d30e1d062101d9182738dbeb42f4c29.1726365007.git.wen.yang@linux.dev> In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Migadu-Flow: FLOW_OUT Content-Type: text/plain; charset="utf-8" By directly encoding CONFIG_ARCH_MMAP_RND_BITS_{MIN/MAX} and CONFIG_ARCH_MMAP_RND_COMPAT_BITS_{MIN/MAX} into the ctl_table's min/max field, unnecessary global variables can be removed, saving 16 bytes. Signed-off-by: Wen Yang Cc: Luis Chamberlain Cc: Kees Cook Cc: Joel Granados Cc: Eric W. Biederman Cc: Christian Brauner Cc: Dave Young Cc: linux-kernel@vger.kernel.org --- include/linux/mm.h | 4 ---- kernel/sysctl.c | 12 ++++++------ mm/mmap.c | 4 ---- 3 files changed, 6 insertions(+), 14 deletions(-) diff --git a/include/linux/mm.h b/include/linux/mm.h index 6549d0979b28..9d9c4a4f4708 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -87,13 +87,9 @@ extern int sysctl_legacy_va_layout; #endif =20 #ifdef CONFIG_HAVE_ARCH_MMAP_RND_BITS -extern const int mmap_rnd_bits_min; -extern int mmap_rnd_bits_max __ro_after_init; extern int mmap_rnd_bits __read_mostly; #endif #ifdef CONFIG_HAVE_ARCH_MMAP_RND_COMPAT_BITS -extern const int mmap_rnd_compat_bits_min; -extern const int mmap_rnd_compat_bits_max; extern int mmap_rnd_compat_bits __read_mostly; #endif =20 diff --git a/kernel/sysctl.c b/kernel/sysctl.c index 86de15638e31..05197d46007d 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -2196,10 +2196,10 @@ static struct ctl_table vm_table[] =3D { .procname =3D "mmap_rnd_bits", .data =3D &mmap_rnd_bits, .maxlen =3D sizeof(mmap_rnd_bits), - .mode =3D 0600, + .mode =3D 0600 | SYSCTL_FLAG_MIN | SYSCTL_FLAG_MAX, .proc_handler =3D proc_dointvec_minmax, - .extra1 =3D (void *)&mmap_rnd_bits_min, - .extra2 =3D (void *)&mmap_rnd_bits_max, + .min =3D CONFIG_ARCH_MMAP_RND_BITS_MIN, + .max =3D CONFIG_ARCH_MMAP_RND_BITS_MAX, }, #endif #ifdef CONFIG_HAVE_ARCH_MMAP_RND_COMPAT_BITS @@ -2207,10 +2207,10 @@ static struct ctl_table vm_table[] =3D { .procname =3D "mmap_rnd_compat_bits", .data =3D &mmap_rnd_compat_bits, .maxlen =3D sizeof(mmap_rnd_compat_bits), - .mode =3D 0600, + .mode =3D 0600 | SYSCTL_FLAG_MIN | SYSCTL_FLAG_MAX, .proc_handler =3D proc_dointvec_minmax, - .extra1 =3D (void *)&mmap_rnd_compat_bits_min, - .extra2 =3D (void *)&mmap_rnd_compat_bits_max, + .min =3D CONFIG_ARCH_MMAP_RND_COMPAT_BITS_MIN, + .max =3D CONFIG_ARCH_MMAP_RND_COMPAT_BITS_MAX, }, #endif }; diff --git a/mm/mmap.c b/mm/mmap.c index d0dfc85b209b..8ed6f0d31d95 100644 --- a/mm/mmap.c +++ b/mm/mmap.c @@ -63,13 +63,9 @@ #endif =20 #ifdef CONFIG_HAVE_ARCH_MMAP_RND_BITS -const int mmap_rnd_bits_min =3D CONFIG_ARCH_MMAP_RND_BITS_MIN; -int mmap_rnd_bits_max __ro_after_init =3D CONFIG_ARCH_MMAP_RND_BITS_MAX; int mmap_rnd_bits __read_mostly =3D CONFIG_ARCH_MMAP_RND_BITS; #endif #ifdef CONFIG_HAVE_ARCH_MMAP_RND_COMPAT_BITS -const int mmap_rnd_compat_bits_min =3D CONFIG_ARCH_MMAP_RND_COMPAT_BITS_MI= N; -const int mmap_rnd_compat_bits_max =3D CONFIG_ARCH_MMAP_RND_COMPAT_BITS_MA= X; int mmap_rnd_compat_bits __read_mostly =3D CONFIG_ARCH_MMAP_RND_COMPAT_BIT= S; #endif =20 --=20 2.25.1 From nobody Sun Feb 8 08:44:39 2026 Received: from out-172.mta1.migadu.com (out-172.mta1.migadu.com [95.215.58.172]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 469DAEAE7 for ; Sun, 15 Sep 2024 02:10:27 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=95.215.58.172 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1726366229; cv=none; b=BF2rPIQSWluf4zUhqDdJ7zLY8nxEd2ALnLHmsWYYvcJ8lO/7PUfKA5nwPanrQkCoUmePOL1Gg2ix6Bzk0RYLE9xG+/mFhVUIedPnFPrt63TjNt97nHD4LpF3qCb+8rO7po+5JDnUltuLJGfSPd4FDJOE7Ha3cBgEIwNCmTzpC9g= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1726366229; c=relaxed/simple; bh=RHVUgBL8W4f3kC/MaUMlbi8UpCu8cHLEklQbok+aygc=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=s0piZIkHbtuzVrtNySE5Kazzewy+YKgABNm/SfYIKVtjee5EbCLYTE7+wjJL26l4Z9VfXYJrF2vCwivd8NVOvnZKRIn1ESxvOxQ6s5iDVGx4tjbpclF0DpKTu2AaMY2t2zoXLydsoofpdV4ZVHQCaoKT1OKAc2JJU8WO46+9i+U= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev; spf=pass smtp.mailfrom=linux.dev; dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev header.b=dbixe1oy; arc=none smtp.client-ip=95.215.58.172 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linux.dev Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev header.b="dbixe1oy" X-Report-Abuse: Please report any abuse attempt to abuse@migadu.com and include these headers. DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.dev; s=key1; t=1726366226; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=Q2wNQu8I8yTujCkKssEV3O6B+7E2ic9BaAtLUJTkld4=; b=dbixe1oy4mA7ZHFMYLoMdt7UeBIsAA5YPYerWpr5hFicDg6sbhKNURifXTxaIrxflkP0dX c8mEYT54GxoJd86mzi3y2luvGhacNs/jbFXcTgpZl3kHLsip7Esm1HzXuoWlW0wMCKoLej /yAKyt2KtqTGtTBAN6XnjsyW4FGmcp4= From: Wen Yang To: "Eric W . Biederman" , Luis Chamberlain , Kees Cook , Joel Granados Cc: Christian Brauner , linux-kernel@vger.kernel.org, Wen Yang , Dave Young Subject: [PATCH v3 5/5] sysctl: delete six_hundred_forty_kb to save 4 bytes Date: Sun, 15 Sep 2024 10:08:31 +0800 Message-Id: <747bae0b9c3a947ea8b0e93cf8c0fbe672ff9a94.1726365007.git.wen.yang@linux.dev> In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Migadu-Flow: FLOW_OUT Content-Type: text/plain; charset="utf-8" By directly encoding specific numbers into the min/max field, unnecessary global variable six_hundred_forty_kb can be removed, saving 4 bytes Signed-off-by: Wen Yang Cc: Luis Chamberlain Cc: Kees Cook Cc: Joel Granados Cc: Eric W. Biederman Cc: Christian Brauner Cc: Dave Young Cc: linux-kernel@vger.kernel.org --- kernel/sysctl.c | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/kernel/sysctl.c b/kernel/sysctl.c index 05197d46007d..7affb1ad7065 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -90,13 +90,6 @@ EXPORT_SYMBOL_GPL(sysctl_long_vals); =20 #if defined(CONFIG_SYSCTL) =20 -/* Constants used for minimum and maximum */ - -#ifdef CONFIG_PERF_EVENTS -static const int six_hundred_forty_kb =3D 640 * 1024; -#endif - - static const int ngroups_max =3D NGROUPS_MAX; static const int cap_last_cap =3D CAP_LAST_CAP; =20 @@ -1964,10 +1957,10 @@ static struct ctl_table kern_table[] =3D { .procname =3D "perf_event_max_stack", .data =3D &sysctl_perf_event_max_stack, .maxlen =3D sizeof(sysctl_perf_event_max_stack), - .mode =3D 0644, + .mode =3D 0644 | SYSCTL_FLAG_MIN | SYSCTL_FLAG_MAX, .proc_handler =3D perf_event_max_stack_handler, - .extra1 =3D SYSCTL_ZERO, - .extra2 =3D (void *)&six_hundred_forty_kb, + .min =3D SYSCTL_NUM_ZERO, + .max =3D 640 * 1024, }, { .procname =3D "perf_event_max_contexts_per_stack", --=20 2.25.1