/* Provenance: openssl/openssl linebuffer_write (fixed). * repo: openssl/openssl * commit: 475c466ef2fbd8fc1df6fae1c3eed9c813fc8ff6 * parent: e0666f72294691a808443970b654412a6d92fa0f * commit_url: https://github.com/openssl/openssl/commit/475c466ef2fbd8fc1df6fae1c3eed9c813fc8ff6 * cve: CVE-2025-68160 * license: Apache-2.0 * function: linebuffer_write * relpath: crypto/bio/bf_lbuf.c */ static int linebuffer_write(BIO *b, const char *in, int inl) { int i, num = 0, foundnl; BIO_LINEBUFFER_CTX *ctx; if ((in == NULL) || (inl <= 0)) return 0; ctx = (BIO_LINEBUFFER_CTX *)b->ptr; if ((ctx == NULL) || (b->next_bio == NULL)) return 0; BIO_clear_retry_flags(b); do { const char *p; char c; for (p = in, c = '\0'; p < in + inl && (c = *p) != '\n'; p++) ; if (c == '\n') { p++; foundnl = 1; } else foundnl = 0; /* * If a NL was found and we already have text in the save buffer, * concatenate them and write */ while ((foundnl || p - in > ctx->obuf_size - ctx->obuf_len) && ctx->obuf_len > 0) { int orig_olen = ctx->obuf_len; i = ctx->obuf_size - ctx->obuf_len; if (p - in > 0) { if (i >= p - in) { memcpy(&(ctx->obuf[ctx->obuf_len]), in, p - in); ctx->obuf_len += p - in; inl -= p - in; num += p - in; in = p; } else { memcpy(&(ctx->obuf[ctx->obuf_len]), in, i); ctx->obuf_len += i; inl -= i; in += i; num += i; } } i = BIO_write(b->next_bio, ctx->obuf, ctx->obuf_len); if (i <= 0) { ctx->obuf_len = orig_olen; BIO_copy_next_retry(b); if (i < 0) return ((num > 0) ? num : i); if (i == 0) return num; } if (i < ctx->obuf_len) memmove(ctx->obuf, ctx->obuf + i, ctx->obuf_len - i); ctx->obuf_len -= i; } /* * Now that the save buffer is emptied, let's write the input buffer * if a NL was found and there is anything to write. */ if ((foundnl || p - in > ctx->obuf_size) && p - in > 0) { i = BIO_write(b->next_bio, in, p - in); if (i <= 0) { BIO_copy_next_retry(b); if (i < 0) return ((num > 0) ? num : i); if (i == 0) return num; } num += i; in += i; inl -= i; } } while (foundnl && inl > 0); /* * We've written as much as we can. The rest of the input buffer, if * any, is text that doesn't end with a NL and therefore we need to try * free up some space in our obuf so we can make forward progress. */ while (inl > 0) { size_t avail = (size_t)ctx->obuf_size - (size_t)ctx->obuf_len; size_t to_copy; if (avail == 0) { /* Flush buffered data to make room */ i = BIO_write(b->next_bio, ctx->obuf, ctx->obuf_len); if (i <= 0) { BIO_copy_next_retry(b); return num > 0 ? num : i; } if (i < ctx->obuf_len) memmove(ctx->obuf, ctx->obuf + i, ctx->obuf_len - i); ctx->obuf_len -= i; continue; } to_copy = inl > (int)avail ? avail : (size_t)inl; memcpy(&(ctx->obuf[ctx->obuf_len]), in, to_copy); ctx->obuf_len += (int)to_copy; in += to_copy; inl -= (int)to_copy; num += (int)to_copy; } return num; }