Skip to content

feat: Add write_mem payload to bootloader payloads#163

Open
efargas wants to merge 6 commits into
refactor/logging-serilogfrom
jules-write-mem-payload-278287118685724991
Open

feat: Add write_mem payload to bootloader payloads#163
efargas wants to merge 6 commits into
refactor/logging-serilogfrom
jules-write-mem-payload-278287118685724991

Conversation

@efargas
Copy link
Copy Markdown
Owner

@efargas efargas commented Mar 28, 2026

  • Added write_mem payload mirroring dump_mem.
  • Extracted target address and size from parameters matching the bootloader execution frame.
  • Leveraged existing UART_protocol_recv in lib/read.c to directly copy payload bytes over serial directly to memory.
  • Added write_mem to the Docker build list in build_and_collect.sh.

PR created automatically by Jules for task 278287118685724991 started by @efargas

Added `write_mem` payload structure mirroring `dump_mem`. Uses the custom UART protocol (via `UART_protocol_recv`) to receive bytes over serial and copy them directly to the specified target address on the PLC. Build process adjusted in `build_and_collect.sh` to compile the new payload.

Co-authored-by: efargas <9705611+efargas@users.noreply.github.com>
@google-labs-jules
Copy link
Copy Markdown
Contributor

👋 Jules, reporting for duty! I'm here to lend a hand with this pull request.

When you start a review, I'll add a 👀 emoji to each comment to let you know I've read it. I'll focus on feedback directed at me and will do my best to stay out of conversations between you and other bots or reviewers to keep the noise down.

I'll push a commit with your requested changes shortly after. Please note there might be a delay between these steps, but rest assured I'm on the job!

For more direct control, you can switch me to Reactive Mode. When this mode is on, I will only act on comments where you specifically mention me with @jules. You can find this option in the Pull Request section of your global Jules UI settings. You can always switch back!

New to Jules? Learn more at jules.google/docs.


For security, I will only act on instructions from the user who triggered this task.

Copilot AI review requested due to automatic review settings March 28, 2026 17:18
Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a new memory writing payload for Siemens S7 PLCs, enabling arbitrary data writes to memory via UART. The review identifies a critical security vulnerability due to the lack of validation for target addresses and sizes, which could lead to device bricking. Other feedback includes addressing potential undefined behavior from pointer casting by using memcpy, resolving function signature inconsistencies, removing unused assembly files, and cleaning up redundant null terminators in string literals.

UART_protocol_send_single(greeting, sizeof(greeting));

// Receive data from host and write it directly to the target address
int result = UART_protocol_recv(tar_addr, size);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

critical

The received target address (tar_addr) and size are used without any validation. This is a critical security vulnerability. A malicious or malformed input from the host could specify an arbitrary address and size, potentially overwriting critical code or data, such as the bootloader itself. This could lead to a permanent denial of service (bricking the device). You should add checks to ensure that the memory range being written to is within a valid and safe region.

Comment on lines +49 to +50
uint32_t size = *((uint32_t *)(read_buf+8));
char *tar_addr = *((char **)(read_buf+4));
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

Reading multi-byte values by casting a pointer and dereferencing can lead to undefined behavior due to strict aliasing violations and potential unaligned memory access. A safer and more portable approach is to use memcpy. Note that you may need to include the appropriate header for memcpy (e.g., <string.h>).

Suggested change
uint32_t size = *((uint32_t *)(read_buf+8));
char *tar_addr = *((char **)(read_buf+4));
uint32_t size;
char *tar_addr;
memcpy(&size, read_buf + 8, sizeof(size));
memcpy(&tar_addr, read_buf + 4, sizeof(tar_addr));

../lib/string.c \
../lib/read.c

#SRC_ASM := start.S
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The start.S file is included in the pull request but is not used in the build, as indicated by this commented-out line. The entry point _start is defined in write_mem.c. To avoid confusion, the unused start.S file should be removed from the repository, and this line can be removed as well.

Comment on lines +1 to +16
.globl _start
.globl main

.section .text.entry
.align 4
_start:
/* Must preserve regs and cpsr */
/*stmfd sp!, {r0-r12, lr}
adr sb, _start

bl main

ldmfd sp!, {r0-r12, lr}
bx lr*/

b main
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

This assembly file appears to be unused. The Makefile for this payload has the corresponding SRC_ASM variable commented out, and the _start entry point is defined in write_mem.c. Furthermore, this file references a main function which does not exist in the payload. To avoid confusion and reduce code clutter, this file should be removed.

#include "../lib/print.h"
#include "../lib/read.h"

