Skip to content

Conversation

@alejandro-colomar
Copy link
Collaborator

@alejandro-colomar alejandro-colomar commented Dec 7, 2025


Revisions:

v1b
  • Rebase
  • Reword commit message.
$ git rd 
1:  1df03082f ! 1:  d8c60e2d1 lib/limits.c: Reduce scope of local arrays
    @@ lib/limits.c: static int setup_user_limits (const char *uname)
        /* start the checks */
        fil = fopen (LIMITS_FILE, "r");
     @@ lib/limits.c: static int setup_user_limits (const char *uname)
    -    * FIXME: A better (smarter) checking should be done
    +    * FIXME: a better (smarter) checking should be done
         */
        while (fgets (buf, 1024, fil) != NULL) {
     +          char  name[1024];
2:  a1ad7bae3 = 2:  ddc2186c7 lib/limits.c: Clear the newline
3:  8cb6e30fb ! 3:  e4264669e lib/limits.c: Replace sscanf(3) with conventional string parsing
    @@ Commit message
     
      ## lib/limits.c ##
     @@ lib/limits.c: static int setup_user_limits (const char *uname)
    -    * FIXME: A better (smarter) checking should be done
    +    * FIXME: a better (smarter) checking should be done
         */
        while (fgets (buf, 1024, fil) != NULL) {
     -          char  name[1024];
4:  67f545f11 = 4:  231bf262c lib/limits.c: Unindent
5:  99792bc90 ! 5:  fb7418036 lib/limits.c: Remove dead code
    @@ Metadata
      ## Commit message ##
         lib/limits.c: Remove dead code
     
    -    We're going to overwrite this in fgets(3), and even if it were to fail
    -    in the first, call, we don't use the buffer after that, so the zeroing
    -    is superfluous.
    +    We overwrite this in fgets(3), and even if it were to fail in the first
    +    call, we don't use the buffer after that, so the zeroing is superfluous.
     
         Signed-off-by: Alejandro Colomar <alx@kernel.org>
     
v1c
  • Rebase
$ git rd 
1:  d8c60e2d1 = 1:  834b16684 lib/limits.c: Reduce scope of local arrays
2:  ddc2186c7 = 2:  c7932f412 lib/limits.c: Clear the newline
3:  e4264669e = 3:  0abbd660c lib/limits.c: Replace sscanf(3) with conventional string parsing
4:  231bf262c = 4:  a57f58cd0 lib/limits.c: Unindent
5:  fb7418036 = 5:  dfba6c46e lib/limits.c: Remove dead code

@alejandro-colomar alejandro-colomar force-pushed the sscanf branch 4 times, most recently from a44624a to 67f545f Compare December 7, 2025 00:18
We only use them in the loop, and we write to them unconditionally in
every iteration with sscanf(3), so we can reduce their lifetime, and
skip the superfluous zeroing.

Signed-off-by: Alejandro Colomar <alx@kernel.org>
And reject incomplete lines.

Signed-off-by: Alejandro Colomar <alx@kernel.org>
sscanf(3) is quite brittle.  Let's parse with regular string functions,
which are much more robust.  This should silence a CodeQL false
positive, BTW.

This new parsing has a slight difference with the sscanf(3) call: the
first whitespace after the name is turned into a null delimiter byte,
while sscanf(3) was keeping it as part of the second string.  However,
since we later skip leading white space --within do_user_limits()--,
this is irrelevant.

I've tested this patch with the following program:

	$ cat sscanf.c
	#include <err.h>
	#include <stdio.h>
	#include <string.h>

	extern inline char *
	stpsep(char *s, const char *delim)
	{
		strsep(&s, delim);

		return s;
	}

	#define stpspn(s, accept)                                             \
	({                                                                    \
		auto  s_ = s;                                                 \
									      \
		s_ + strspn(s_, accept);                                      \
	})

	int
	main(void)
	{
		char  buf[1000];
		char  s1[1000] = "";
		char  s2[1000] = "";
		char  *p1, *p2;
		int   n;

		if (fgets(buf, 1000, stdin) == NULL)
			err(1, "fgets");

		n = sscanf(buf, "%s%[ACDFIKLMNOPRSTUacdfiklmnoprstu0-9 \t-]", s1, s2);
		if (n != 2)
			warn("sscanf: %d", n);

		printf("--- s1: |%s|\n", s1);
		printf("--- s2: |%s|\n", s2);

		if (stpsep(buf, "\n") == NULL)
			warn("stpsep(\"\n\")");

		p1 = buf;
		p2 = stpsep(buf, " \t");
		if (p2 == NULL)
			warn("stpsep");
		else
			stpcpy(stpspn(p2, "ACDFIKLMNOPRSTUacdfiklmnoprstu0123456789 \t-"), "");

		printf("+++ s1: |%s|\n", p1);
		printf("+++ s2: |%s|\n", p2);
	}
	alx@devuan:~/tmp$ gcc -Wall -Wextra sscanf.c
	alx@devuan:~/tmp$ ./a.out
	qwe
	a.out: sscanf: 1: Success
	--- s1: |qwe|
	--- s2: ||
	a.out: stpsep: Success
	+++ s1: |qwe|
	+++ s2: |(null)|
	alx@devuan:~/tmp$ ./a.out
	qwe qwe
	--- s1: |qwe|
	--- s2: | |
	+++ s1: |qwe|
	+++ s2: ||
	alx@devuan:~/tmp$ ./a.out
	qwe acd acd 123456
	--- s1: |qwe|
	--- s2: | acd acd 123456|
	+++ s1: |qwe|
	+++ s2: |acd acd 123456|
	alx@devuan:~/tmp$ ./a.out
	qwe acd123 qwe
	--- s1: |qwe|
	--- s2: | acd123 |
	+++ s1: |qwe|
	+++ s2: |acd123 |

Interestingly, this patch makes it more obvious that we're silently
ignoring garbage after the limit.  Should we be more strict in what we
parse?  That'll be for another day.

BTW, we've removed a conditional, but keep the code indented.  That will
keep this patch small.  The next commit will fix that indentation.

Signed-off-by: Alejandro Colomar <alx@kernel.org>
Signed-off-by: Alejandro Colomar <alx@kernel.org>
We overwrite this in fgets(3), and even if it were to fail in the first
call, we don't use the buffer after that, so the zeroing is superfluous.

Signed-off-by: Alejandro Colomar <alx@kernel.org>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant