libc: fix access mode tests in fmemopen(3)

Previously a stream opened as read-only could be written to.  Add a test
case for the fix.

Also correct another incorrect access mode check that worked by
accident, and improve the tests for that.

PR:		281953
Reported by:	Erkki Moorits, fuz
Reviewed by:	fuz, khng (earlier)
Sponsored by:	The FreeBSD Foundation
Differential Revision: https://reviews.freebsd.org/D47265

(cherry picked from commit 0953460ce149e6f384aafbcb1e6213dfbf8f6a16)
(cherry picked from commit 6b9f7133aba44189d9625c352bc2c2a59baf18ef)
This commit is contained in:
Ed Maste 2024-10-23 09:41:51 -04:00
parent 1af027e583
commit 4fbd6e0e3c
2 changed files with 38 additions and 5 deletions

View file

@ -74,10 +74,9 @@ fmemopen(void * __restrict buf, size_t size, const char * __restrict mode)
}
/*
* There's no point in requiring an automatically allocated buffer
* in write-only mode.
* An automatically allocated buffer is only allowed in read-write mode.
*/
if (!(flags & O_RDWR) && buf == NULL) {
if ((flags & O_ACCMODE) != O_RDWR && buf == NULL) {
errno = EINVAL;
return (NULL);
}
@ -136,9 +135,10 @@ fmemopen(void * __restrict buf, size_t size, const char * __restrict mode)
break;
}
/* Disable read in O_WRONLY mode, and write in O_RDONLY mode. */
f = funopen(ck,
flags & O_WRONLY ? NULL : fmemopen_read,
flags & O_RDONLY ? NULL : fmemopen_write,
(flags & O_ACCMODE) == O_WRONLY ? NULL : fmemopen_read,
(flags & O_ACCMODE) == O_RDONLY ? NULL : fmemopen_write,
fmemopen_seek, fmemopen_close);
if (f == NULL) {

View file

@ -132,9 +132,11 @@ ATF_TC_BODY(test_autoalloc, tc)
/* Open a FILE * using a wrong mode */
fp = fmemopen(NULL, 512, "r");
ATF_REQUIRE(fp == NULL);
ATF_REQUIRE(errno == EINVAL);
fp = fmemopen(NULL, 512, "w");
ATF_REQUIRE(fp == NULL);
ATF_REQUIRE(errno == EINVAL);
}
ATF_TC_WITHOUT_HEAD(test_data_length);
@ -271,6 +273,36 @@ ATF_TC_BODY(test_size_0, tc)
ATF_REQUIRE(errno == EINVAL);
}
/*
* PR281953 - ensure we cannot write in read-only only mode, and cannot read in
* write-only mode.
*/
ATF_TC_WITHOUT_HEAD(test_rdonly_wronly);
ATF_TC_BODY(test_rdonly_wronly, tc)
{
FILE *fp;
char buf[16];
char buf_orig[16] = "input data";
char buf_write[16] = "write";
size_t sz;
memcpy(buf, buf_orig, sizeof(buf));
fp = fmemopen(buf, sizeof(buf), "r");
ATF_REQUIRE(fp != NULL);
sz = fwrite(buf_write, 1, strlen(buf_write), fp);
ATF_REQUIRE(sz == 0);
ATF_REQUIRE(errno == EBADF);
ATF_REQUIRE(memcmp(buf, buf_orig, sizeof(buf)) == 0);
fclose(fp);
fp = fmemopen(buf_orig, sizeof(buf), "w");
ATF_REQUIRE(fp != NULL);
sz = fread(buf, sizeof(buf), 1, fp);
ATF_REQUIRE(sz == 0);
ATF_REQUIRE(errno == EBADF);
fclose(fp);
}
ATF_TP_ADD_TCS(tp)
{
@ -280,6 +312,7 @@ ATF_TP_ADD_TCS(tp)
ATF_TP_ADD_TC(tp, test_binary);
ATF_TP_ADD_TC(tp, test_append_binary_pos);
ATF_TP_ADD_TC(tp, test_size_0);
ATF_TP_ADD_TC(tp, test_rdonly_wronly);
return (atf_no_error());
}