From daniel at haxx.se Wed Oct 16 10:21:34 2024 From: daniel at haxx.se (Daniel Stenberg) Date: Wed, 16 Oct 2024 10:21:34 +0200 (CEST) Subject: [RELEASE] libssh2 1.11.1 Message-ID: <289r0q2q-4893-qo5o-1qos-60635p0rs7n1@unkk.fr> Hello! We just shipped a new release: 1.11.1. Enjoy! Get it from https://libssh2.org/ as usual. The actual changelog is best view here: https://github.com/libssh2/libssh2/releases/tag/libssh2-1.11.1 -- / daniel.haxx.se From Gianluca at debugsrl.it Wed Oct 16 10:30:39 2024 From: Gianluca at debugsrl.it (Gianluca Bortolozzo) Date: Wed, 16 Oct 2024 08:30:39 +0000 Subject: libssh2 leak on write to sftp server Message-ID: Dear all, I'm testing a sw. with the device Espressif esp32/WROVER-E, with esp-idf 4.4.3 and with visualgdb (a cross platform based on visual studio). The server is a notebook with windows10 and OpenSSF free version by the link https://github.com/PowerShell/Win32-OpenSSH During test with wifi/ethernet test to read/write file into a local server sftp I discovered that: the heap is stable if I read file from server, If I write a file to a server sftp start to decrease of 80byte every operation the heap available. I double check a lot alloc and free, it seem ok but the sfpt_open or write reduce the heap. The files are text file of json developed on write (250 bytes of size) , decoded when I read from server sftp. The version of libssh2 is LIBSSH2_VERSION "1.11.1_DEV" Attached the file of test where the functions used are: void Manager_client_sftp(void) manage the operation read write into server sftp and int InvioJsonIdPowerOnIdentification (LIBSSH2_SESSION *session) that write the file to the server sftp and decrease the heap Did you have ever seen this this problem ? If yes are ther a solution? In the same time I'm starting the porting to last esp-idf into visualcode ide with plugin espressif Because with visualgdb does not support the last revison of esp-idf. Many thanks Best Regards Gianluca Bortolozzo Debug s.r.l. Via della Meccanica 1T 36100 VICENZA Tel. +39 0444-566344 Fax +39 0444-962273 -------------- next part -------------- An HTML attachment was scrubbed... URL: -------------- next part -------------- // invia il json del ID di POWER ON // parameters: session, la sessione sftp aperta // return: 2, comando non richiesto // 0, tutto ok scritto // -1, errore server sftp int InvioJsonIdPowerOnIdentification (LIBSSH2_SESSION *session) { cJSON *root; int result = 2; ssize_t nwritten; //LIBSSH2_SFTP *sftp_session = NULL; // LIBSSH2_SFTP_HANDLE *sftp_handle = NULL; uint8_t aux_len; // e' un power on si deve inviare il file json printf("JSON: ID_POWER_ON/IDENTIFICATION\r\n"); // TODO: gestire la problematica di server sFTP che non si connette o altro root = cJSON_CreateObject ( ); cJSON_AddStringToObject(root, STR_ID_JSON, JSON_ID_TRANSMIT_IDENTIFICATION); cJSON_AddStringToObject(root, STR_SERIAL_NUMBER, app_Machine.Codici.Matricola); cJSON_AddStringToObject(root, STR_TRAIN_NUMBER, app_Machine.Codici.NumeroTreno); cJSON_AddStringToObject(root, STR_TRAVEL_NUMBER, app_Machine.Codici.NumeroViaggio); SetTimeZoneItaly ( ); // preparazione del prefisso e poi del nome del file GenerazionePrefissoFileJson(nomeFileJson, LEN_MAX_NAME_FILE); // si salva il prefisso poiche' servira' a controllare le risposte ricevute e trovare l'ultima memset(str_data_req_travel_code, 0, LEN_STR_DATA); strcpy(str_data_req_travel_code, nomeFileJson); aux_len = strlen(nomeFileJson); sprintf(nomeFileJson + aux_len, "%s_", app_Machine.Codici.NumeroTreno); aux_len = strlen(nomeFileJson); sprintf(nomeFileJson + aux_len, "%s_", app_Machine.Codici.Matricola); aux_len = strlen(nomeFileJson); sprintf(nomeFileJson + aux_len, "%s", STR_IDENTIFICATION_FILE); // scrittura del file sul server // generazione di nome file in base a data e ora , con json sftp_session = libssh2_sftp_init (session); if (!sftp_session) { fprintf(stderr, "Unable to init SFTP session\n"); // stato di errore result = -1; } else { int len; esp_task_wdt_reset(); // Request to write a file via SFTP // do // { sftp_handle = libssh2_sftp_open(sftp_session, nomeFileJson, LIBSSH2_FXF_WRITE | LIBSSH2_FXF_CREAT | LIBSSH2_FXF_TRUNC, LIBSSH2_SFTP_S_IRUSR | LIBSSH2_SFTP_S_IWUSR | LIBSSH2_SFTP_S_IRGRP | LIBSSH2_SFTP_S_IROTH); // } while (libssh2_sftp_last_error(sftp_session) == LIBSSH2_ERROR_EAGAIN); if (!sftp_handle) { fprintf (stderr, "Unable to open file with SFTP: %ld\n", libssh2_sftp_last_error (sftp_session)); // stato di errore result = -1; } else { my_json_string = cJSON_Print(root); begin = my_json_string; /// ESP_LOGI(TAG, "json_string\n%s", my_json_string); len = strlen(my_json_string); do { // write data in a loop until we block nwritten = libssh2_sftp_write(sftp_handle, my_json_string, len); my_json_string += nwritten; len -= nwritten; // HACK: serve per non bloccare il modbus altrimenti con il timeout rimanda comandi di reinizializzazione vTaskDelay(10); } while (len > 0); if (begin) { cJSON_free(begin); } if (root) { cJSON_Delete(root); } } if (sftp_handle) libssh2_sftp_close (sftp_handle); } // if (sftp_session) { libssh2_sftp_shutdown (sftp_session); } return result; } //------------------------------------------------------------------------------ void Manager_client_sftp(void) { static uint8_t old_state=255; static struct sockaddr_in sin; vTaskDelay(20); if (state != old_state) { printf("Manager_client_sftp state = %d\n",state); old_state = state; } // gestione anomalie che impediscono l'esecuzione del client sftp if (app_Machine.SftpServerSetup.SoloServerSftp == 0) { // server sftp non abilitato si mette la macchina a stati in idle if (state == STATE_IDLE) { return; } state = STATE_SHUTDOWN; } // gestione anomalie che impediscono l'esecuzione del client sftp if (chunk_operation_running != false) { // server sftp non abilitato si mette la macchina a stati in idle if (state == STATE_IDLE) { return; } state = STATE_SHUTDOWN; } esp_task_wdt_reset(); switch (state) { case 0: { // carica dalla flash interna le impostazioni se presenti if (doneRegistration == false) { doneRegistration = true; if (InitializeVariableAccountSftp ( ) != ESP_OK) { printf ("errore nella lettura variabili account sftp\n\r"); } if (account_sFTP_registered == false) { if (InitializeAccountSftp2 (&account_sftp) == 0) { account_sFTP_registered = true; } } if (key_private_registered == false) { if (InitializePrivateKeySftp2 ( ) == 0) { key_private_registered = true; } } if (key_public_registered == false) { if (InitializePublicKeySftp2 ( ) == 0) { key_public_registered = true; } } if ((account_sFTP_registered == false) || (key_private_registered == false) || (key_public_registered == false)) { // non sono presenti le credenziali per cui si riprova e lo si segnala app_Machine.Status.DoubleWord &= ~(1 << APP_STATUS_ACCOUNT_SFTP_REGISTRATO); return; } else if ((account_sFTP_registered == true) && (key_private_registered == true) && (key_public_registered == true)) { // sono presenti le credenziali e ci si e' connessi app_Machine.Status.DoubleWord |= 1 << APP_STATUS_ACCOUNT_SFTP_REGISTRATO; } // qui sftp_session deve essere null serve nel caso si vada in shutdown senza // aver inizializzato correttamente sft_session } if ((app_command_sftp.Comand.DoubleWord & (1 << APP_ID_TRANSMIT_ID)) != 0) { // al power on si deve fare richiesta del numero di viaggio app_command_sftp.Comand.DoubleWord &= ~(1 << APP_ID_TRANSMIT_ID); fl_APP_ID_TRANSMIT_ID = true; sftp_session = NULL; state = 10; } else if ((app_command_sftp.Comand.DoubleWord & (1 << APP_ID_DELIVERY_DONE)) != 0) { app_command_sftp.Comand.DoubleWord &= ~(1 << APP_ID_DELIVERY_DONE); fl_NEW_DELIVERY_ID = true; sftp_session = NULL; state = 10; } else if ((app_command_sftp.Comand.DoubleWord & (1 << APP_ID_NEW_TRAVEL_NUMBER)) != 0) { app_command_sftp.Comand.DoubleWord &= ~(1 << APP_ID_NEW_TRAVEL_NUMBER); fl_NEW_TRAVEL_NUMBER_ID = true; sftp_session = NULL; state = 10; } else if ((app_command_sftp.Comand.DoubleWord & (1 << APP_ID_CHECK_TRAVEL_NUMBER)) != 0) { app_command_sftp.Comand.DoubleWord &= ~(1 << APP_ID_CHECK_TRAVEL_NUMBER); fl_CHECK_TRAVEL_NUMBER_ID = true; sftp_session = NULL; state = 10; } else if ((app_command_sftp.Comand.DoubleWord & (1 << APP_ID_CODE_DISCOUNT)) != 0) { app_command_sftp.Comand.DoubleWord &= ~(1 << APP_ID_CODE_DISCOUNT); fl_CHECK_CODE_DISCOUNT_ID = true; sftp_session = NULL; state = 10; } } break; case 10: // controllo della memoria disponibile se poca resetta CheckFreeSpaceOnHeap(); // inizia la parte ssh di test derivata da sftp_write.c di libssh2 rc = libssh2_init(0); if (rc) { fprintf(stderr, "libssh2 initialization failed (%d)\n", rc); // stato di errore state = STATE_SHUTDOWN; } else { state = 11; } break; case 11: // The application code is responsible for creating the socket // and establishing the connection sock = socket(AF_INET, SOCK_STREAM, 0); if (sock == LIBSSH2_INVALID_SOCKET) { fprintf(stderr, "failed to create socket.\n"); // stato di errore si va in shutdown per fare il recovery state = STATE_SHUTDOWN; } else { sin.sin_family = AF_INET; // si imposta a 1151 il default dovrebbe essere 22 ma si deve poter impostare sin.sin_port = htons(app_Machine.SftpServerSetup.PortaServerSftp); memcpy(&sin.sin_addr.s_addr, &app_Machine.SftpServerSetup.IpServerSftp, 4); state = 12; } break; case 12: { int r; r = connect(sock, (struct sockaddr*)(&sin), sizeof(struct sockaddr_in)); if (r != 0) { fprintf(stderr, "r = %d xx failed to connect.\n", r); // stato di errore state = STATE_SHUTDOWN; } else { state = 13; } } break; case 13: // Create a session instance session = libssh2_session_init(); if (!session) { fprintf (stderr, "Could not initialize SSH session.\n"); // stato di errore state = STATE_SHUTDOWN; } else { // Since we have set non-blocking, tell libssh2 we are blocking libssh2_session_set_blocking (session, 1); state = 14; } break; case 14: // ... start it up. This will trade welcome banners, exchange keys, // and setup crypto, compression, and MAC layers rc = libssh2_session_handshake(session, sock); if (rc) { fprintf(stderr, "Failure establishing SSH session: %d\n", rc); // stato di errore state = STATE_SHUTDOWN; } else { state = 15; } break; case 15: // At this point we have not yet authenticated. The first thing to do // is check the hostkey's fingerprint against our known hosts Your app // may have it hard coded, may go to a file, may present it to the // user, that's your call fingerprint = libssh2_hostkey_hash(session, LIBSSH2_HOSTKEY_HASH_SHA1); // si confronta il fingerprint ottenuto con quello ottenuto dalle credenziali di accesso // se serve state = 16; break; case 16: // check what authentication methods are available // si deve verificare che tutto sia definito altrimenti non si parte if ((account_sFTP_registered != true) || (key_private_registered != true) || (key_public_registered != true)) { RequestReinitSftp ( ); return; } userauthlist = libssh2_userauth_list(session, account_sftp.username, strlen(account_sftp.username)); fprintf(stderr, "Authentication methods: %s\n", userauthlist); if (strstr(userauthlist, "password") != NULL) { auth_pw |= 1; } if (strstr(userauthlist, "keyboard-interactive") != NULL) { auth_pw |= 2; } if (strstr(userauthlist, "publickey") != NULL) { auth_pw |= 4; } state = 17; break; case 17: if ( (auth_pw & 2) == auth_pw) { // We could authenticate via password if (libssh2_userauth_password(session, account_sftp.username, account_sftp.password)) { fprintf(stderr, "Authentication by password failed.\n"); // stato di errore state = STATE_SHUTDOWN; break; } } else { int result; // Or by public key result = libssh2_userauth_publickey_frommemory(session, account_sftp.username, strlen( account_sftp.username), key_public, strlen(key_public), key_private, strlen(key_private), account_sftp.passphrase); if (result != 0) { fprintf (stderr, "Authentication by public key failed.\n"); // stato di errore state = STATE_SHUTDOWN; break; } } state = 21; break; case 21: // gestione di file json if (fl_APP_ID_TRANSMIT_ID == true) { int answer; fl_APP_ID_TRANSMIT_ID = false; // CheckFreeSpaceOnHeap(); // printf ("----------------------------------------\n\r"); // ESP_ERROR_CHECK( heap_trace_start(HEAP_TRACE_ALL) ); // WRITE file to server sftp answer = InvioJsonIdPowerOnIdentification(session); // ESP_ERROR_CHECK( heap_trace_stop() ); // heap_trace_dump(); // CheckFreeSpaceOnHeap(); // printf ("----------------------------------------\n\r"); // printf ("----------------------------------------\n\r"); // printf (" "); } else if (fl_NEW_TRAVEL_NUMBER_ID == true) { int answer; fl_NEW_TRAVEL_NUMBER_ID = false; answer = InvioJsonIdNewTravelNumber(session); } else if (fl_CHECK_TRAVEL_NUMBER_ID == true) { int answer; fl_CHECK_TRAVEL_NUMBER_ID = false; answer = SearchJsonIdNewTravelNumber(session); } else if (fl_CHECK_CODE_DISCOUNT_ID == true) { int answer; // ESP_ERROR_CHECK( heap_trace_start(HEAP_TRACE_ALL) ); fl_CHECK_CODE_DISCOUNT_ID = false; answer = SearchJsonIdCodeDiscount(session); } else if (fl_NEW_DELIVERY_ID == true) { int answer; fl_NEW_DELIVERY_ID = false; // WRITE file to server sftp answer = InvioJsonDelivery(session); } state = STATE_SHUTDOWN; break; case STATE_SHUTDOWN: if (session) { libssh2_session_disconnect (session, "Normal Shutdown"); libssh2_session_free (session); session = NULL; } if (sock != LIBSSH2_INVALID_SOCKET) { shutdown (sock, 2); close (sock); } // fprintf (stderr, "all done\n"); libssh2_exit ( ); state = STATE_IDLE; break; case STATE_IDLE: // stato di idle si attende che gli stati permettono l'attivazione del client sftp if ( (app_Machine.SftpServerSetup.SoloServerSftp != 0) && (chunk_operation_running == false) ) { state = 0; } vTaskDelay (10); break; } } //-----------------------------------------------------------------------------