Então, já faço essa limitação através da seguinte função:

char * read_line(FILE * stream) {
    char * buffer = (char *) malloc(sizeof(char) * MAX_BUFFER_SIZE);
    
    int read = strlen(fgets(buffer, MAX_BUFFER_SIZE, stream));

    if(read < MAX_BUFFER_SIZE && buffer[read - 1] == '\n') {
        buffer[--read] = '\0';
    }

    printf("characters read: %d\n", read);

    return buffer;
}

E passo a stdin como argumento. O que ocorreu ao meu ver (e pelo que eu compreendi via resposta do brenomazieiro) foi que ao usar o redirecionador padrão do terminal do linux (<), o mesmo alocou, dinamicamente, mais instruções ou sobreescritas de instrução assembly ao programa, de modo que pudesse efetuar o redirecionamento da forma correta.

Muito provavelmente devo achar algo no código fonte do linux ou da distro que estou usando, mas ainda não olhei.

Você aloca memória para o buffer, mas em que momento ela é liberada? Ou seja, quem faz o free(buffer)?

Acredito que vc esteja usando esta função várias vezes para ler todas as linhas, certo? Provavelmente em um loop. Como está sendo feito?

Acho que isso já ajuda a saber as causas, não precisa chegar ao ponto de ver o fonte do Linux...