File size: 4,757 Bytes
4f0bd4e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
/*
 * block_device.c — Simple block device with seek/read/write
 *
 * A small self-contained example for GRACE evaluation (Phase 4).
 *
 * Intentional bug:
 *   blk_seek() computes the new position as:
 *       dev->position = dev->position + offset
 *   When `dev->position` is close to SIZE_MAX and `offset` is large,
 *   this addition can overflow a size_t, wrapping around to a small value
 *   and bypassing the bounds check.
 */

#include <stddef.h>
#include <stdint.h>
#include <string.h>

/* ------------------------------------------------------------------ */
/* Data structures                                                      */
/* ------------------------------------------------------------------ */

#define BLK_BLOCK_SIZE 512

typedef struct {
    uint8_t *data;       /* backing storage                           */
    size_t   capacity;   /* total device size in bytes                */
    size_t   position;   /* current seek position                     */
    int      is_open;    /* 1 if open, 0 if closed                   */
    uint32_t error_flags;/* accumulated error flags                   */
} blk_dev_t;

/* Error codes */
#define BLK_OK           0
#define BLK_ERR_CLOSED  -1
#define BLK_ERR_BOUNDS  -2
#define BLK_ERR_NULL    -3

/* ------------------------------------------------------------------ */
/* Lifecycle                                                           */
/* ------------------------------------------------------------------ */

/*
 * blk_init — initialise a block device with a backing buffer.
 *
 * Precondition:  dev != NULL, data != NULL, size > 0
 * Postcondition: dev->is_open == 1, dev->position == 0
 */
int blk_init(blk_dev_t *dev, uint8_t *data, size_t size)
{
    if (dev == NULL || data == NULL)
        return BLK_ERR_NULL;

    dev->data        = data;
    dev->capacity    = size;
    dev->position    = 0;
    dev->is_open     = 1;
    dev->error_flags = 0;
    return BLK_OK;
}

/*
 * blk_close — close the block device.
 *
 * Precondition:  dev != NULL, dev->is_open == 1
 * Postcondition: dev->is_open == 0
 */
int blk_close(blk_dev_t *dev)
{
    if (dev == NULL)
        return BLK_ERR_NULL;
    if (!dev->is_open)
        return BLK_ERR_CLOSED;
    dev->is_open = 0;
    return BLK_OK;
}

/* ------------------------------------------------------------------ */
/* I/O operations                                                      */
/* ------------------------------------------------------------------ */

/*
 * blk_read — read `len` bytes from the device at the current position.
 *
 * Precondition:  dev != NULL, buf != NULL, dev->is_open == 1,
 *                dev->position + len <= dev->capacity
 * Postcondition: buf[0..len-1] filled with device data,
 *                dev->position advanced by len
 */
int blk_read(blk_dev_t *dev, uint8_t *buf, size_t len)
{
    if (dev == NULL || buf == NULL)
        return BLK_ERR_NULL;
    if (!dev->is_open)
        return BLK_ERR_CLOSED;
    if (dev->position + len > dev->capacity)
        return BLK_ERR_BOUNDS;

    memcpy(buf, dev->data + dev->position, len);
    dev->position += len;
    return BLK_OK;
}

/*
 * blk_write — write `len` bytes to the device at the current position.
 *
 * Precondition:  dev != NULL, data != NULL, dev->is_open == 1,
 *                dev->position + len <= dev->capacity
 * Postcondition: device data updated, dev->position advanced by len
 */
int blk_write(blk_dev_t *dev, const uint8_t *data, size_t len)
{
    if (dev == NULL || data == NULL)
        return BLK_ERR_NULL;
    if (!dev->is_open)
        return BLK_ERR_CLOSED;
    if (dev->position + len > dev->capacity)
        return BLK_ERR_BOUNDS;

    memcpy(dev->data + dev->position, data, len);
    dev->position += len;
    return BLK_OK;
}

/*
 * blk_seek — seek to a position relative to the current position.
 *
 * Precondition:  dev != NULL, dev->is_open == 1,
 *                0 <= dev->position + offset <= dev->capacity
 * Postcondition: dev->position == old(dev->position) + offset
 *
 * BUG: the addition `dev->position + offset` can overflow size_t when
 *      both values are large. The overflow wraps around to a small value,
 *      bypassing the `new_pos > dev->capacity` check and resulting in
 *      an out-of-bounds position that corrupts subsequent reads/writes.
 */
int blk_seek(blk_dev_t *dev, size_t offset)
{
    if (dev == NULL)
        return BLK_ERR_NULL;
    if (!dev->is_open)
        return BLK_ERR_CLOSED;

    /* BUG: integer overflow when dev->position + offset wraps around */
    size_t new_pos = dev->position + offset;   /* <-- intentional overflow bug */
    if (new_pos > dev->capacity)
        return BLK_ERR_BOUNDS;

    dev->position = new_pos;
    return BLK_OK;
}