Bug Summary

File:util/nvramtool/cmos_lowlevel.c
Warning:line 63, column 46
The result of the left shift is undefined due to shifting by '64', which is greater or equal to the width of type 'int'

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name cmos_lowlevel.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -pic-is-pie -mframe-pointer=all -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/home/coreboot/node-root/workspace/coreboot_scanbuild -resource-dir /opt/xgcc/lib/clang/17 -I /home/coreboot/node-root/workspace/coreboot_scanbuild/util/nvramtool -internal-isystem /opt/xgcc/lib/clang/17/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/13/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -source-date-epoch 1714465709 -fdebug-compilation-dir=/home/coreboot/node-root/workspace/coreboot_scanbuild -ferror-limit 19 -fgnuc-version=4.2.1 -analyzer-opt-analyze-headers -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /cb-build/coreboot_scanbuild.0/sharedutils-scanbuildtmp/2024-05-02-073004-2299942-1 -x c /home/coreboot/node-root/workspace/coreboot_scanbuild/util/nvramtool/cmos_lowlevel.c
1/* SPDX-License-Identifier: GPL-2.0-only */
2
3#if defined(__FreeBSD__)
4#include <fcntl.h>
5#include <unistd.h>
6#endif
7
8#include "common.h"
9#include "cmos_lowlevel.h"
10
11/* Hardware Abstraction Layer: lowlevel byte-wise write access */
12
13extern cmos_access_t cmos_hal, memory_hal;
14static cmos_access_t *current_access =
15#ifdef CMOS_HAL
16 &cmos_hal;
17#else
18 &memory_hal;
19#endif
20
21void select_hal(hal_t hal, void *data)
22{
23 switch(hal) {
24#ifdef CMOS_HAL
25 case HAL_CMOS:
26 current_access = &cmos_hal;
27 break;
28#endif
29 case HAL_MEMORY:
30 default:
31 current_access = &memory_hal;
32 break;
33 }
34 current_access->init(data);
35}
36
37/* Bit-level access */
38typedef struct {
39 unsigned byte_index;
40 unsigned bit_offset;
41} cmos_bit_op_location_t;
42
43static unsigned cmos_bit_op_strategy(unsigned bit, unsigned bits_left,
44 cmos_bit_op_location_t * where);
45static unsigned char cmos_read_bits(const cmos_bit_op_location_t * where,
46 unsigned nr_bits);
47static void cmos_write_bits(const cmos_bit_op_location_t * where,
48 unsigned nr_bits, unsigned char value);
49static unsigned char get_bits(unsigned long long value, unsigned bit,
50 unsigned nr_bits);
51static void put_bits(unsigned char value, unsigned bit, unsigned nr_bits,
52 unsigned long long *result);
53
54/****************************************************************************
55 * get_bits
56 *
57 * Extract a value 'nr_bits' bits wide starting at bit position 'bit' from
58 * 'value' and return the result. It is assumed that 'nr_bits' is at most 8.
59 ****************************************************************************/
60static inline unsigned char get_bits(unsigned long long value, unsigned bit,
61 unsigned nr_bits)
62{
63 return (value >> bit) & ((unsigned char)((1 << nr_bits) - 1));
16
The result of the left shift is undefined due to shifting by '64', which is greater or equal to the width of type 'int'
64}
65
66/****************************************************************************
67 * put_bits
68 *
69 * Extract the low order 'nr_bits' bits from 'value' and store them in the
70 * value pointed to by 'result' starting at bit position 'bit'. The bit
71 * positions in 'result' where the result is stored are assumed to be
72 * initially zero.
73 ****************************************************************************/
74static inline void put_bits(unsigned char value, unsigned bit,
75 unsigned nr_bits, unsigned long long *result)
76{
77 *result += ((unsigned long long)(value &
78 ((unsigned char)((1 << nr_bits) - 1)))) << bit;
79}
80
81/****************************************************************************
82 * cmos_read
83 *
84 * Read value from nonvolatile RAM at position given by 'bit' and 'length'
85 * and return this value. The I/O privilege level of the currently executing
86 * process must be set appropriately.
87 *
88 * Returned value is either (unsigned long long), or malloc()'d (char *)
89 * cast to (unsigned long long)
90 ****************************************************************************/
91unsigned long long cmos_read(const cmos_entry_t * e)
92{
93 cmos_bit_op_location_t where;
94 unsigned bit = e->bit, length = e->length;
95 unsigned next_bit, bits_left, nr_bits;
96 unsigned long long result = 0;
97 unsigned char value;
98
99 assert(!verify_cmos_op(bit, length, e->config))((void) sizeof ((!verify_cmos_op(bit, length, e->config)) ?
1 : 0), __extension__ ({ if (!verify_cmos_op(bit, length, e->
config)) ; else __assert_fail ("!verify_cmos_op(bit, length, e->config)"
, "/home/coreboot/node-root/workspace/coreboot_scanbuild/util/nvramtool/cmos_lowlevel.c"
, 99, __extension__ __PRETTY_FUNCTION__); }))
;
100
101 if (e->config == CMOS_ENTRY_STRING) {
102 int strsz = (length + 7) / 8 + 1;
103 char *newstring = malloc(strsz);
104 unsigned usize = (8 * sizeof(unsigned long long));
105
106 if (!newstring) {
107 out_of_memory();
108 }
109
110 memset(newstring, 0, strsz);
111
112 for (next_bit = 0, bits_left = length;
113 bits_left; next_bit += nr_bits, bits_left -= nr_bits) {
114 nr_bits = cmos_bit_op_strategy(bit + next_bit,
115 bits_left > usize ? usize : bits_left, &where);
116 value = cmos_read_bits(&where, nr_bits);
117 put_bits(value, next_bit % usize, nr_bits,
118 &((unsigned long long *)newstring)[next_bit /
119 usize]);
120 result = (unsigned long)newstring;
121 }
122 } else {
123 for (next_bit = 0, bits_left = length;
124 bits_left; next_bit += nr_bits, bits_left -= nr_bits) {
125 nr_bits =
126 cmos_bit_op_strategy(bit + next_bit, bits_left,
127 &where);
128 value = cmos_read_bits(&where, nr_bits);
129 put_bits(value, next_bit, nr_bits, &result);
130 }
131 }
132
133 return result;
134}
135
136/****************************************************************************
137 * cmos_write
138 *
139 * Write 'data' to nonvolatile RAM at position given by 'bit' and 'length'.
140 * The I/O privilege level of the currently executing process must be set
141 * appropriately.
142 ****************************************************************************/
143void cmos_write(const cmos_entry_t * e, unsigned long long value)
144{
145 cmos_bit_op_location_t where;
146 unsigned bit = e->bit, length = e->length;
147 unsigned next_bit, bits_left, nr_bits;
148
149 assert(!verify_cmos_op(bit, length, e->config))((void) sizeof ((!verify_cmos_op(bit, length, e->config)) ?
1 : 0), __extension__ ({ if (!verify_cmos_op(bit, length, e->
config)) ; else __assert_fail ("!verify_cmos_op(bit, length, e->config)"
, "/home/coreboot/node-root/workspace/coreboot_scanbuild/util/nvramtool/cmos_lowlevel.c"
, 149, __extension__ __PRETTY_FUNCTION__); }))
;
1
Taking true branch
150
151 if (e->config
1.1
Field 'config' is equal to CMOS_ENTRY_STRING
== CMOS_ENTRY_STRING) {
2
Taking true branch
152 unsigned long long *data =
153 (unsigned long long *)(unsigned long)value;
154 unsigned usize = (8 * sizeof(unsigned long long));
3
'usize' initialized to 64
155
156 for (next_bit = 0, bits_left = length;
4
Loop condition is true. Entering loop body
157 bits_left; next_bit += nr_bits, bits_left -= nr_bits) {
158 nr_bits = cmos_bit_op_strategy(bit + next_bit,
8
Calling 'cmos_bit_op_strategy'
12
Returning from 'cmos_bit_op_strategy'
13
The value 64 is assigned to 'nr_bits'
159 bits_left > usize ? usize : bits_left,
5
Assuming 'bits_left' is > 'usize'
6
'?' condition is true
7
Passing the value 64 via 2nd parameter 'bits_left'
160 &where);
161 value = data[next_bit / usize];
162 cmos_write_bits(&where, nr_bits,
163 get_bits(value, next_bit % usize, nr_bits));
14
Passing the value 64 via 3rd parameter 'nr_bits'
15
Calling 'get_bits'
164 }
165 } else {
166 for (next_bit = 0, bits_left = length;
167 bits_left; next_bit += nr_bits, bits_left -= nr_bits) {
168 nr_bits = cmos_bit_op_strategy(bit + next_bit,
169 bits_left, &where);
170 cmos_write_bits(&where, nr_bits,
171 get_bits(value, next_bit, nr_bits));
172 }
173 }
174}
175
176/****************************************************************************
177 * cmos_read_byte
178 *
179 * Read a byte from nonvolatile RAM at a position given by 'index' and return
180 * the result. An 'index' value of 0 represents the first byte of
181 * nonvolatile RAM.
182 *
183 * Note: the first 14 bytes of nonvolatile RAM provide an interface to the
184 * real time clock.
185 ****************************************************************************/
186unsigned char cmos_read_byte(unsigned index)
187{
188 return current_access->read(index);
189}
190
191/****************************************************************************
192 * cmos_write_byte
193 *
194 * Write 'value' to nonvolatile RAM at a position given by 'index'. An
195 * 'index' of 0 represents the first byte of nonvolatile RAM.
196 *
197 * Note: the first 14 bytes of nonvolatile RAM provide an interface to the
198 * real time clock. Writing to any of these bytes will therefore
199 * affect its functioning.
200 ****************************************************************************/
201void cmos_write_byte(unsigned index, unsigned char value)
202{
203 current_access->write(index, value);
204}
205
206/****************************************************************************
207 * cmos_read_all
208 *
209 * Read all contents of CMOS memory into array 'data'. The first 14 bytes of
210 * 'data' are set to zero since this corresponds to the real time clock area.
211 ****************************************************************************/
212void cmos_read_all(unsigned char data[])
213{
214 unsigned i;
215
216 for (i = 0; i < CMOS_RTC_AREA_SIZE14; i++)
217 data[i] = 0;
218
219 for (; i < CMOS_SIZE256; i++)
220 data[i] = cmos_read_byte(i);
221}
222
223/****************************************************************************
224 * cmos_write_all
225 *
226 * Update all of CMOS memory with the contents of array 'data'. The first 14
227 * bytes of 'data' are ignored since this corresponds to the real time clock
228 * area.
229 ****************************************************************************/
230void cmos_write_all(unsigned char data[])
231{
232 unsigned i;
233
234 for (i = CMOS_RTC_AREA_SIZE14; i < CMOS_SIZE256; i++)
235 cmos_write_byte(i, data[i]);
236}
237
238/****************************************************************************
239 * set_iopl
240 *
241 * Set the I/O privilege level of the executing process. Root privileges are
242 * required for performing this action. A sufficient I/O privilege level
243 * allows the process to access x86 I/O address space and to disable/reenable
244 * interrupts while executing in user space. Messing with the I/O privilege
245 * level is therefore somewhat dangerous.
246 ****************************************************************************/
247void set_iopl(int level)
248{
249 current_access->set_iopl(level);
250}
251
252/****************************************************************************
253 * verify_cmos_op
254 *
255 * 'bit' represents a bit position in the nonvolatile RAM. The first bit
256 * (i.e. the lowest order bit of the first byte) of nonvolatile RAM is
257 * labeled as bit 0. 'length' represents the width in bits of a value we
258 * wish to read or write. Perform sanity checking on 'bit' and 'length'. If
259 * no problems were encountered, return OK. Else return an error code.
260 ****************************************************************************/
261int verify_cmos_op(unsigned bit, unsigned length, cmos_entry_config_t config)
262{
263 if ((bit >= (8 * CMOS_SIZE256)) || ((bit + length) > (8 * CMOS_SIZE256)))
264 return CMOS_AREA_OUT_OF_RANGE(0x30000 + 0);
265
266 if (bit < (8 * CMOS_RTC_AREA_SIZE14))
267 return CMOS_AREA_OVERLAPS_RTC(0x30000 + 1);
268
269 if (config == CMOS_ENTRY_STRING)
270 return OK0;
271
272 if (length > (8 * sizeof(unsigned long long)))
273 return CMOS_AREA_TOO_WIDE(0x30000 + 2);
274
275 return OK0;
276}
277
278/****************************************************************************
279 * cmos_bit_op_strategy
280 *
281 * Helper function used by cmos_read() and cmos_write() to determine which
282 * bits to read or write next.
283 ****************************************************************************/
284static unsigned cmos_bit_op_strategy(unsigned bit, unsigned bits_left,
285 cmos_bit_op_location_t * where)
286{
287 unsigned max_bits;
288
289 where->byte_index = bit >> 3;
290 where->bit_offset = bit & 0x07;
291 max_bits = 8 - where->bit_offset;
292 return (bits_left > max_bits) ? max_bits : bits_left;
9
Assuming 'bits_left' is <= 'max_bits'
10
'?' condition is false
11
Returning the value 64
293}
294
295/****************************************************************************
296 * cmos_read_bits
297 *
298 * Read a chunk of bits from a byte location within CMOS memory. Return the
299 * value represented by the chunk of bits.
300 ****************************************************************************/
301static unsigned char cmos_read_bits(const cmos_bit_op_location_t * where,
302 unsigned nr_bits)
303{
304 return (cmos_read_byte(where->byte_index) >> where->bit_offset) &
305 ((unsigned char)((1 << nr_bits) - 1));
306}
307
308/****************************************************************************
309 * cmos_write_bits
310 *
311 * Write a chunk of bits (the low order 'nr_bits' bits of 'value') to an area
312 * within a particular byte of CMOS memory.
313 ****************************************************************************/
314static void cmos_write_bits(const cmos_bit_op_location_t * where,
315 unsigned nr_bits, unsigned char value)
316{
317 unsigned char n, mask;
318
319 if (nr_bits == 8) {
320 cmos_write_byte(where->byte_index, value);
321 return;
322 }
323
324 n = cmos_read_byte(where->byte_index);
325 mask = ((unsigned char)((1 << nr_bits) - 1)) << where->bit_offset;
326 n = (n & ~mask) + ((value << where->bit_offset) & mask);
327 cmos_write_byte(where->byte_index, n);
328}