char greeting[] = "Ok\0";
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The explicit null terminator \0 is redundant, as string literals are already null-terminated. This results in greeting being an array of 4 characters ('O', 'k', \0, \0) instead of 3. Consequently, sizeof(greeting) is 4, and an extra null byte is sent over UART, which is likely not intended.

Suggested change
char greeting[] = "Ok\0";
char greeting[] = "Ok";

* - Offset 4: Target memory address (4 bytes)
* - Offset 8: Number of bytes to write (4 bytes)
*/
int doit(uint8_t *read_buf, unsigned char *write_buf) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The function signature of doit here uses uint8_t* for read_buf, which differs from its forward declaration on line 17 that uses unsigned char*. While these types are often equivalent, it's best practice to use consistent types in declarations and definitions to improve code clarity and prevent potential issues.

Suggested change
int doit(uint8_t *read_buf, unsigned char *write_buf) {
int doit(unsigned char *read_buf, unsigned char *write_buf) {

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a new bootloader payload (write_mem) intended to mirror the existing dump_mem payload, enabling the host to stream bytes over UART directly into a target memory address on the PLC.

Changes:

  • Introduces write_mem payload entrypoint and UART receive-to-memory write logic.
  • Adds write_mem to the payload build/collection script.
  • Adds several build outputs (*.o, *.d) under write_mem/ (currently committed as new files).

Reviewed changes

Copilot reviewed 11 out of 16 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
bootloader-payloads/payloads/write_mem/write_mem.c Implements the write_mem payload and uses UART_protocol_recv() to write received bytes into target memory.
bootloader-payloads/payloads/write_mem/Makefile Adds a Makefile to build the payload using the shared ../lib/*.c sources.
bootloader-payloads/payloads/write_mem/link.ld Includes the shared linker script.
bootloader-payloads/payloads/write_mem/memory.h Adds the same RW buffer definition pattern used by other payloads.
bootloader-payloads/payloads/write_mem/start.S Adds the standard entry stub (currently unused by Makefile, consistent with other payloads).
bootloader-payloads/payloads/build_and_collect.sh Includes write_mem in the payload build loop.
bootloader-payloads/payloads/write_mem/build/write_mem.o Committed build artifact (object file).
bootloader-payloads/payloads/write_mem/build/write_mem.d Committed build artifact (dependency file).
bootloader-payloads/payloads/write_mem/lib/print.o Committed build artifact (object file).
bootloader-payloads/payloads/write_mem/lib/print.d Committed build artifact (dependency file).
bootloader-payloads/payloads/write_mem/lib/read.o Committed build artifact (object file).
bootloader-payloads/payloads/write_mem/lib/read.d Committed build artifact (dependency file).
bootloader-payloads/payloads/write_mem/lib/stdlib.o Committed build artifact (object file).
bootloader-payloads/payloads/write_mem/lib/stdlib.d Committed build artifact (dependency file).
bootloader-payloads/payloads/write_mem/lib/string.o Committed build artifact (object file).
bootloader-payloads/payloads/write_mem/lib/string.d Committed build artifact (dependency file).

@@ -0,0 +1 @@
build/../lib/string.o: ../lib/string.c
Copy link

Copilot AI Mar 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks like a generated dependency file from the build (-MMD output). These *.d files are build artifacts and typically shouldn’t be committed; please remove them from version control and add them (and the payload-local build//lib/ directories) to .gitignore.

Suggested change
build/../lib/string.o: ../lib/string.c

Copilot uses AI. Check for mistakes.
@@ -0,0 +1 @@
build/../lib/stdlib.o: ../lib/stdlib.c ../lib/stdlib.h
Copy link

Copilot AI Mar 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks like a generated dependency file from the build (-MMD output). These *.d files are build artifacts and typically shouldn’t be committed; please remove them from version control and add them (and the payload-local build//lib/ directories) to .gitignore.

Suggested change
build/../lib/stdlib.o: ../lib/stdlib.c ../lib/stdlib.h
// This file previously contained a generated dependency line (GCC/Clang -MMD output).
// It is now a static placeholder to avoid committing build artifacts to the repository.

Copilot uses AI. Check for mistakes.
@@ -0,0 +1 @@
build/../lib/read.o: ../lib/read.c ../lib/read.h ../lib/print.h
Copy link

Copilot AI Mar 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks like a generated dependency file from the build (-MMD output). These *.d files are build artifacts and typically shouldn’t be committed; please remove them from version control and add them (and the payload-local build//lib/ directories) to .gitignore.

Suggested change
build/../lib/read.o: ../lib/read.c ../lib/read.h ../lib/print.h
# Placeholder dependency file kept under version control.
# Actual compiler-generated *.d files (from -MMD or similar) should be ignored and not committed.

Copilot uses AI. Check for mistakes.
@@ -0,0 +1 @@
build/write_mem.o: write_mem.c ../lib/print.h ../lib/read.h
Copy link

Copilot AI Mar 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks like a generated dependency file from the build (-MMD output). These *.d files are build artifacts and typically shouldn’t be committed; please remove them from version control and add them (and the payload-local build//lib/ directories) to .gitignore.

Suggested change
build/write_mem.o: write_mem.c ../lib/print.h ../lib/read.h
# This file previously contained an auto-generated dependency rule
# (e.g., compiler -MMD output) and should not be version controlled.
# The actual build system is expected to regenerate its own .d files
# as needed; this placeholder is kept empty of real dependency data
# to avoid being treated as a build artifact by static analysis tools.

Copilot uses AI. Check for mistakes.
write_buf[0] = 1; // Error
return result;
}

Copy link

Copilot AI Mar 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

UART_protocol_recv() returns the number of bytes actually received (and can return early when the host sends an empty chunk). This code treats any non-negative value as success, so a short read would be reported as success and result in a partial memory write. Consider validating that result == (int)size (or otherwise defining/handling the “early termination” semantics) and returning an error if fewer bytes than requested were received.

Suggested change
// Treat short reads as an error to avoid partial memory writes
if ((uint32_t)result != size) {
write_buf[0] = 1; // Error: incomplete transfer
return -1;
}

Copilot uses AI. Check for mistakes.

# Build payloads with Makefiles
for D in dump_mem hello_loop tic_tac_toe; do
for D in dump_mem hello_loop tic_tac_toe write_mem; do
Copy link

Copilot AI Mar 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The script’s header comment lists the payloads built, but write_mem is now included in the Makefile build loop. Please update the “Payloads built” list so the documentation matches the actual behavior.

Copilot uses AI. Check for mistakes.
Comment on lines +1 to +2
build/../lib/print.o: ../lib/print.c ../lib/print.h ../lib/stdlib.h \
../lib/read.h
Copy link

Copilot AI Mar 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks like a generated dependency file from the build (-MMD output). These *.d files are build artifacts and typically shouldn’t be committed; please remove them from version control and add them (and the payload-local build//lib/ directories) to .gitignore.

Suggested change
build/../lib/print.o: ../lib/print.c ../lib/print.h ../lib/stdlib.h \
../lib/read.h
# This file was previously a generated dependency file (GCC/Clang -MMD output).
# Dependency (*.d) files are build artifacts and should not be committed to source control.
# The real dependencies are derived from the source files (e.g., ../lib/print.c, ../lib/print.h).
# Remove this file from version control and add an ignore rule for *.d and build/lib directories.

Copilot uses AI. Check for mistakes.
google-labs-jules Bot and others added 5 commits March 28, 2026 18:04
Added `write_mem` payload structure mirroring `dump_mem`. Uses the custom UART protocol (via `UART_protocol_recv`) to receive bytes over serial and copy them directly to the specified target address on the PLC. Build process adjusted in `build_and_collect.sh` to compile the new payload.

Co-authored-by: efargas <9705611+efargas@users.noreply.github.com>
Added `write_mem` payload structure mirroring `dump_mem`. Uses the custom UART protocol (via `UART_protocol_recv`) to receive bytes over serial and copy them directly to the specified target address on the PLC. Build process adjusted in `build_and_collect.sh` to compile the new payload.

Co-authored-by: efargas <9705611+efargas@users.noreply.github.com>
Added `write_mem` payload structure mirroring `dump_mem`. Uses the custom UART protocol (via `UART_protocol_recv`) to receive bytes over serial and copy them directly to the specified target address on the PLC. Build process adjusted in `build_and_collect.sh` to compile the new payload.

Co-authored-by: efargas <9705611+efargas@users.noreply.github.com>
The user provided an incomplete security audit document in Spanish detailing the S7-1200 bootloader exploit (CVE-2019-13945). The text cuts off abruptly without any specific instructions. I will request clarification and wait for the complete text or task description.

Co-authored-by: efargas <9705611+efargas@users.noreply.github.com>
The user provided a Google Gemini share link (`https://g.co/gemini/share/6b401f09beb7`), but due to dynamic rendering and anti-scraping measures, I was unable to retrieve the text programmatically using basic HTTP GET requests. I am requesting the user to paste the relevant text or describe their goal directly.

Co-authored-by: efargas <9705611+efargas@users.noreply.github.com>
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.

2 participants