1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
28 /*	  All Rights Reserved  	*/
29 
30 /*	Copyright (c) 1987, 1988 Microsoft Corporation	*/
31 /*	  All Rights Reserved	*/
32 
33 
34 #include <errno.h>
35 #include <libelf.h>
36 #include "decl.h"
37 #include "msg.h"
38 
39 /*
40  * Routines for generating a checksum for an elf image. Typically used to create
41  * a DT_CHECKSUM entry.  This checksum is intended to remain constant after
42  * operations such as strip(1)/mcs(1), thus only allocatable sections are
43  * processed, and of those, any that might be modified by these external
44  * commands are skipped.
45  */
46 #define	MSW(l)	(((l) >> 16) & 0x0000ffffL)
47 #define	LSW(l)	((l) & 0x0000ffffL)
48 
49 
50 /*
51  * update and epilogue sum functions (stolen from libcmd)
52  */
53 static long
sumupd(long sum,char * cp,unsigned long cnt)54 sumupd(long sum, char *cp, unsigned long cnt)
55 {
56 	if ((cp == 0) || (cnt == 0))
57 		return (sum);
58 
59 	while (cnt--)
60 		sum += *cp++ & 0x00ff;
61 
62 	return (sum);
63 }
64 
65 static long
sumepi(long sum)66 sumepi(long sum)
67 {
68 	long	_sum;
69 
70 	_sum = LSW(sum) + MSW(sum);
71 	return ((ushort_t)(LSW(_sum) + MSW(_sum)));
72 }
73 
74 /*
75  * This module is compiled twice, the second time having
76  * -D_ELF64 defined.  The following set of macros represent
77  * the differences between the two compilations.  Be
78  * careful *not* to add any class dependent code (anything
79  * that has elf32 or elf64 in the name) to this code
80  * without hiding it behind a switchable macro like these.
81  */
82 #if	defined(_ELF64)
83 
84 #define	elf_checksum		elf64_checksum
85 #define	Elf_Ehdr		Elf64_Ehdr
86 #define	Elf_Shdr		Elf64_Shdr
87 #define	getehdr			elf64_getehdr
88 #define	getshdr			elf64_getshdr
89 
90 #else	/* else ELF32 */
91 
92 #define	elf_checksum		elf32_checksum
93 #define	Elf_Ehdr		Elf32_Ehdr
94 #define	Elf_Shdr		Elf32_Shdr
95 #define	getehdr			elf32_getehdr
96 #define	getshdr			elf32_getshdr
97 
98 #endif	/* ELF64 */
99 
100 long
elf_checksum(Elf * elf)101 elf_checksum(Elf * elf)
102 {
103 	long		sum = 0;
104 	Elf_Ehdr *	ehdr;
105 	Elf_Shdr *	shdr;
106 	Elf_Scn *	scn;
107 	Elf_Data *	data, * (* getdata)(Elf_Scn *, Elf_Data *);
108 	size_t		shnum;
109 
110 	if ((ehdr = getehdr(elf)) == 0)
111 		return (0);
112 
113 	/*
114 	 * Determine the data information to retrieve.  When called from ld()
115 	 * we're processing an ELF_C_IMAGE (memory) image and thus need to use
116 	 * elf_getdata(), as there is not yet a file image (or raw data) backing
117 	 * this.  When called from utilities like elfdump(1) we're processing a
118 	 * file image and thus using the elf_rawdata() allows the same byte
119 	 * stream to be processed from different architectures - presently this
120 	 * is irrelevant, as the checksum simply sums the data bytes, their
121 	 * order doesn't matter.  But being uncooked is slightly less overhead.
122 	 *
123 	 * If the file is writable, the raw data will not reflect any
124 	 * changes made in the process, so the uncooked version is only
125 	 * for readonly files.
126 	 */
127 	if ((elf->ed_myflags & (EDF_MEMORY | EDF_WRITE)) != 0)
128 		getdata = elf_getdata;
129 	else
130 		getdata = elf_rawdata;
131 
132 	for (shnum = 1; shnum < ehdr->e_shnum; shnum++) {
133 		if ((scn = elf_getscn(elf, shnum)) == 0)
134 			return (0);
135 		if ((shdr = getshdr(scn)) == 0)
136 			return (0);
137 
138 		/* Exclude strippable sections */
139 		if (!(shdr->sh_flags & SHF_ALLOC))
140 			continue;
141 
142 		/*
143 		 * Exclude allocable sections that can change:
144 		 *	- The .dynsym section can contain section symbols
145 		 *		that strip might remove.
146 		 *	- The .dynamic section is modified by the setting of
147 		 *		this checksum value.
148 		 *	- The .SUNW_dof section uses ftok(3C), which returns
149 		 *		different values, to define a key for the
150 		 *		objects in that section.
151 		 */
152 		if ((shdr->sh_type == SHT_DYNSYM) ||
153 		    (shdr->sh_type == SHT_DYNAMIC) ||
154 		    (shdr->sh_type == SHT_SUNW_dof))
155 			continue;
156 
157 		data = 0;
158 		while ((data = (*getdata)(scn, data)) != 0)
159 			sum = sumupd(sum, data->d_buf, data->d_size);
160 
161 	}
162 	return (sumepi(sum));
163 }
164