1/*- 2 * Copyright (c) 2002 Poul-Henning Kamp 3 * Copyright (c) 2002 Networks Associates Technology, Inc. 4 * All rights reserved. 5 * 6 * This software was developed for the FreeBSD Project by Poul-Henning Kamp 7 * and NAI Labs, the Security Research Division of Network Associates, Inc. 8 * under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the 9 * DARPA CHATS research program. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 */ 32 33#include <sys/cdefs.h>
|
34__FBSDID("$FreeBSD: head/sys/geom/geom_mbr.c 118150 2003-07-29 10:09:13Z phk $");
|
34__FBSDID("$FreeBSD: head/sys/geom/geom_mbr.c 119660 2003-09-01 20:45:32Z phk $"); |
35 36#include <sys/param.h> 37#include <sys/errno.h> 38#include <sys/endian.h> 39#include <sys/systm.h> 40#include <sys/kernel.h> 41#include <sys/malloc.h> 42#include <sys/bio.h> 43#include <sys/lock.h> 44#include <sys/mutex.h> 45 46#include <sys/diskmbr.h> 47#include <sys/sbuf.h> 48#include <geom/geom.h> 49#include <geom/geom_slice.h> 50 51#define MBR_CLASS_NAME "MBR" 52#define MBREXT_CLASS_NAME "MBREXT" 53 54static struct dos_partition historical_bogus_partition_table[NDOSPART] = { 55 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, 56 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, 57 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, 58 { 0x80, 0, 1, 0, DOSPTYP_386BSD, 255, 255, 255, 0, 50000, }, 59}; 60 61static struct dos_partition historical_bogus_partition_table_fixed[NDOSPART] = { 62 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, 63 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, 64 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, 65 { 0x80, 0, 1, 0, DOSPTYP_386BSD, 254, 255, 255, 0, 50000, }, 66}; 67 68static void 69g_mbr_print(int i, struct dos_partition *dp) 70{ 71 72 printf("[%d] f:%02x typ:%d", i, dp->dp_flag, dp->dp_typ); 73 printf(" s(CHS):%d/%d/%d", DPCYL(dp->dp_scyl, dp->dp_ssect), 74 dp->dp_shd, DPSECT(dp->dp_ssect)); 75 printf(" e(CHS):%d/%d/%d", DPCYL(dp->dp_ecyl, dp->dp_esect), 76 dp->dp_ehd, DPSECT(dp->dp_esect)); 77 printf(" s:%d l:%d\n", dp->dp_start, dp->dp_size); 78} 79 80struct g_mbr_softc { 81 int type [NDOSPART]; 82 u_int sectorsize; 83 u_char sec0[512]; 84}; 85 86static int 87g_mbr_modify(struct g_geom *gp, struct g_mbr_softc *ms, u_char *sec0) 88{ 89 int i, error; 90 off_t l[NDOSPART]; 91 struct dos_partition ndp[NDOSPART], *dp; 92 93 g_topology_assert(); 94 95 if (sec0[0x1fe] != 0x55 && sec0[0x1ff] != 0xaa) 96 return (EBUSY); 97 98 dp = ndp; 99 for (i = 0; i < NDOSPART; i++) { 100 dos_partition_dec( 101 sec0 + DOSPARTOFF + i * sizeof(struct dos_partition), 102 dp + i); 103 if (bootverbose) 104 g_mbr_print(i, dp + i); 105 } 106 if ((!bcmp(dp, historical_bogus_partition_table, 107 sizeof historical_bogus_partition_table)) || 108 (!bcmp(dp, historical_bogus_partition_table_fixed, 109 sizeof historical_bogus_partition_table_fixed))) { 110 /* 111 * We will not allow people to write these from "the inside", 112 * Since properly selfdestructing takes too much code. If 113 * people really want to do this, they cannot have any 114 * providers of this geom open, and in that case they can just 115 * as easily overwrite the MBR in the parent device. 116 */ 117 return(EBUSY); 118 } 119 for (i = 0; i < NDOSPART; i++) { 120 /* 121 * A Protective MBR (PMBR) has a single partition of 122 * type 0xEE spanning the whole disk. Such a MBR 123 * protects a GPT on the disk from MBR tools that 124 * don't know anything about GPT. We're interpreting 125 * it a bit more loosely: any partition of type 0xEE 126 * is to be skipped as it doesn't contain any data 127 * that we should care about. We still allow other 128 * partitions to be present in the MBR. A PMBR will 129 * be handled correctly anyway. 130 */ 131 if (dp[i].dp_typ == DOSPTYP_PMBR) 132 l[i] = 0; 133 else if (dp[i].dp_flag != 0 && dp[i].dp_flag != 0x80) 134 l[i] = 0; 135 else if (dp[i].dp_typ == 0) 136 l[i] = 0; 137 else 138 l[i] = (off_t)dp[i].dp_size * ms->sectorsize; 139 error = g_slice_config(gp, i, G_SLICE_CONFIG_CHECK, 140 (off_t)dp[i].dp_start * ms->sectorsize, l[i], 141 ms->sectorsize, "%ss%d", gp->name, 1 + i); 142 if (error) 143 return (error); 144 } 145 for (i = 0; i < NDOSPART; i++) { 146 ms->type[i] = dp[i].dp_typ; 147 g_slice_config(gp, i, G_SLICE_CONFIG_SET, 148 (off_t)dp[i].dp_start * ms->sectorsize, l[i], 149 ms->sectorsize, "%ss%d", gp->name, 1 + i); 150 } 151 bcopy(sec0, ms->sec0, 512); 152 return (0); 153} 154
|
155static void
156g_mbr_ioctl(void *arg, int flag)
|
155static int 156g_mbr_ioctl(struct g_provider *pp, u_long cmd, void *data, struct thread *td) |
157{
|
158 struct bio *bp;
|
158 struct g_geom *gp;
|
160 struct g_slicer *gsp;
|
159 struct g_mbr_softc *ms;
|
162 struct g_ioctl *gio;
|
160 struct g_slicer *gsp; |
161 struct g_consumer *cp;
|
164 u_char *sec0;
|
162 int error; 163
|
167 bp = arg;
168 if (flag == EV_CANCEL) {
169 g_io_deliver(bp, ENXIO);
170 return;
171 }
172 gp = bp->bio_to->geom;
|
164 gp = pp->geom; |
165 gsp = gp->softc; 166 ms = gsp->softc;
|
175 gio = (struct g_ioctl *)bp->bio_data;
|
167
|
177 /* The disklabel to set is the ioctl argument. */
178 sec0 = gio->data;
179
180 error = g_mbr_modify(gp, ms, sec0);
181 if (error) {
182 g_io_deliver(bp, error);
183 return;
|
168 switch(cmd) { 169 case DIOCSMBR: { 170 DROP_GIANT(); 171 g_topology_lock(); 172 /* Validate and modify our slicer instance to match. */ 173 error = g_mbr_modify(gp, ms, data); 174 cp = LIST_FIRST(&gp->consumer); 175 error = g_write_data(cp, 0, data, 512); 176 g_topology_unlock(); 177 PICKUP_GIANT(); 178 return(error); |
179 }
|
185 cp = LIST_FIRST(&gp->consumer);
186 error = g_write_data(cp, 0, sec0, 512);
187 g_io_deliver(bp, error);
|
180 default: 181 return (ENOIOCTL); 182 } |
183} 184
|
190
|
185static int 186g_mbr_start(struct bio *bp) 187{ 188 struct g_provider *pp; 189 struct g_geom *gp; 190 struct g_mbr_softc *mp; 191 struct g_slicer *gsp;
|
198 struct g_ioctl *gio;
199 int idx, error;
|
192 int idx; |
193 194 pp = bp->bio_to; 195 idx = pp->index; 196 gp = pp->geom; 197 gsp = gp->softc; 198 mp = gsp->softc; 199 if (bp->bio_cmd == BIO_GETATTR) { 200 if (g_handleattr_int(bp, "MBR::type", mp->type[idx])) 201 return (1); 202 if (g_handleattr_off_t(bp, "MBR::offset", 203 gsp->slices[idx].offset)) 204 return (1); 205 } 206
|
214 /* We only handle ioctl(2) requests of the right format. */
215 if (strcmp(bp->bio_attribute, "GEOM::ioctl"))
216 return (0);
217 else if (bp->bio_length != sizeof(*gio))
218 return (0);
219
220 /* Get hold of the ioctl parameters. */
221 gio = (struct g_ioctl *)bp->bio_data;
222
223 switch (gio->cmd) {
224 case DIOCSMBR:
225 /*
226 * These we cannot do without the topology lock and some
227 * some I/O requests. Ask the event-handler to schedule
228 * us in a less restricted environment.
229 */
230 error = g_post_event(g_mbr_ioctl, bp, M_NOWAIT, gp, NULL);
231 if (error)
232 g_io_deliver(bp, error);
233 /*
234 * We must return non-zero to indicate that we will deal
235 * with this bio, even though we have not done so yet.
236 */
237 return (1);
238 default:
239 return (0);
240 }
|
207 return (0); |
208} 209 210static void 211g_mbr_dumpconf(struct sbuf *sb, const char *indent, struct g_geom *gp, struct g_consumer *cp __unused, struct g_provider *pp) 212{ 213 struct g_mbr_softc *mp; 214 struct g_slicer *gsp; 215 216 gsp = gp->softc; 217 mp = gsp->softc; 218 g_slice_dumpconf(sb, indent, gp, cp, pp); 219 if (pp != NULL) { 220 if (indent == NULL) 221 sbuf_printf(sb, " ty %d", mp->type[pp->index]); 222 else 223 sbuf_printf(sb, "%s<type>%d</type>\n", indent, 224 mp->type[pp->index]); 225 } 226} 227 228static struct g_geom * 229g_mbr_taste(struct g_class *mp, struct g_provider *pp, int insist) 230{ 231 struct g_geom *gp; 232 struct g_consumer *cp; 233 int error; 234 struct g_mbr_softc *ms; 235 u_int fwsectors, sectorsize; 236 u_char *buf; 237 238 g_trace(G_T_TOPOLOGY, "mbr_taste(%s,%s)", mp->name, pp->name); 239 g_topology_assert(); 240 gp = g_slice_new(mp, NDOSPART, pp, &cp, &ms, sizeof *ms, g_mbr_start); 241 if (gp == NULL) 242 return (NULL); 243 g_topology_unlock(); 244 gp->dumpconf = g_mbr_dumpconf;
|
245 gp->ioctl = g_mbr_ioctl; |
246 do { 247 if (gp->rank != 2 && insist == 0) 248 break; 249 error = g_getattr("GEOM::fwsectors", cp, &fwsectors); 250 if (error) 251 fwsectors = 17; 252 sectorsize = cp->provider->sectorsize; 253 if (sectorsize < 512) 254 break; 255 ms->sectorsize = sectorsize; 256 buf = g_read_data(cp, 0, sectorsize, &error); 257 if (buf == NULL || error != 0) 258 break; 259 g_topology_lock(); 260 g_mbr_modify(gp, ms, buf); 261 g_topology_unlock(); 262 g_free(buf); 263 break; 264 } while (0); 265 g_topology_lock(); 266 g_access_rel(cp, -1, 0, 0); 267 if (LIST_EMPTY(&gp->provider)) { 268 g_slice_spoiled(cp); 269 return (NULL); 270 } 271 return (gp); 272} 273 274static struct g_class g_mbr_class = { 275 .name = MBR_CLASS_NAME, 276 .taste = g_mbr_taste, 277}; 278 279DECLARE_GEOM_CLASS(g_mbr_class, g_mbr); 280 281#define NDOSEXTPART 32 282struct g_mbrext_softc { 283 int type [NDOSEXTPART]; 284}; 285 286static int 287g_mbrext_start(struct bio *bp) 288{ 289 struct g_provider *pp; 290 struct g_geom *gp; 291 struct g_mbrext_softc *mp; 292 struct g_slicer *gsp; 293 int idx; 294 295 pp = bp->bio_to; 296 idx = pp->index; 297 gp = pp->geom; 298 gsp = gp->softc; 299 mp = gsp->softc; 300 if (bp->bio_cmd == BIO_GETATTR) { 301 if (g_handleattr_int(bp, "MBR::type", mp->type[idx])) 302 return (1); 303 } 304 return (0); 305} 306 307static void 308g_mbrext_dumpconf(struct sbuf *sb, const char *indent, struct g_geom *gp, struct g_consumer *cp __unused, struct g_provider *pp) 309{ 310 struct g_mbrext_softc *mp; 311 struct g_slicer *gsp; 312 313 g_slice_dumpconf(sb, indent, gp, cp, pp); 314 gsp = gp->softc; 315 mp = gsp->softc; 316 if (pp != NULL) { 317 if (indent == NULL) 318 sbuf_printf(sb, " ty %d", mp->type[pp->index]); 319 else 320 sbuf_printf(sb, "%s<type>%d</type>\n", indent, 321 mp->type[pp->index]); 322 } 323} 324 325static struct g_geom * 326g_mbrext_taste(struct g_class *mp, struct g_provider *pp, int insist __unused) 327{ 328 struct g_geom *gp; 329 struct g_consumer *cp; 330 int error, i, slice; 331 struct g_mbrext_softc *ms; 332 off_t off; 333 u_char *buf; 334 struct dos_partition dp[4]; 335 u_int fwsectors, sectorsize; 336 337 g_trace(G_T_TOPOLOGY, "g_mbrext_taste(%s,%s)", mp->name, pp->name); 338 g_topology_assert(); 339 if (strcmp(pp->geom->class->name, MBR_CLASS_NAME)) 340 return (NULL); 341 gp = g_slice_new(mp, NDOSEXTPART, pp, &cp, &ms, sizeof *ms, 342 g_mbrext_start); 343 if (gp == NULL) 344 return (NULL); 345 g_topology_unlock(); 346 gp->dumpconf = g_mbrext_dumpconf; 347 off = 0; 348 slice = 0; 349 do { 350 error = g_getattr("MBR::type", cp, &i); 351 if (error || (i != DOSPTYP_EXT && i != DOSPTYP_EXTLBA)) 352 break; 353 error = g_getattr("GEOM::fwsectors", cp, &fwsectors); 354 if (error) 355 fwsectors = 17; 356 sectorsize = cp->provider->sectorsize; 357 if (sectorsize != 512) 358 break; 359 for (;;) { 360 buf = g_read_data(cp, off, sectorsize, &error); 361 if (buf == NULL || error != 0) 362 break; 363 if (buf[0x1fe] != 0x55 && buf[0x1ff] != 0xaa) { 364 g_free(buf); 365 break; 366 } 367 for (i = 0; i < NDOSPART; i++) 368 dos_partition_dec( 369 buf + DOSPARTOFF + 370 i * sizeof(struct dos_partition), dp + i); 371 g_free(buf); 372 if (bootverbose) { 373 printf("MBREXT Slice %d on %s:\n", 374 slice + 5, gp->name); 375 g_mbr_print(0, dp); 376 g_mbr_print(1, dp + 1); 377 } 378 if ((dp[0].dp_flag & 0x7f) == 0 && 379 dp[0].dp_size != 0 && dp[0].dp_typ != 0) { 380 g_topology_lock(); 381 g_slice_config(gp, slice, G_SLICE_CONFIG_SET, 382 (((off_t)dp[0].dp_start) << 9ULL) + off, 383 ((off_t)dp[0].dp_size) << 9ULL, 384 sectorsize, 385 "%*.*s%d", 386 strlen(gp->name) - 1, 387 strlen(gp->name) - 1, 388 gp->name, 389 slice + 5); 390 g_topology_unlock(); 391 ms->type[slice] = dp[0].dp_typ; 392 slice++; 393 } 394 if (dp[1].dp_flag != 0) 395 break; 396 if (dp[1].dp_typ != DOSPTYP_EXT && 397 dp[1].dp_typ != DOSPTYP_EXTLBA) 398 break; 399 if (dp[1].dp_size == 0) 400 break; 401 off = ((off_t)dp[1].dp_start) << 9ULL; 402 } 403 break; 404 } while (0); 405 g_topology_lock(); 406 g_access_rel(cp, -1, 0, 0); 407 if (LIST_EMPTY(&gp->provider)) { 408 g_slice_spoiled(cp); 409 return (NULL); 410 } 411 return (gp); 412} 413 414 415static struct g_class g_mbrext_class = { 416 .name = MBREXT_CLASS_NAME, 417 .taste = g_mbrext_taste, 418}; 419 420DECLARE_GEOM_CLASS(g_mbrext_class, g_mbrext);
|