1 /*
2 checksum.c - implementation of the elf{32,64}_checksum(3) functions.
3 Copyright (C) 1995 - 2001 Michael Riepe
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public
7 License as published by the Free Software Foundation; either
8 version 2 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
14
15 You should have received a copy of the GNU Library General Public
16 License along with this library; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
18 */
19
20 #include <private.h>
21
22 #ifndef lint
23 static const char rcsid[] = "@(#) $Id: checksum.c,v 1.7 2008/05/23 08:15:34 michael Exp $";
24 #endif /* lint */
25
26 /*
27 * Compatibility note:
28 *
29 * The algorithm used in {elf32,elf64,gelf}_checksum() does not seem to
30 * be documented. I hope I got it right. My implementation does the
31 * following:
32 *
33 * - skip sections that do not have the SHF_ALLOC flag set
34 * - skip sections of type SHT_NULL, SHT_NOBITS, SHT_DYNSYM and
35 * SHT_DYNAMIC
36 * - add all data bytes from the remaining sections, modulo 2**32
37 * - add upper and lower half of the result
38 * - subtract 0xffff if the result is > 0xffff
39 * - if any error occurs, return 0L
40 */
41
42 static int
skip_section(Elf_Scn * scn,unsigned cls)43 skip_section(Elf_Scn *scn, unsigned cls) {
44 if (cls == ELFCLASS32) {
45 Elf32_Shdr *shdr = &scn->s_shdr32;
46
47 if (!(shdr->sh_flags & SHF_ALLOC)) {
48 return 1;
49 }
50 switch (shdr->sh_type) {
51 case SHT_NULL:
52 case SHT_NOBITS:
53 /* Solaris seems to ignore these, too */
54 case SHT_DYNSYM:
55 case SHT_DYNAMIC:
56 return 1;
57 }
58 }
59 #if __LIBELF64
60 else if (cls == ELFCLASS64) {
61 Elf64_Shdr *shdr = &scn->s_shdr64;
62
63 if (!(shdr->sh_flags & SHF_ALLOC)) {
64 return 1;
65 }
66 switch (shdr->sh_type) {
67 case SHT_NULL:
68 case SHT_NOBITS:
69 /* Solaris seems to ignore these, too */
70 case SHT_DYNSYM:
71 case SHT_DYNAMIC:
72 return 1;
73 }
74 }
75 #endif /* __LIBELF64 */
76 else {
77 seterr(ERROR_UNIMPLEMENTED);
78 }
79 return 0;
80 }
81
82 static long
add_bytes(unsigned char * ptr,size_t len)83 add_bytes(unsigned char *ptr, size_t len) {
84 long csum = 0;
85
86 while (len--) {
87 csum += *ptr++;
88 }
89 return csum;
90 }
91
92 static long
_elf_csum(Elf * elf)93 _elf_csum(Elf *elf) {
94 long csum = 0;
95 Elf_Data *data;
96 Elf_Scn *scn;
97
98 if (!elf->e_ehdr && !_elf_cook(elf)) {
99 /* propagate errors from _elf_cook */
100 return 0L;
101 }
102 seterr(0);
103 for (scn = elf->e_scn_1; scn; scn = scn->s_link) {
104 if (scn->s_index == SHN_UNDEF || skip_section(scn, elf->e_class)) {
105 continue;
106 }
107 data = NULL;
108 while ((data = elf_getdata(scn, data))) {
109 if (data->d_size) {
110 if (data->d_buf == NULL) {
111 seterr(ERROR_NULLBUF);
112 return 0L;
113 }
114 csum += add_bytes(data->d_buf, data->d_size);
115 }
116 }
117 }
118 if (_elf_errno) {
119 return 0L;
120 }
121 csum = (csum & 0xffff) + ((csum >> 16) & 0xffff);
122 if (csum > 0xffff) {
123 csum -= 0xffff;
124 }
125 return csum;
126 }
127
128 long
elf32_checksum(Elf * elf)129 elf32_checksum(Elf *elf) {
130 if (elf) {
131 if (elf->e_kind != ELF_K_ELF) {
132 seterr(ERROR_NOTELF);
133 }
134 else if (elf->e_class != ELFCLASS32) {
135 seterr(ERROR_CLASSMISMATCH);
136 }
137 else {
138 return _elf_csum(elf);
139 }
140 }
141 return 0L;
142 }
143
144 #if __LIBELF64
145
146 long
elf64_checksum(Elf * elf)147 elf64_checksum(Elf *elf) {
148 if (elf) {
149 if (elf->e_kind != ELF_K_ELF) {
150 seterr(ERROR_NOTELF);
151 }
152 else if (elf->e_class != ELFCLASS64) {
153 seterr(ERROR_CLASSMISMATCH);
154 }
155 else {
156 return _elf_csum(elf);
157 }
158 }
159 return 0L;
160 }
161
162 long
gelf_checksum(Elf * elf)163 gelf_checksum(Elf *elf) {
164 if (elf) {
165 if (elf->e_kind != ELF_K_ELF) {
166 seterr(ERROR_NOTELF);
167 }
168 else if (!valid_class(elf->e_class)) {
169 seterr(ERROR_UNKNOWN_CLASS);
170 }
171 else {
172 return _elf_csum(elf);
173 }
174 }
175 return 0L;
176 }
177
178 #endif /* __LIBELF64 */
179