11da177e4SLinus Torvalds /* xfrm_user.c: User interface to configure xfrm engine. 21da177e4SLinus Torvalds * 31da177e4SLinus Torvalds * Copyright (C) 2002 David S. Miller (davem@redhat.com) 41da177e4SLinus Torvalds * 51da177e4SLinus Torvalds * Changes: 61da177e4SLinus Torvalds * Mitsuru KANDA @USAGI 71da177e4SLinus Torvalds * Kazunori MIYAZAWA @USAGI 81da177e4SLinus Torvalds * Kunihiro Ishiguro <kunihiro@ipinfusion.com> 91da177e4SLinus Torvalds * IPv6 support 101da177e4SLinus Torvalds * 111da177e4SLinus Torvalds */ 121da177e4SLinus Torvalds 139409f38aSHerbert Xu #include <linux/crypto.h> 141da177e4SLinus Torvalds #include <linux/module.h> 151da177e4SLinus Torvalds #include <linux/kernel.h> 161da177e4SLinus Torvalds #include <linux/types.h> 171da177e4SLinus Torvalds #include <linux/slab.h> 181da177e4SLinus Torvalds #include <linux/socket.h> 191da177e4SLinus Torvalds #include <linux/string.h> 201da177e4SLinus Torvalds #include <linux/net.h> 211da177e4SLinus Torvalds #include <linux/skbuff.h> 221da177e4SLinus Torvalds #include <linux/rtnetlink.h> 231da177e4SLinus Torvalds #include <linux/pfkeyv2.h> 241da177e4SLinus Torvalds #include <linux/ipsec.h> 251da177e4SLinus Torvalds #include <linux/init.h> 261da177e4SLinus Torvalds #include <linux/security.h> 271da177e4SLinus Torvalds #include <net/sock.h> 281da177e4SLinus Torvalds #include <net/xfrm.h> 2988fc2c84SThomas Graf #include <net/netlink.h> 301da177e4SLinus Torvalds #include <asm/uaccess.h> 31e23c7194SMasahide NAKAMURA #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 32e23c7194SMasahide NAKAMURA #include <linux/in6.h> 33e23c7194SMasahide NAKAMURA #endif 341da177e4SLinus Torvalds 351da177e4SLinus Torvalds static int verify_one_alg(struct rtattr **xfrma, enum xfrm_attr_type_t type) 361da177e4SLinus Torvalds { 371da177e4SLinus Torvalds struct rtattr *rt = xfrma[type - 1]; 381da177e4SLinus Torvalds struct xfrm_algo *algp; 3931c26852SHerbert Xu int len; 401da177e4SLinus Torvalds 411da177e4SLinus Torvalds if (!rt) 421da177e4SLinus Torvalds return 0; 431da177e4SLinus Torvalds 4431c26852SHerbert Xu len = (rt->rta_len - sizeof(*rt)) - sizeof(*algp); 4531c26852SHerbert Xu if (len < 0) 461da177e4SLinus Torvalds return -EINVAL; 471da177e4SLinus Torvalds 481da177e4SLinus Torvalds algp = RTA_DATA(rt); 4931c26852SHerbert Xu 5031c26852SHerbert Xu len -= (algp->alg_key_len + 7U) / 8; 5131c26852SHerbert Xu if (len < 0) 5231c26852SHerbert Xu return -EINVAL; 5331c26852SHerbert Xu 541da177e4SLinus Torvalds switch (type) { 551da177e4SLinus Torvalds case XFRMA_ALG_AUTH: 561da177e4SLinus Torvalds if (!algp->alg_key_len && 571da177e4SLinus Torvalds strcmp(algp->alg_name, "digest_null") != 0) 581da177e4SLinus Torvalds return -EINVAL; 591da177e4SLinus Torvalds break; 601da177e4SLinus Torvalds 611da177e4SLinus Torvalds case XFRMA_ALG_CRYPT: 621da177e4SLinus Torvalds if (!algp->alg_key_len && 631da177e4SLinus Torvalds strcmp(algp->alg_name, "cipher_null") != 0) 641da177e4SLinus Torvalds return -EINVAL; 651da177e4SLinus Torvalds break; 661da177e4SLinus Torvalds 671da177e4SLinus Torvalds case XFRMA_ALG_COMP: 681da177e4SLinus Torvalds /* Zero length keys are legal. */ 691da177e4SLinus Torvalds break; 701da177e4SLinus Torvalds 711da177e4SLinus Torvalds default: 721da177e4SLinus Torvalds return -EINVAL; 731da177e4SLinus Torvalds }; 741da177e4SLinus Torvalds 751da177e4SLinus Torvalds algp->alg_name[CRYPTO_MAX_ALG_NAME - 1] = '\0'; 761da177e4SLinus Torvalds return 0; 771da177e4SLinus Torvalds } 781da177e4SLinus Torvalds 791da177e4SLinus Torvalds static int verify_encap_tmpl(struct rtattr **xfrma) 801da177e4SLinus Torvalds { 811da177e4SLinus Torvalds struct rtattr *rt = xfrma[XFRMA_ENCAP - 1]; 821da177e4SLinus Torvalds struct xfrm_encap_tmpl *encap; 831da177e4SLinus Torvalds 841da177e4SLinus Torvalds if (!rt) 851da177e4SLinus Torvalds return 0; 861da177e4SLinus Torvalds 871da177e4SLinus Torvalds if ((rt->rta_len - sizeof(*rt)) < sizeof(*encap)) 881da177e4SLinus Torvalds return -EINVAL; 891da177e4SLinus Torvalds 901da177e4SLinus Torvalds return 0; 911da177e4SLinus Torvalds } 921da177e4SLinus Torvalds 93eb2971b6SMasahide NAKAMURA static int verify_one_addr(struct rtattr **xfrma, enum xfrm_attr_type_t type, 94eb2971b6SMasahide NAKAMURA xfrm_address_t **addrp) 95eb2971b6SMasahide NAKAMURA { 96eb2971b6SMasahide NAKAMURA struct rtattr *rt = xfrma[type - 1]; 97eb2971b6SMasahide NAKAMURA 98eb2971b6SMasahide NAKAMURA if (!rt) 99eb2971b6SMasahide NAKAMURA return 0; 100eb2971b6SMasahide NAKAMURA 101eb2971b6SMasahide NAKAMURA if ((rt->rta_len - sizeof(*rt)) < sizeof(**addrp)) 102eb2971b6SMasahide NAKAMURA return -EINVAL; 103eb2971b6SMasahide NAKAMURA 104eb2971b6SMasahide NAKAMURA if (addrp) 105eb2971b6SMasahide NAKAMURA *addrp = RTA_DATA(rt); 106eb2971b6SMasahide NAKAMURA 107eb2971b6SMasahide NAKAMURA return 0; 108eb2971b6SMasahide NAKAMURA } 109df71837dSTrent Jaeger 110df71837dSTrent Jaeger static inline int verify_sec_ctx_len(struct rtattr **xfrma) 111df71837dSTrent Jaeger { 112df71837dSTrent Jaeger struct rtattr *rt = xfrma[XFRMA_SEC_CTX - 1]; 113df71837dSTrent Jaeger struct xfrm_user_sec_ctx *uctx; 114df71837dSTrent Jaeger int len = 0; 115df71837dSTrent Jaeger 116df71837dSTrent Jaeger if (!rt) 117df71837dSTrent Jaeger return 0; 118df71837dSTrent Jaeger 119df71837dSTrent Jaeger if (rt->rta_len < sizeof(*uctx)) 120df71837dSTrent Jaeger return -EINVAL; 121df71837dSTrent Jaeger 122df71837dSTrent Jaeger uctx = RTA_DATA(rt); 123df71837dSTrent Jaeger 124df71837dSTrent Jaeger len += sizeof(struct xfrm_user_sec_ctx); 125df71837dSTrent Jaeger len += uctx->ctx_len; 126df71837dSTrent Jaeger 127df71837dSTrent Jaeger if (uctx->len != len) 128df71837dSTrent Jaeger return -EINVAL; 129df71837dSTrent Jaeger 130df71837dSTrent Jaeger return 0; 131df71837dSTrent Jaeger } 132df71837dSTrent Jaeger 133df71837dSTrent Jaeger 1341da177e4SLinus Torvalds static int verify_newsa_info(struct xfrm_usersa_info *p, 1351da177e4SLinus Torvalds struct rtattr **xfrma) 1361da177e4SLinus Torvalds { 1371da177e4SLinus Torvalds int err; 1381da177e4SLinus Torvalds 1391da177e4SLinus Torvalds err = -EINVAL; 1401da177e4SLinus Torvalds switch (p->family) { 1411da177e4SLinus Torvalds case AF_INET: 1421da177e4SLinus Torvalds break; 1431da177e4SLinus Torvalds 1441da177e4SLinus Torvalds case AF_INET6: 1451da177e4SLinus Torvalds #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 1461da177e4SLinus Torvalds break; 1471da177e4SLinus Torvalds #else 1481da177e4SLinus Torvalds err = -EAFNOSUPPORT; 1491da177e4SLinus Torvalds goto out; 1501da177e4SLinus Torvalds #endif 1511da177e4SLinus Torvalds 1521da177e4SLinus Torvalds default: 1531da177e4SLinus Torvalds goto out; 1541da177e4SLinus Torvalds }; 1551da177e4SLinus Torvalds 1561da177e4SLinus Torvalds err = -EINVAL; 1571da177e4SLinus Torvalds switch (p->id.proto) { 1581da177e4SLinus Torvalds case IPPROTO_AH: 1591da177e4SLinus Torvalds if (!xfrma[XFRMA_ALG_AUTH-1] || 1601da177e4SLinus Torvalds xfrma[XFRMA_ALG_CRYPT-1] || 1611da177e4SLinus Torvalds xfrma[XFRMA_ALG_COMP-1]) 1621da177e4SLinus Torvalds goto out; 1631da177e4SLinus Torvalds break; 1641da177e4SLinus Torvalds 1651da177e4SLinus Torvalds case IPPROTO_ESP: 1661da177e4SLinus Torvalds if ((!xfrma[XFRMA_ALG_AUTH-1] && 1671da177e4SLinus Torvalds !xfrma[XFRMA_ALG_CRYPT-1]) || 1681da177e4SLinus Torvalds xfrma[XFRMA_ALG_COMP-1]) 1691da177e4SLinus Torvalds goto out; 1701da177e4SLinus Torvalds break; 1711da177e4SLinus Torvalds 1721da177e4SLinus Torvalds case IPPROTO_COMP: 1731da177e4SLinus Torvalds if (!xfrma[XFRMA_ALG_COMP-1] || 1741da177e4SLinus Torvalds xfrma[XFRMA_ALG_AUTH-1] || 1751da177e4SLinus Torvalds xfrma[XFRMA_ALG_CRYPT-1]) 1761da177e4SLinus Torvalds goto out; 1771da177e4SLinus Torvalds break; 1781da177e4SLinus Torvalds 179e23c7194SMasahide NAKAMURA #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 180e23c7194SMasahide NAKAMURA case IPPROTO_DSTOPTS: 181e23c7194SMasahide NAKAMURA case IPPROTO_ROUTING: 182e23c7194SMasahide NAKAMURA if (xfrma[XFRMA_ALG_COMP-1] || 183e23c7194SMasahide NAKAMURA xfrma[XFRMA_ALG_AUTH-1] || 184e23c7194SMasahide NAKAMURA xfrma[XFRMA_ALG_CRYPT-1] || 185e23c7194SMasahide NAKAMURA xfrma[XFRMA_ENCAP-1] || 186e23c7194SMasahide NAKAMURA xfrma[XFRMA_SEC_CTX-1] || 187e23c7194SMasahide NAKAMURA !xfrma[XFRMA_COADDR-1]) 188e23c7194SMasahide NAKAMURA goto out; 189e23c7194SMasahide NAKAMURA break; 190e23c7194SMasahide NAKAMURA #endif 191e23c7194SMasahide NAKAMURA 1921da177e4SLinus Torvalds default: 1931da177e4SLinus Torvalds goto out; 1941da177e4SLinus Torvalds }; 1951da177e4SLinus Torvalds 1961da177e4SLinus Torvalds if ((err = verify_one_alg(xfrma, XFRMA_ALG_AUTH))) 1971da177e4SLinus Torvalds goto out; 1981da177e4SLinus Torvalds if ((err = verify_one_alg(xfrma, XFRMA_ALG_CRYPT))) 1991da177e4SLinus Torvalds goto out; 2001da177e4SLinus Torvalds if ((err = verify_one_alg(xfrma, XFRMA_ALG_COMP))) 2011da177e4SLinus Torvalds goto out; 2021da177e4SLinus Torvalds if ((err = verify_encap_tmpl(xfrma))) 2031da177e4SLinus Torvalds goto out; 204df71837dSTrent Jaeger if ((err = verify_sec_ctx_len(xfrma))) 205df71837dSTrent Jaeger goto out; 206060f02a3SNoriaki TAKAMIYA if ((err = verify_one_addr(xfrma, XFRMA_COADDR, NULL))) 207060f02a3SNoriaki TAKAMIYA goto out; 2081da177e4SLinus Torvalds 2091da177e4SLinus Torvalds err = -EINVAL; 2101da177e4SLinus Torvalds switch (p->mode) { 2117e49e6deSMasahide NAKAMURA case XFRM_MODE_TRANSPORT: 2127e49e6deSMasahide NAKAMURA case XFRM_MODE_TUNNEL: 213060f02a3SNoriaki TAKAMIYA case XFRM_MODE_ROUTEOPTIMIZATION: 214*0a69452cSDiego Beltrami case XFRM_MODE_BEET: 2151da177e4SLinus Torvalds break; 2161da177e4SLinus Torvalds 2171da177e4SLinus Torvalds default: 2181da177e4SLinus Torvalds goto out; 2191da177e4SLinus Torvalds }; 2201da177e4SLinus Torvalds 2211da177e4SLinus Torvalds err = 0; 2221da177e4SLinus Torvalds 2231da177e4SLinus Torvalds out: 2241da177e4SLinus Torvalds return err; 2251da177e4SLinus Torvalds } 2261da177e4SLinus Torvalds 2271da177e4SLinus Torvalds static int attach_one_algo(struct xfrm_algo **algpp, u8 *props, 2281da177e4SLinus Torvalds struct xfrm_algo_desc *(*get_byname)(char *, int), 2291da177e4SLinus Torvalds struct rtattr *u_arg) 2301da177e4SLinus Torvalds { 2311da177e4SLinus Torvalds struct rtattr *rta = u_arg; 2321da177e4SLinus Torvalds struct xfrm_algo *p, *ualg; 2331da177e4SLinus Torvalds struct xfrm_algo_desc *algo; 234b9e9deadSHerbert Xu int len; 2351da177e4SLinus Torvalds 2361da177e4SLinus Torvalds if (!rta) 2371da177e4SLinus Torvalds return 0; 2381da177e4SLinus Torvalds 2391da177e4SLinus Torvalds ualg = RTA_DATA(rta); 2401da177e4SLinus Torvalds 2411da177e4SLinus Torvalds algo = get_byname(ualg->alg_name, 1); 2421da177e4SLinus Torvalds if (!algo) 2431da177e4SLinus Torvalds return -ENOSYS; 2441da177e4SLinus Torvalds *props = algo->desc.sadb_alg_id; 2451da177e4SLinus Torvalds 246b9e9deadSHerbert Xu len = sizeof(*ualg) + (ualg->alg_key_len + 7U) / 8; 247b9e9deadSHerbert Xu p = kmalloc(len, GFP_KERNEL); 2481da177e4SLinus Torvalds if (!p) 2491da177e4SLinus Torvalds return -ENOMEM; 2501da177e4SLinus Torvalds 251b9e9deadSHerbert Xu memcpy(p, ualg, len); 25204ff1260SHerbert Xu strcpy(p->alg_name, algo->name); 2531da177e4SLinus Torvalds *algpp = p; 2541da177e4SLinus Torvalds return 0; 2551da177e4SLinus Torvalds } 2561da177e4SLinus Torvalds 2571da177e4SLinus Torvalds static int attach_encap_tmpl(struct xfrm_encap_tmpl **encapp, struct rtattr *u_arg) 2581da177e4SLinus Torvalds { 2591da177e4SLinus Torvalds struct rtattr *rta = u_arg; 2601da177e4SLinus Torvalds struct xfrm_encap_tmpl *p, *uencap; 2611da177e4SLinus Torvalds 2621da177e4SLinus Torvalds if (!rta) 2631da177e4SLinus Torvalds return 0; 2641da177e4SLinus Torvalds 2651da177e4SLinus Torvalds uencap = RTA_DATA(rta); 2661da177e4SLinus Torvalds p = kmalloc(sizeof(*p), GFP_KERNEL); 2671da177e4SLinus Torvalds if (!p) 2681da177e4SLinus Torvalds return -ENOMEM; 2691da177e4SLinus Torvalds 2701da177e4SLinus Torvalds memcpy(p, uencap, sizeof(*p)); 2711da177e4SLinus Torvalds *encapp = p; 2721da177e4SLinus Torvalds return 0; 2731da177e4SLinus Torvalds } 2741da177e4SLinus Torvalds 275df71837dSTrent Jaeger 276df71837dSTrent Jaeger static inline int xfrm_user_sec_ctx_size(struct xfrm_policy *xp) 277df71837dSTrent Jaeger { 278df71837dSTrent Jaeger struct xfrm_sec_ctx *xfrm_ctx = xp->security; 279df71837dSTrent Jaeger int len = 0; 280df71837dSTrent Jaeger 281df71837dSTrent Jaeger if (xfrm_ctx) { 282df71837dSTrent Jaeger len += sizeof(struct xfrm_user_sec_ctx); 283df71837dSTrent Jaeger len += xfrm_ctx->ctx_len; 284df71837dSTrent Jaeger } 285df71837dSTrent Jaeger return len; 286df71837dSTrent Jaeger } 287df71837dSTrent Jaeger 288df71837dSTrent Jaeger static int attach_sec_ctx(struct xfrm_state *x, struct rtattr *u_arg) 289df71837dSTrent Jaeger { 290df71837dSTrent Jaeger struct xfrm_user_sec_ctx *uctx; 291df71837dSTrent Jaeger 292df71837dSTrent Jaeger if (!u_arg) 293df71837dSTrent Jaeger return 0; 294df71837dSTrent Jaeger 295df71837dSTrent Jaeger uctx = RTA_DATA(u_arg); 296df71837dSTrent Jaeger return security_xfrm_state_alloc(x, uctx); 297df71837dSTrent Jaeger } 298df71837dSTrent Jaeger 299060f02a3SNoriaki TAKAMIYA static int attach_one_addr(xfrm_address_t **addrpp, struct rtattr *u_arg) 300060f02a3SNoriaki TAKAMIYA { 301060f02a3SNoriaki TAKAMIYA struct rtattr *rta = u_arg; 302060f02a3SNoriaki TAKAMIYA xfrm_address_t *p, *uaddrp; 303060f02a3SNoriaki TAKAMIYA 304060f02a3SNoriaki TAKAMIYA if (!rta) 305060f02a3SNoriaki TAKAMIYA return 0; 306060f02a3SNoriaki TAKAMIYA 307060f02a3SNoriaki TAKAMIYA uaddrp = RTA_DATA(rta); 308060f02a3SNoriaki TAKAMIYA p = kmalloc(sizeof(*p), GFP_KERNEL); 309060f02a3SNoriaki TAKAMIYA if (!p) 310060f02a3SNoriaki TAKAMIYA return -ENOMEM; 311060f02a3SNoriaki TAKAMIYA 312060f02a3SNoriaki TAKAMIYA memcpy(p, uaddrp, sizeof(*p)); 313060f02a3SNoriaki TAKAMIYA *addrpp = p; 314060f02a3SNoriaki TAKAMIYA return 0; 315060f02a3SNoriaki TAKAMIYA } 316060f02a3SNoriaki TAKAMIYA 3171da177e4SLinus Torvalds static void copy_from_user_state(struct xfrm_state *x, struct xfrm_usersa_info *p) 3181da177e4SLinus Torvalds { 3191da177e4SLinus Torvalds memcpy(&x->id, &p->id, sizeof(x->id)); 3201da177e4SLinus Torvalds memcpy(&x->sel, &p->sel, sizeof(x->sel)); 3211da177e4SLinus Torvalds memcpy(&x->lft, &p->lft, sizeof(x->lft)); 3221da177e4SLinus Torvalds x->props.mode = p->mode; 3231da177e4SLinus Torvalds x->props.replay_window = p->replay_window; 3241da177e4SLinus Torvalds x->props.reqid = p->reqid; 3251da177e4SLinus Torvalds x->props.family = p->family; 3261da177e4SLinus Torvalds x->props.saddr = p->saddr; 3271da177e4SLinus Torvalds x->props.flags = p->flags; 3281da177e4SLinus Torvalds } 3291da177e4SLinus Torvalds 330d51d081dSJamal Hadi Salim /* 331d51d081dSJamal Hadi Salim * someday when pfkey also has support, we could have the code 332d51d081dSJamal Hadi Salim * somehow made shareable and move it to xfrm_state.c - JHS 333d51d081dSJamal Hadi Salim * 334d51d081dSJamal Hadi Salim */ 335d51d081dSJamal Hadi Salim static int xfrm_update_ae_params(struct xfrm_state *x, struct rtattr **xfrma) 336d51d081dSJamal Hadi Salim { 337d51d081dSJamal Hadi Salim int err = - EINVAL; 338d51d081dSJamal Hadi Salim struct rtattr *rp = xfrma[XFRMA_REPLAY_VAL-1]; 339d51d081dSJamal Hadi Salim struct rtattr *lt = xfrma[XFRMA_LTIME_VAL-1]; 340d51d081dSJamal Hadi Salim struct rtattr *et = xfrma[XFRMA_ETIMER_THRESH-1]; 341d51d081dSJamal Hadi Salim struct rtattr *rt = xfrma[XFRMA_REPLAY_THRESH-1]; 342d51d081dSJamal Hadi Salim 343d51d081dSJamal Hadi Salim if (rp) { 344d51d081dSJamal Hadi Salim struct xfrm_replay_state *replay; 345d51d081dSJamal Hadi Salim if (RTA_PAYLOAD(rp) < sizeof(*replay)) 346d51d081dSJamal Hadi Salim goto error; 347d51d081dSJamal Hadi Salim replay = RTA_DATA(rp); 348d51d081dSJamal Hadi Salim memcpy(&x->replay, replay, sizeof(*replay)); 349d51d081dSJamal Hadi Salim memcpy(&x->preplay, replay, sizeof(*replay)); 350d51d081dSJamal Hadi Salim } 351d51d081dSJamal Hadi Salim 352d51d081dSJamal Hadi Salim if (lt) { 353d51d081dSJamal Hadi Salim struct xfrm_lifetime_cur *ltime; 354d51d081dSJamal Hadi Salim if (RTA_PAYLOAD(lt) < sizeof(*ltime)) 355d51d081dSJamal Hadi Salim goto error; 356d51d081dSJamal Hadi Salim ltime = RTA_DATA(lt); 357d51d081dSJamal Hadi Salim x->curlft.bytes = ltime->bytes; 358d51d081dSJamal Hadi Salim x->curlft.packets = ltime->packets; 359d51d081dSJamal Hadi Salim x->curlft.add_time = ltime->add_time; 360d51d081dSJamal Hadi Salim x->curlft.use_time = ltime->use_time; 361d51d081dSJamal Hadi Salim } 362d51d081dSJamal Hadi Salim 363d51d081dSJamal Hadi Salim if (et) { 364d51d081dSJamal Hadi Salim if (RTA_PAYLOAD(et) < sizeof(u32)) 365d51d081dSJamal Hadi Salim goto error; 366d51d081dSJamal Hadi Salim x->replay_maxage = *(u32*)RTA_DATA(et); 367d51d081dSJamal Hadi Salim } 368d51d081dSJamal Hadi Salim 369d51d081dSJamal Hadi Salim if (rt) { 370d51d081dSJamal Hadi Salim if (RTA_PAYLOAD(rt) < sizeof(u32)) 371d51d081dSJamal Hadi Salim goto error; 372d51d081dSJamal Hadi Salim x->replay_maxdiff = *(u32*)RTA_DATA(rt); 373d51d081dSJamal Hadi Salim } 374d51d081dSJamal Hadi Salim 375d51d081dSJamal Hadi Salim return 0; 376d51d081dSJamal Hadi Salim error: 377d51d081dSJamal Hadi Salim return err; 378d51d081dSJamal Hadi Salim } 379d51d081dSJamal Hadi Salim 3801da177e4SLinus Torvalds static struct xfrm_state *xfrm_state_construct(struct xfrm_usersa_info *p, 3811da177e4SLinus Torvalds struct rtattr **xfrma, 3821da177e4SLinus Torvalds int *errp) 3831da177e4SLinus Torvalds { 3841da177e4SLinus Torvalds struct xfrm_state *x = xfrm_state_alloc(); 3851da177e4SLinus Torvalds int err = -ENOMEM; 3861da177e4SLinus Torvalds 3871da177e4SLinus Torvalds if (!x) 3881da177e4SLinus Torvalds goto error_no_put; 3891da177e4SLinus Torvalds 3901da177e4SLinus Torvalds copy_from_user_state(x, p); 3911da177e4SLinus Torvalds 3921da177e4SLinus Torvalds if ((err = attach_one_algo(&x->aalg, &x->props.aalgo, 3931da177e4SLinus Torvalds xfrm_aalg_get_byname, 3941da177e4SLinus Torvalds xfrma[XFRMA_ALG_AUTH-1]))) 3951da177e4SLinus Torvalds goto error; 3961da177e4SLinus Torvalds if ((err = attach_one_algo(&x->ealg, &x->props.ealgo, 3971da177e4SLinus Torvalds xfrm_ealg_get_byname, 3981da177e4SLinus Torvalds xfrma[XFRMA_ALG_CRYPT-1]))) 3991da177e4SLinus Torvalds goto error; 4001da177e4SLinus Torvalds if ((err = attach_one_algo(&x->calg, &x->props.calgo, 4011da177e4SLinus Torvalds xfrm_calg_get_byname, 4021da177e4SLinus Torvalds xfrma[XFRMA_ALG_COMP-1]))) 4031da177e4SLinus Torvalds goto error; 4041da177e4SLinus Torvalds if ((err = attach_encap_tmpl(&x->encap, xfrma[XFRMA_ENCAP-1]))) 4051da177e4SLinus Torvalds goto error; 406060f02a3SNoriaki TAKAMIYA if ((err = attach_one_addr(&x->coaddr, xfrma[XFRMA_COADDR-1]))) 407060f02a3SNoriaki TAKAMIYA goto error; 40872cb6962SHerbert Xu err = xfrm_init_state(x); 4091da177e4SLinus Torvalds if (err) 4101da177e4SLinus Torvalds goto error; 4111da177e4SLinus Torvalds 412df71837dSTrent Jaeger if ((err = attach_sec_ctx(x, xfrma[XFRMA_SEC_CTX-1]))) 413df71837dSTrent Jaeger goto error; 414df71837dSTrent Jaeger 4151da177e4SLinus Torvalds x->km.seq = p->seq; 416d51d081dSJamal Hadi Salim x->replay_maxdiff = sysctl_xfrm_aevent_rseqth; 417d51d081dSJamal Hadi Salim /* sysctl_xfrm_aevent_etime is in 100ms units */ 418d51d081dSJamal Hadi Salim x->replay_maxage = (sysctl_xfrm_aevent_etime*HZ)/XFRM_AE_ETH_M; 419d51d081dSJamal Hadi Salim x->preplay.bitmap = 0; 420d51d081dSJamal Hadi Salim x->preplay.seq = x->replay.seq+x->replay_maxdiff; 421d51d081dSJamal Hadi Salim x->preplay.oseq = x->replay.oseq +x->replay_maxdiff; 422d51d081dSJamal Hadi Salim 423d51d081dSJamal Hadi Salim /* override default values from above */ 424d51d081dSJamal Hadi Salim 425d51d081dSJamal Hadi Salim err = xfrm_update_ae_params(x, (struct rtattr **)xfrma); 426d51d081dSJamal Hadi Salim if (err < 0) 427d51d081dSJamal Hadi Salim goto error; 4281da177e4SLinus Torvalds 4291da177e4SLinus Torvalds return x; 4301da177e4SLinus Torvalds 4311da177e4SLinus Torvalds error: 4321da177e4SLinus Torvalds x->km.state = XFRM_STATE_DEAD; 4331da177e4SLinus Torvalds xfrm_state_put(x); 4341da177e4SLinus Torvalds error_no_put: 4351da177e4SLinus Torvalds *errp = err; 4361da177e4SLinus Torvalds return NULL; 4371da177e4SLinus Torvalds } 4381da177e4SLinus Torvalds 4391da177e4SLinus Torvalds static int xfrm_add_sa(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma) 4401da177e4SLinus Torvalds { 4411da177e4SLinus Torvalds struct xfrm_usersa_info *p = NLMSG_DATA(nlh); 4421da177e4SLinus Torvalds struct xfrm_state *x; 4431da177e4SLinus Torvalds int err; 44426b15dadSJamal Hadi Salim struct km_event c; 4451da177e4SLinus Torvalds 4461da177e4SLinus Torvalds err = verify_newsa_info(p, (struct rtattr **)xfrma); 4471da177e4SLinus Torvalds if (err) 4481da177e4SLinus Torvalds return err; 4491da177e4SLinus Torvalds 4501da177e4SLinus Torvalds x = xfrm_state_construct(p, (struct rtattr **)xfrma, &err); 4511da177e4SLinus Torvalds if (!x) 4521da177e4SLinus Torvalds return err; 4531da177e4SLinus Torvalds 45426b15dadSJamal Hadi Salim xfrm_state_hold(x); 4551da177e4SLinus Torvalds if (nlh->nlmsg_type == XFRM_MSG_NEWSA) 4561da177e4SLinus Torvalds err = xfrm_state_add(x); 4571da177e4SLinus Torvalds else 4581da177e4SLinus Torvalds err = xfrm_state_update(x); 4591da177e4SLinus Torvalds 4601da177e4SLinus Torvalds if (err < 0) { 4611da177e4SLinus Torvalds x->km.state = XFRM_STATE_DEAD; 46221380b81SHerbert Xu __xfrm_state_put(x); 4637d6dfe1fSPatrick McHardy goto out; 4641da177e4SLinus Torvalds } 4651da177e4SLinus Torvalds 46626b15dadSJamal Hadi Salim c.seq = nlh->nlmsg_seq; 46726b15dadSJamal Hadi Salim c.pid = nlh->nlmsg_pid; 468f60f6b8fSHerbert Xu c.event = nlh->nlmsg_type; 46926b15dadSJamal Hadi Salim 47026b15dadSJamal Hadi Salim km_state_notify(x, &c); 4717d6dfe1fSPatrick McHardy out: 47226b15dadSJamal Hadi Salim xfrm_state_put(x); 4731da177e4SLinus Torvalds return err; 4741da177e4SLinus Torvalds } 4751da177e4SLinus Torvalds 476eb2971b6SMasahide NAKAMURA static struct xfrm_state *xfrm_user_state_lookup(struct xfrm_usersa_id *p, 477eb2971b6SMasahide NAKAMURA struct rtattr **xfrma, 478eb2971b6SMasahide NAKAMURA int *errp) 479eb2971b6SMasahide NAKAMURA { 480eb2971b6SMasahide NAKAMURA struct xfrm_state *x = NULL; 481eb2971b6SMasahide NAKAMURA int err; 482eb2971b6SMasahide NAKAMURA 483eb2971b6SMasahide NAKAMURA if (xfrm_id_proto_match(p->proto, IPSEC_PROTO_ANY)) { 484eb2971b6SMasahide NAKAMURA err = -ESRCH; 485eb2971b6SMasahide NAKAMURA x = xfrm_state_lookup(&p->daddr, p->spi, p->proto, p->family); 486eb2971b6SMasahide NAKAMURA } else { 487eb2971b6SMasahide NAKAMURA xfrm_address_t *saddr = NULL; 488eb2971b6SMasahide NAKAMURA 489eb2971b6SMasahide NAKAMURA err = verify_one_addr(xfrma, XFRMA_SRCADDR, &saddr); 490eb2971b6SMasahide NAKAMURA if (err) 491eb2971b6SMasahide NAKAMURA goto out; 492eb2971b6SMasahide NAKAMURA 493eb2971b6SMasahide NAKAMURA if (!saddr) { 494eb2971b6SMasahide NAKAMURA err = -EINVAL; 495eb2971b6SMasahide NAKAMURA goto out; 496eb2971b6SMasahide NAKAMURA } 497eb2971b6SMasahide NAKAMURA 498eb2971b6SMasahide NAKAMURA x = xfrm_state_lookup_byaddr(&p->daddr, saddr, p->proto, 499eb2971b6SMasahide NAKAMURA p->family); 500eb2971b6SMasahide NAKAMURA } 501eb2971b6SMasahide NAKAMURA 502eb2971b6SMasahide NAKAMURA out: 503eb2971b6SMasahide NAKAMURA if (!x && errp) 504eb2971b6SMasahide NAKAMURA *errp = err; 505eb2971b6SMasahide NAKAMURA return x; 506eb2971b6SMasahide NAKAMURA } 507eb2971b6SMasahide NAKAMURA 5081da177e4SLinus Torvalds static int xfrm_del_sa(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma) 5091da177e4SLinus Torvalds { 5101da177e4SLinus Torvalds struct xfrm_state *x; 511eb2971b6SMasahide NAKAMURA int err = -ESRCH; 51226b15dadSJamal Hadi Salim struct km_event c; 5131da177e4SLinus Torvalds struct xfrm_usersa_id *p = NLMSG_DATA(nlh); 5141da177e4SLinus Torvalds 515eb2971b6SMasahide NAKAMURA x = xfrm_user_state_lookup(p, (struct rtattr **)xfrma, &err); 5161da177e4SLinus Torvalds if (x == NULL) 517eb2971b6SMasahide NAKAMURA return err; 5181da177e4SLinus Torvalds 5196f68dc37SDavid S. Miller if ((err = security_xfrm_state_delete(x)) != 0) 520c8c05a8eSCatherine Zhang goto out; 521c8c05a8eSCatherine Zhang 5221da177e4SLinus Torvalds if (xfrm_state_kern(x)) { 523c8c05a8eSCatherine Zhang err = -EPERM; 524c8c05a8eSCatherine Zhang goto out; 5251da177e4SLinus Torvalds } 5261da177e4SLinus Torvalds 52726b15dadSJamal Hadi Salim err = xfrm_state_delete(x); 528c8c05a8eSCatherine Zhang if (err < 0) 529c8c05a8eSCatherine Zhang goto out; 53026b15dadSJamal Hadi Salim 53126b15dadSJamal Hadi Salim c.seq = nlh->nlmsg_seq; 53226b15dadSJamal Hadi Salim c.pid = nlh->nlmsg_pid; 533f60f6b8fSHerbert Xu c.event = nlh->nlmsg_type; 53426b15dadSJamal Hadi Salim km_state_notify(x, &c); 5351da177e4SLinus Torvalds 536c8c05a8eSCatherine Zhang out: 537c8c05a8eSCatherine Zhang xfrm_state_put(x); 53826b15dadSJamal Hadi Salim return err; 5391da177e4SLinus Torvalds } 5401da177e4SLinus Torvalds 5411da177e4SLinus Torvalds static void copy_to_user_state(struct xfrm_state *x, struct xfrm_usersa_info *p) 5421da177e4SLinus Torvalds { 5431da177e4SLinus Torvalds memcpy(&p->id, &x->id, sizeof(p->id)); 5441da177e4SLinus Torvalds memcpy(&p->sel, &x->sel, sizeof(p->sel)); 5451da177e4SLinus Torvalds memcpy(&p->lft, &x->lft, sizeof(p->lft)); 5461da177e4SLinus Torvalds memcpy(&p->curlft, &x->curlft, sizeof(p->curlft)); 5471da177e4SLinus Torvalds memcpy(&p->stats, &x->stats, sizeof(p->stats)); 5481da177e4SLinus Torvalds p->saddr = x->props.saddr; 5491da177e4SLinus Torvalds p->mode = x->props.mode; 5501da177e4SLinus Torvalds p->replay_window = x->props.replay_window; 5511da177e4SLinus Torvalds p->reqid = x->props.reqid; 5521da177e4SLinus Torvalds p->family = x->props.family; 5531da177e4SLinus Torvalds p->flags = x->props.flags; 5541da177e4SLinus Torvalds p->seq = x->km.seq; 5551da177e4SLinus Torvalds } 5561da177e4SLinus Torvalds 5571da177e4SLinus Torvalds struct xfrm_dump_info { 5581da177e4SLinus Torvalds struct sk_buff *in_skb; 5591da177e4SLinus Torvalds struct sk_buff *out_skb; 5601da177e4SLinus Torvalds u32 nlmsg_seq; 5611da177e4SLinus Torvalds u16 nlmsg_flags; 5621da177e4SLinus Torvalds int start_idx; 5631da177e4SLinus Torvalds int this_idx; 5641da177e4SLinus Torvalds }; 5651da177e4SLinus Torvalds 5661da177e4SLinus Torvalds static int dump_one_state(struct xfrm_state *x, int count, void *ptr) 5671da177e4SLinus Torvalds { 5681da177e4SLinus Torvalds struct xfrm_dump_info *sp = ptr; 5691da177e4SLinus Torvalds struct sk_buff *in_skb = sp->in_skb; 5701da177e4SLinus Torvalds struct sk_buff *skb = sp->out_skb; 5711da177e4SLinus Torvalds struct xfrm_usersa_info *p; 5721da177e4SLinus Torvalds struct nlmsghdr *nlh; 5731da177e4SLinus Torvalds unsigned char *b = skb->tail; 5741da177e4SLinus Torvalds 5751da177e4SLinus Torvalds if (sp->this_idx < sp->start_idx) 5761da177e4SLinus Torvalds goto out; 5771da177e4SLinus Torvalds 5781da177e4SLinus Torvalds nlh = NLMSG_PUT(skb, NETLINK_CB(in_skb).pid, 5791da177e4SLinus Torvalds sp->nlmsg_seq, 5801da177e4SLinus Torvalds XFRM_MSG_NEWSA, sizeof(*p)); 5811da177e4SLinus Torvalds nlh->nlmsg_flags = sp->nlmsg_flags; 5821da177e4SLinus Torvalds 5831da177e4SLinus Torvalds p = NLMSG_DATA(nlh); 5841da177e4SLinus Torvalds copy_to_user_state(x, p); 5851da177e4SLinus Torvalds 5861da177e4SLinus Torvalds if (x->aalg) 5871da177e4SLinus Torvalds RTA_PUT(skb, XFRMA_ALG_AUTH, 5881da177e4SLinus Torvalds sizeof(*(x->aalg))+(x->aalg->alg_key_len+7)/8, x->aalg); 5891da177e4SLinus Torvalds if (x->ealg) 5901da177e4SLinus Torvalds RTA_PUT(skb, XFRMA_ALG_CRYPT, 5911da177e4SLinus Torvalds sizeof(*(x->ealg))+(x->ealg->alg_key_len+7)/8, x->ealg); 5921da177e4SLinus Torvalds if (x->calg) 5931da177e4SLinus Torvalds RTA_PUT(skb, XFRMA_ALG_COMP, sizeof(*(x->calg)), x->calg); 5941da177e4SLinus Torvalds 5951da177e4SLinus Torvalds if (x->encap) 5961da177e4SLinus Torvalds RTA_PUT(skb, XFRMA_ENCAP, sizeof(*x->encap), x->encap); 5971da177e4SLinus Torvalds 598df71837dSTrent Jaeger if (x->security) { 599df71837dSTrent Jaeger int ctx_size = sizeof(struct xfrm_sec_ctx) + 600df71837dSTrent Jaeger x->security->ctx_len; 601df71837dSTrent Jaeger struct rtattr *rt = __RTA_PUT(skb, XFRMA_SEC_CTX, ctx_size); 602df71837dSTrent Jaeger struct xfrm_user_sec_ctx *uctx = RTA_DATA(rt); 603df71837dSTrent Jaeger 604df71837dSTrent Jaeger uctx->exttype = XFRMA_SEC_CTX; 605df71837dSTrent Jaeger uctx->len = ctx_size; 606df71837dSTrent Jaeger uctx->ctx_doi = x->security->ctx_doi; 607df71837dSTrent Jaeger uctx->ctx_alg = x->security->ctx_alg; 608df71837dSTrent Jaeger uctx->ctx_len = x->security->ctx_len; 609df71837dSTrent Jaeger memcpy(uctx + 1, x->security->ctx_str, x->security->ctx_len); 610df71837dSTrent Jaeger } 611060f02a3SNoriaki TAKAMIYA 612060f02a3SNoriaki TAKAMIYA if (x->coaddr) 613060f02a3SNoriaki TAKAMIYA RTA_PUT(skb, XFRMA_COADDR, sizeof(*x->coaddr), x->coaddr); 614060f02a3SNoriaki TAKAMIYA 6159afaca05SMasahide NAKAMURA if (x->lastused) 6169afaca05SMasahide NAKAMURA RTA_PUT(skb, XFRMA_LASTUSED, sizeof(x->lastused), &x->lastused); 6179afaca05SMasahide NAKAMURA 6181da177e4SLinus Torvalds nlh->nlmsg_len = skb->tail - b; 6191da177e4SLinus Torvalds out: 6201da177e4SLinus Torvalds sp->this_idx++; 6211da177e4SLinus Torvalds return 0; 6221da177e4SLinus Torvalds 6231da177e4SLinus Torvalds nlmsg_failure: 6241da177e4SLinus Torvalds rtattr_failure: 6251da177e4SLinus Torvalds skb_trim(skb, b - skb->data); 6261da177e4SLinus Torvalds return -1; 6271da177e4SLinus Torvalds } 6281da177e4SLinus Torvalds 6291da177e4SLinus Torvalds static int xfrm_dump_sa(struct sk_buff *skb, struct netlink_callback *cb) 6301da177e4SLinus Torvalds { 6311da177e4SLinus Torvalds struct xfrm_dump_info info; 6321da177e4SLinus Torvalds 6331da177e4SLinus Torvalds info.in_skb = cb->skb; 6341da177e4SLinus Torvalds info.out_skb = skb; 6351da177e4SLinus Torvalds info.nlmsg_seq = cb->nlh->nlmsg_seq; 6361da177e4SLinus Torvalds info.nlmsg_flags = NLM_F_MULTI; 6371da177e4SLinus Torvalds info.this_idx = 0; 6381da177e4SLinus Torvalds info.start_idx = cb->args[0]; 639dc00a525SMasahide NAKAMURA (void) xfrm_state_walk(0, dump_one_state, &info); 6401da177e4SLinus Torvalds cb->args[0] = info.this_idx; 6411da177e4SLinus Torvalds 6421da177e4SLinus Torvalds return skb->len; 6431da177e4SLinus Torvalds } 6441da177e4SLinus Torvalds 6451da177e4SLinus Torvalds static struct sk_buff *xfrm_state_netlink(struct sk_buff *in_skb, 6461da177e4SLinus Torvalds struct xfrm_state *x, u32 seq) 6471da177e4SLinus Torvalds { 6481da177e4SLinus Torvalds struct xfrm_dump_info info; 6491da177e4SLinus Torvalds struct sk_buff *skb; 6501da177e4SLinus Torvalds 6511da177e4SLinus Torvalds skb = alloc_skb(NLMSG_GOODSIZE, GFP_ATOMIC); 6521da177e4SLinus Torvalds if (!skb) 6531da177e4SLinus Torvalds return ERR_PTR(-ENOMEM); 6541da177e4SLinus Torvalds 6551da177e4SLinus Torvalds NETLINK_CB(skb).dst_pid = NETLINK_CB(in_skb).pid; 6561da177e4SLinus Torvalds info.in_skb = in_skb; 6571da177e4SLinus Torvalds info.out_skb = skb; 6581da177e4SLinus Torvalds info.nlmsg_seq = seq; 6591da177e4SLinus Torvalds info.nlmsg_flags = 0; 6601da177e4SLinus Torvalds info.this_idx = info.start_idx = 0; 6611da177e4SLinus Torvalds 6621da177e4SLinus Torvalds if (dump_one_state(x, 0, &info)) { 6631da177e4SLinus Torvalds kfree_skb(skb); 6641da177e4SLinus Torvalds return NULL; 6651da177e4SLinus Torvalds } 6661da177e4SLinus Torvalds 6671da177e4SLinus Torvalds return skb; 6681da177e4SLinus Torvalds } 6691da177e4SLinus Torvalds 6701da177e4SLinus Torvalds static int xfrm_get_sa(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma) 6711da177e4SLinus Torvalds { 6721da177e4SLinus Torvalds struct xfrm_usersa_id *p = NLMSG_DATA(nlh); 6731da177e4SLinus Torvalds struct xfrm_state *x; 6741da177e4SLinus Torvalds struct sk_buff *resp_skb; 675eb2971b6SMasahide NAKAMURA int err = -ESRCH; 6761da177e4SLinus Torvalds 677eb2971b6SMasahide NAKAMURA x = xfrm_user_state_lookup(p, (struct rtattr **)xfrma, &err); 6781da177e4SLinus Torvalds if (x == NULL) 6791da177e4SLinus Torvalds goto out_noput; 6801da177e4SLinus Torvalds 6811da177e4SLinus Torvalds resp_skb = xfrm_state_netlink(skb, x, nlh->nlmsg_seq); 6821da177e4SLinus Torvalds if (IS_ERR(resp_skb)) { 6831da177e4SLinus Torvalds err = PTR_ERR(resp_skb); 6841da177e4SLinus Torvalds } else { 6851da177e4SLinus Torvalds err = netlink_unicast(xfrm_nl, resp_skb, 6861da177e4SLinus Torvalds NETLINK_CB(skb).pid, MSG_DONTWAIT); 6871da177e4SLinus Torvalds } 6881da177e4SLinus Torvalds xfrm_state_put(x); 6891da177e4SLinus Torvalds out_noput: 6901da177e4SLinus Torvalds return err; 6911da177e4SLinus Torvalds } 6921da177e4SLinus Torvalds 6931da177e4SLinus Torvalds static int verify_userspi_info(struct xfrm_userspi_info *p) 6941da177e4SLinus Torvalds { 6951da177e4SLinus Torvalds switch (p->info.id.proto) { 6961da177e4SLinus Torvalds case IPPROTO_AH: 6971da177e4SLinus Torvalds case IPPROTO_ESP: 6981da177e4SLinus Torvalds break; 6991da177e4SLinus Torvalds 7001da177e4SLinus Torvalds case IPPROTO_COMP: 7011da177e4SLinus Torvalds /* IPCOMP spi is 16-bits. */ 7021da177e4SLinus Torvalds if (p->max >= 0x10000) 7031da177e4SLinus Torvalds return -EINVAL; 7041da177e4SLinus Torvalds break; 7051da177e4SLinus Torvalds 7061da177e4SLinus Torvalds default: 7071da177e4SLinus Torvalds return -EINVAL; 7081da177e4SLinus Torvalds }; 7091da177e4SLinus Torvalds 7101da177e4SLinus Torvalds if (p->min > p->max) 7111da177e4SLinus Torvalds return -EINVAL; 7121da177e4SLinus Torvalds 7131da177e4SLinus Torvalds return 0; 7141da177e4SLinus Torvalds } 7151da177e4SLinus Torvalds 7161da177e4SLinus Torvalds static int xfrm_alloc_userspi(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma) 7171da177e4SLinus Torvalds { 7181da177e4SLinus Torvalds struct xfrm_state *x; 7191da177e4SLinus Torvalds struct xfrm_userspi_info *p; 7201da177e4SLinus Torvalds struct sk_buff *resp_skb; 7211da177e4SLinus Torvalds xfrm_address_t *daddr; 7221da177e4SLinus Torvalds int family; 7231da177e4SLinus Torvalds int err; 7241da177e4SLinus Torvalds 7251da177e4SLinus Torvalds p = NLMSG_DATA(nlh); 7261da177e4SLinus Torvalds err = verify_userspi_info(p); 7271da177e4SLinus Torvalds if (err) 7281da177e4SLinus Torvalds goto out_noput; 7291da177e4SLinus Torvalds 7301da177e4SLinus Torvalds family = p->info.family; 7311da177e4SLinus Torvalds daddr = &p->info.id.daddr; 7321da177e4SLinus Torvalds 7331da177e4SLinus Torvalds x = NULL; 7341da177e4SLinus Torvalds if (p->info.seq) { 7351da177e4SLinus Torvalds x = xfrm_find_acq_byseq(p->info.seq); 7361da177e4SLinus Torvalds if (x && xfrm_addr_cmp(&x->id.daddr, daddr, family)) { 7371da177e4SLinus Torvalds xfrm_state_put(x); 7381da177e4SLinus Torvalds x = NULL; 7391da177e4SLinus Torvalds } 7401da177e4SLinus Torvalds } 7411da177e4SLinus Torvalds 7421da177e4SLinus Torvalds if (!x) 7431da177e4SLinus Torvalds x = xfrm_find_acq(p->info.mode, p->info.reqid, 7441da177e4SLinus Torvalds p->info.id.proto, daddr, 7451da177e4SLinus Torvalds &p->info.saddr, 1, 7461da177e4SLinus Torvalds family); 7471da177e4SLinus Torvalds err = -ENOENT; 7481da177e4SLinus Torvalds if (x == NULL) 7491da177e4SLinus Torvalds goto out_noput; 7501da177e4SLinus Torvalds 7511da177e4SLinus Torvalds resp_skb = ERR_PTR(-ENOENT); 7521da177e4SLinus Torvalds 7531da177e4SLinus Torvalds spin_lock_bh(&x->lock); 7541da177e4SLinus Torvalds if (x->km.state != XFRM_STATE_DEAD) { 7551da177e4SLinus Torvalds xfrm_alloc_spi(x, htonl(p->min), htonl(p->max)); 7561da177e4SLinus Torvalds if (x->id.spi) 7571da177e4SLinus Torvalds resp_skb = xfrm_state_netlink(skb, x, nlh->nlmsg_seq); 7581da177e4SLinus Torvalds } 7591da177e4SLinus Torvalds spin_unlock_bh(&x->lock); 7601da177e4SLinus Torvalds 7611da177e4SLinus Torvalds if (IS_ERR(resp_skb)) { 7621da177e4SLinus Torvalds err = PTR_ERR(resp_skb); 7631da177e4SLinus Torvalds goto out; 7641da177e4SLinus Torvalds } 7651da177e4SLinus Torvalds 7661da177e4SLinus Torvalds err = netlink_unicast(xfrm_nl, resp_skb, 7671da177e4SLinus Torvalds NETLINK_CB(skb).pid, MSG_DONTWAIT); 7681da177e4SLinus Torvalds 7691da177e4SLinus Torvalds out: 7701da177e4SLinus Torvalds xfrm_state_put(x); 7711da177e4SLinus Torvalds out_noput: 7721da177e4SLinus Torvalds return err; 7731da177e4SLinus Torvalds } 7741da177e4SLinus Torvalds 7751da177e4SLinus Torvalds static int verify_policy_dir(__u8 dir) 7761da177e4SLinus Torvalds { 7771da177e4SLinus Torvalds switch (dir) { 7781da177e4SLinus Torvalds case XFRM_POLICY_IN: 7791da177e4SLinus Torvalds case XFRM_POLICY_OUT: 7801da177e4SLinus Torvalds case XFRM_POLICY_FWD: 7811da177e4SLinus Torvalds break; 7821da177e4SLinus Torvalds 7831da177e4SLinus Torvalds default: 7841da177e4SLinus Torvalds return -EINVAL; 7851da177e4SLinus Torvalds }; 7861da177e4SLinus Torvalds 7871da177e4SLinus Torvalds return 0; 7881da177e4SLinus Torvalds } 7891da177e4SLinus Torvalds 790f7b6983fSMasahide NAKAMURA static int verify_policy_type(__u8 type) 791f7b6983fSMasahide NAKAMURA { 792f7b6983fSMasahide NAKAMURA switch (type) { 793f7b6983fSMasahide NAKAMURA case XFRM_POLICY_TYPE_MAIN: 794f7b6983fSMasahide NAKAMURA #ifdef CONFIG_XFRM_SUB_POLICY 795f7b6983fSMasahide NAKAMURA case XFRM_POLICY_TYPE_SUB: 796f7b6983fSMasahide NAKAMURA #endif 797f7b6983fSMasahide NAKAMURA break; 798f7b6983fSMasahide NAKAMURA 799f7b6983fSMasahide NAKAMURA default: 800f7b6983fSMasahide NAKAMURA return -EINVAL; 801f7b6983fSMasahide NAKAMURA }; 802f7b6983fSMasahide NAKAMURA 803f7b6983fSMasahide NAKAMURA return 0; 804f7b6983fSMasahide NAKAMURA } 805f7b6983fSMasahide NAKAMURA 8061da177e4SLinus Torvalds static int verify_newpolicy_info(struct xfrm_userpolicy_info *p) 8071da177e4SLinus Torvalds { 8081da177e4SLinus Torvalds switch (p->share) { 8091da177e4SLinus Torvalds case XFRM_SHARE_ANY: 8101da177e4SLinus Torvalds case XFRM_SHARE_SESSION: 8111da177e4SLinus Torvalds case XFRM_SHARE_USER: 8121da177e4SLinus Torvalds case XFRM_SHARE_UNIQUE: 8131da177e4SLinus Torvalds break; 8141da177e4SLinus Torvalds 8151da177e4SLinus Torvalds default: 8161da177e4SLinus Torvalds return -EINVAL; 8171da177e4SLinus Torvalds }; 8181da177e4SLinus Torvalds 8191da177e4SLinus Torvalds switch (p->action) { 8201da177e4SLinus Torvalds case XFRM_POLICY_ALLOW: 8211da177e4SLinus Torvalds case XFRM_POLICY_BLOCK: 8221da177e4SLinus Torvalds break; 8231da177e4SLinus Torvalds 8241da177e4SLinus Torvalds default: 8251da177e4SLinus Torvalds return -EINVAL; 8261da177e4SLinus Torvalds }; 8271da177e4SLinus Torvalds 8281da177e4SLinus Torvalds switch (p->sel.family) { 8291da177e4SLinus Torvalds case AF_INET: 8301da177e4SLinus Torvalds break; 8311da177e4SLinus Torvalds 8321da177e4SLinus Torvalds case AF_INET6: 8331da177e4SLinus Torvalds #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 8341da177e4SLinus Torvalds break; 8351da177e4SLinus Torvalds #else 8361da177e4SLinus Torvalds return -EAFNOSUPPORT; 8371da177e4SLinus Torvalds #endif 8381da177e4SLinus Torvalds 8391da177e4SLinus Torvalds default: 8401da177e4SLinus Torvalds return -EINVAL; 8411da177e4SLinus Torvalds }; 8421da177e4SLinus Torvalds 8431da177e4SLinus Torvalds return verify_policy_dir(p->dir); 8441da177e4SLinus Torvalds } 8451da177e4SLinus Torvalds 846df71837dSTrent Jaeger static int copy_from_user_sec_ctx(struct xfrm_policy *pol, struct rtattr **xfrma) 847df71837dSTrent Jaeger { 848df71837dSTrent Jaeger struct rtattr *rt = xfrma[XFRMA_SEC_CTX-1]; 849df71837dSTrent Jaeger struct xfrm_user_sec_ctx *uctx; 850df71837dSTrent Jaeger 851df71837dSTrent Jaeger if (!rt) 852df71837dSTrent Jaeger return 0; 853df71837dSTrent Jaeger 854df71837dSTrent Jaeger uctx = RTA_DATA(rt); 855df71837dSTrent Jaeger return security_xfrm_policy_alloc(pol, uctx); 856df71837dSTrent Jaeger } 857df71837dSTrent Jaeger 8581da177e4SLinus Torvalds static void copy_templates(struct xfrm_policy *xp, struct xfrm_user_tmpl *ut, 8591da177e4SLinus Torvalds int nr) 8601da177e4SLinus Torvalds { 8611da177e4SLinus Torvalds int i; 8621da177e4SLinus Torvalds 8631da177e4SLinus Torvalds xp->xfrm_nr = nr; 8641da177e4SLinus Torvalds for (i = 0; i < nr; i++, ut++) { 8651da177e4SLinus Torvalds struct xfrm_tmpl *t = &xp->xfrm_vec[i]; 8661da177e4SLinus Torvalds 8671da177e4SLinus Torvalds memcpy(&t->id, &ut->id, sizeof(struct xfrm_id)); 8681da177e4SLinus Torvalds memcpy(&t->saddr, &ut->saddr, 8691da177e4SLinus Torvalds sizeof(xfrm_address_t)); 8701da177e4SLinus Torvalds t->reqid = ut->reqid; 8711da177e4SLinus Torvalds t->mode = ut->mode; 8721da177e4SLinus Torvalds t->share = ut->share; 8731da177e4SLinus Torvalds t->optional = ut->optional; 8741da177e4SLinus Torvalds t->aalgos = ut->aalgos; 8751da177e4SLinus Torvalds t->ealgos = ut->ealgos; 8761da177e4SLinus Torvalds t->calgos = ut->calgos; 8771da177e4SLinus Torvalds } 8781da177e4SLinus Torvalds } 8791da177e4SLinus Torvalds 8801da177e4SLinus Torvalds static int copy_from_user_tmpl(struct xfrm_policy *pol, struct rtattr **xfrma) 8811da177e4SLinus Torvalds { 8821da177e4SLinus Torvalds struct rtattr *rt = xfrma[XFRMA_TMPL-1]; 8831da177e4SLinus Torvalds struct xfrm_user_tmpl *utmpl; 8841da177e4SLinus Torvalds int nr; 8851da177e4SLinus Torvalds 8861da177e4SLinus Torvalds if (!rt) { 8871da177e4SLinus Torvalds pol->xfrm_nr = 0; 8881da177e4SLinus Torvalds } else { 8891da177e4SLinus Torvalds nr = (rt->rta_len - sizeof(*rt)) / sizeof(*utmpl); 8901da177e4SLinus Torvalds 8911da177e4SLinus Torvalds if (nr > XFRM_MAX_DEPTH) 8921da177e4SLinus Torvalds return -EINVAL; 8931da177e4SLinus Torvalds 8941da177e4SLinus Torvalds copy_templates(pol, RTA_DATA(rt), nr); 8951da177e4SLinus Torvalds } 8961da177e4SLinus Torvalds return 0; 8971da177e4SLinus Torvalds } 8981da177e4SLinus Torvalds 899f7b6983fSMasahide NAKAMURA static int copy_from_user_policy_type(u8 *tp, struct rtattr **xfrma) 900f7b6983fSMasahide NAKAMURA { 901f7b6983fSMasahide NAKAMURA struct rtattr *rt = xfrma[XFRMA_POLICY_TYPE-1]; 902f7b6983fSMasahide NAKAMURA struct xfrm_userpolicy_type *upt; 903f7b6983fSMasahide NAKAMURA __u8 type = XFRM_POLICY_TYPE_MAIN; 904f7b6983fSMasahide NAKAMURA int err; 905f7b6983fSMasahide NAKAMURA 906f7b6983fSMasahide NAKAMURA if (rt) { 907f7b6983fSMasahide NAKAMURA if (rt->rta_len < sizeof(*upt)) 908f7b6983fSMasahide NAKAMURA return -EINVAL; 909f7b6983fSMasahide NAKAMURA 910f7b6983fSMasahide NAKAMURA upt = RTA_DATA(rt); 911f7b6983fSMasahide NAKAMURA type = upt->type; 912f7b6983fSMasahide NAKAMURA } 913f7b6983fSMasahide NAKAMURA 914f7b6983fSMasahide NAKAMURA err = verify_policy_type(type); 915f7b6983fSMasahide NAKAMURA if (err) 916f7b6983fSMasahide NAKAMURA return err; 917f7b6983fSMasahide NAKAMURA 918f7b6983fSMasahide NAKAMURA *tp = type; 919f7b6983fSMasahide NAKAMURA return 0; 920f7b6983fSMasahide NAKAMURA } 921f7b6983fSMasahide NAKAMURA 9221da177e4SLinus Torvalds static void copy_from_user_policy(struct xfrm_policy *xp, struct xfrm_userpolicy_info *p) 9231da177e4SLinus Torvalds { 9241da177e4SLinus Torvalds xp->priority = p->priority; 9251da177e4SLinus Torvalds xp->index = p->index; 9261da177e4SLinus Torvalds memcpy(&xp->selector, &p->sel, sizeof(xp->selector)); 9271da177e4SLinus Torvalds memcpy(&xp->lft, &p->lft, sizeof(xp->lft)); 9281da177e4SLinus Torvalds xp->action = p->action; 9291da177e4SLinus Torvalds xp->flags = p->flags; 9301da177e4SLinus Torvalds xp->family = p->sel.family; 9311da177e4SLinus Torvalds /* XXX xp->share = p->share; */ 9321da177e4SLinus Torvalds } 9331da177e4SLinus Torvalds 9341da177e4SLinus Torvalds static void copy_to_user_policy(struct xfrm_policy *xp, struct xfrm_userpolicy_info *p, int dir) 9351da177e4SLinus Torvalds { 9361da177e4SLinus Torvalds memcpy(&p->sel, &xp->selector, sizeof(p->sel)); 9371da177e4SLinus Torvalds memcpy(&p->lft, &xp->lft, sizeof(p->lft)); 9381da177e4SLinus Torvalds memcpy(&p->curlft, &xp->curlft, sizeof(p->curlft)); 9391da177e4SLinus Torvalds p->priority = xp->priority; 9401da177e4SLinus Torvalds p->index = xp->index; 9411da177e4SLinus Torvalds p->sel.family = xp->family; 9421da177e4SLinus Torvalds p->dir = dir; 9431da177e4SLinus Torvalds p->action = xp->action; 9441da177e4SLinus Torvalds p->flags = xp->flags; 9451da177e4SLinus Torvalds p->share = XFRM_SHARE_ANY; /* XXX xp->share */ 9461da177e4SLinus Torvalds } 9471da177e4SLinus Torvalds 9481da177e4SLinus Torvalds static struct xfrm_policy *xfrm_policy_construct(struct xfrm_userpolicy_info *p, struct rtattr **xfrma, int *errp) 9491da177e4SLinus Torvalds { 9501da177e4SLinus Torvalds struct xfrm_policy *xp = xfrm_policy_alloc(GFP_KERNEL); 9511da177e4SLinus Torvalds int err; 9521da177e4SLinus Torvalds 9531da177e4SLinus Torvalds if (!xp) { 9541da177e4SLinus Torvalds *errp = -ENOMEM; 9551da177e4SLinus Torvalds return NULL; 9561da177e4SLinus Torvalds } 9571da177e4SLinus Torvalds 9581da177e4SLinus Torvalds copy_from_user_policy(xp, p); 959df71837dSTrent Jaeger 960f7b6983fSMasahide NAKAMURA err = copy_from_user_policy_type(&xp->type, xfrma); 961f7b6983fSMasahide NAKAMURA if (err) 962f7b6983fSMasahide NAKAMURA goto error; 963f7b6983fSMasahide NAKAMURA 964df71837dSTrent Jaeger if (!(err = copy_from_user_tmpl(xp, xfrma))) 965df71837dSTrent Jaeger err = copy_from_user_sec_ctx(xp, xfrma); 966f7b6983fSMasahide NAKAMURA if (err) 967f7b6983fSMasahide NAKAMURA goto error; 9681da177e4SLinus Torvalds 9691da177e4SLinus Torvalds return xp; 970f7b6983fSMasahide NAKAMURA error: 971f7b6983fSMasahide NAKAMURA *errp = err; 972f7b6983fSMasahide NAKAMURA kfree(xp); 973f7b6983fSMasahide NAKAMURA return NULL; 9741da177e4SLinus Torvalds } 9751da177e4SLinus Torvalds 9761da177e4SLinus Torvalds static int xfrm_add_policy(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma) 9771da177e4SLinus Torvalds { 9781da177e4SLinus Torvalds struct xfrm_userpolicy_info *p = NLMSG_DATA(nlh); 9791da177e4SLinus Torvalds struct xfrm_policy *xp; 98026b15dadSJamal Hadi Salim struct km_event c; 9811da177e4SLinus Torvalds int err; 9821da177e4SLinus Torvalds int excl; 9831da177e4SLinus Torvalds 9841da177e4SLinus Torvalds err = verify_newpolicy_info(p); 9851da177e4SLinus Torvalds if (err) 9861da177e4SLinus Torvalds return err; 987df71837dSTrent Jaeger err = verify_sec_ctx_len((struct rtattr **)xfrma); 988df71837dSTrent Jaeger if (err) 989df71837dSTrent Jaeger return err; 9901da177e4SLinus Torvalds 9911da177e4SLinus Torvalds xp = xfrm_policy_construct(p, (struct rtattr **)xfrma, &err); 9921da177e4SLinus Torvalds if (!xp) 9931da177e4SLinus Torvalds return err; 9941da177e4SLinus Torvalds 99526b15dadSJamal Hadi Salim /* shouldnt excl be based on nlh flags?? 99626b15dadSJamal Hadi Salim * Aha! this is anti-netlink really i.e more pfkey derived 99726b15dadSJamal Hadi Salim * in netlink excl is a flag and you wouldnt need 99826b15dadSJamal Hadi Salim * a type XFRM_MSG_UPDPOLICY - JHS */ 9991da177e4SLinus Torvalds excl = nlh->nlmsg_type == XFRM_MSG_NEWPOLICY; 10001da177e4SLinus Torvalds err = xfrm_policy_insert(p->dir, xp, excl); 10011da177e4SLinus Torvalds if (err) { 10025f8ac64bSTrent Jaeger security_xfrm_policy_free(xp); 10031da177e4SLinus Torvalds kfree(xp); 10041da177e4SLinus Torvalds return err; 10051da177e4SLinus Torvalds } 10061da177e4SLinus Torvalds 1007f60f6b8fSHerbert Xu c.event = nlh->nlmsg_type; 100826b15dadSJamal Hadi Salim c.seq = nlh->nlmsg_seq; 100926b15dadSJamal Hadi Salim c.pid = nlh->nlmsg_pid; 101026b15dadSJamal Hadi Salim km_policy_notify(xp, p->dir, &c); 101126b15dadSJamal Hadi Salim 10121da177e4SLinus Torvalds xfrm_pol_put(xp); 10131da177e4SLinus Torvalds 10141da177e4SLinus Torvalds return 0; 10151da177e4SLinus Torvalds } 10161da177e4SLinus Torvalds 10171da177e4SLinus Torvalds static int copy_to_user_tmpl(struct xfrm_policy *xp, struct sk_buff *skb) 10181da177e4SLinus Torvalds { 10191da177e4SLinus Torvalds struct xfrm_user_tmpl vec[XFRM_MAX_DEPTH]; 10201da177e4SLinus Torvalds int i; 10211da177e4SLinus Torvalds 10221da177e4SLinus Torvalds if (xp->xfrm_nr == 0) 10231da177e4SLinus Torvalds return 0; 10241da177e4SLinus Torvalds 10251da177e4SLinus Torvalds for (i = 0; i < xp->xfrm_nr; i++) { 10261da177e4SLinus Torvalds struct xfrm_user_tmpl *up = &vec[i]; 10271da177e4SLinus Torvalds struct xfrm_tmpl *kp = &xp->xfrm_vec[i]; 10281da177e4SLinus Torvalds 10291da177e4SLinus Torvalds memcpy(&up->id, &kp->id, sizeof(up->id)); 10301da177e4SLinus Torvalds up->family = xp->family; 10311da177e4SLinus Torvalds memcpy(&up->saddr, &kp->saddr, sizeof(up->saddr)); 10321da177e4SLinus Torvalds up->reqid = kp->reqid; 10331da177e4SLinus Torvalds up->mode = kp->mode; 10341da177e4SLinus Torvalds up->share = kp->share; 10351da177e4SLinus Torvalds up->optional = kp->optional; 10361da177e4SLinus Torvalds up->aalgos = kp->aalgos; 10371da177e4SLinus Torvalds up->ealgos = kp->ealgos; 10381da177e4SLinus Torvalds up->calgos = kp->calgos; 10391da177e4SLinus Torvalds } 10401da177e4SLinus Torvalds RTA_PUT(skb, XFRMA_TMPL, 10411da177e4SLinus Torvalds (sizeof(struct xfrm_user_tmpl) * xp->xfrm_nr), 10421da177e4SLinus Torvalds vec); 10431da177e4SLinus Torvalds 10441da177e4SLinus Torvalds return 0; 10451da177e4SLinus Torvalds 10461da177e4SLinus Torvalds rtattr_failure: 10471da177e4SLinus Torvalds return -1; 10481da177e4SLinus Torvalds } 10491da177e4SLinus Torvalds 10500d681623SSerge Hallyn static int copy_sec_ctx(struct xfrm_sec_ctx *s, struct sk_buff *skb) 1051df71837dSTrent Jaeger { 10520d681623SSerge Hallyn int ctx_size = sizeof(struct xfrm_sec_ctx) + s->ctx_len; 1053df71837dSTrent Jaeger struct rtattr *rt = __RTA_PUT(skb, XFRMA_SEC_CTX, ctx_size); 1054df71837dSTrent Jaeger struct xfrm_user_sec_ctx *uctx = RTA_DATA(rt); 1055df71837dSTrent Jaeger 1056df71837dSTrent Jaeger uctx->exttype = XFRMA_SEC_CTX; 1057df71837dSTrent Jaeger uctx->len = ctx_size; 10580d681623SSerge Hallyn uctx->ctx_doi = s->ctx_doi; 10590d681623SSerge Hallyn uctx->ctx_alg = s->ctx_alg; 10600d681623SSerge Hallyn uctx->ctx_len = s->ctx_len; 10610d681623SSerge Hallyn memcpy(uctx + 1, s->ctx_str, s->ctx_len); 1062df71837dSTrent Jaeger return 0; 1063df71837dSTrent Jaeger 1064df71837dSTrent Jaeger rtattr_failure: 1065df71837dSTrent Jaeger return -1; 1066df71837dSTrent Jaeger } 1067df71837dSTrent Jaeger 10680d681623SSerge Hallyn static inline int copy_to_user_state_sec_ctx(struct xfrm_state *x, struct sk_buff *skb) 10690d681623SSerge Hallyn { 10700d681623SSerge Hallyn if (x->security) { 10710d681623SSerge Hallyn return copy_sec_ctx(x->security, skb); 10720d681623SSerge Hallyn } 10730d681623SSerge Hallyn return 0; 10740d681623SSerge Hallyn } 10750d681623SSerge Hallyn 10760d681623SSerge Hallyn static inline int copy_to_user_sec_ctx(struct xfrm_policy *xp, struct sk_buff *skb) 10770d681623SSerge Hallyn { 10780d681623SSerge Hallyn if (xp->security) { 10790d681623SSerge Hallyn return copy_sec_ctx(xp->security, skb); 10800d681623SSerge Hallyn } 10810d681623SSerge Hallyn return 0; 10820d681623SSerge Hallyn } 10830d681623SSerge Hallyn 1084f7b6983fSMasahide NAKAMURA #ifdef CONFIG_XFRM_SUB_POLICY 1085f7b6983fSMasahide NAKAMURA static int copy_to_user_policy_type(struct xfrm_policy *xp, struct sk_buff *skb) 1086f7b6983fSMasahide NAKAMURA { 1087f7b6983fSMasahide NAKAMURA struct xfrm_userpolicy_type upt; 1088f7b6983fSMasahide NAKAMURA 1089f7b6983fSMasahide NAKAMURA memset(&upt, 0, sizeof(upt)); 1090f7b6983fSMasahide NAKAMURA upt.type = xp->type; 1091f7b6983fSMasahide NAKAMURA 1092f7b6983fSMasahide NAKAMURA RTA_PUT(skb, XFRMA_POLICY_TYPE, sizeof(upt), &upt); 1093f7b6983fSMasahide NAKAMURA 1094f7b6983fSMasahide NAKAMURA return 0; 1095f7b6983fSMasahide NAKAMURA 1096f7b6983fSMasahide NAKAMURA rtattr_failure: 1097f7b6983fSMasahide NAKAMURA return -1; 1098f7b6983fSMasahide NAKAMURA } 1099f7b6983fSMasahide NAKAMURA 1100f7b6983fSMasahide NAKAMURA #else 1101f7b6983fSMasahide NAKAMURA static inline int copy_to_user_policy_type(struct xfrm_policy *xp, struct sk_buff *skb) 1102f7b6983fSMasahide NAKAMURA { 1103f7b6983fSMasahide NAKAMURA return 0; 1104f7b6983fSMasahide NAKAMURA } 1105f7b6983fSMasahide NAKAMURA #endif 1106f7b6983fSMasahide NAKAMURA 11071da177e4SLinus Torvalds static int dump_one_policy(struct xfrm_policy *xp, int dir, int count, void *ptr) 11081da177e4SLinus Torvalds { 11091da177e4SLinus Torvalds struct xfrm_dump_info *sp = ptr; 11101da177e4SLinus Torvalds struct xfrm_userpolicy_info *p; 11111da177e4SLinus Torvalds struct sk_buff *in_skb = sp->in_skb; 11121da177e4SLinus Torvalds struct sk_buff *skb = sp->out_skb; 11131da177e4SLinus Torvalds struct nlmsghdr *nlh; 11141da177e4SLinus Torvalds unsigned char *b = skb->tail; 11151da177e4SLinus Torvalds 11161da177e4SLinus Torvalds if (sp->this_idx < sp->start_idx) 11171da177e4SLinus Torvalds goto out; 11181da177e4SLinus Torvalds 11191da177e4SLinus Torvalds nlh = NLMSG_PUT(skb, NETLINK_CB(in_skb).pid, 11201da177e4SLinus Torvalds sp->nlmsg_seq, 11211da177e4SLinus Torvalds XFRM_MSG_NEWPOLICY, sizeof(*p)); 11221da177e4SLinus Torvalds p = NLMSG_DATA(nlh); 11231da177e4SLinus Torvalds nlh->nlmsg_flags = sp->nlmsg_flags; 11241da177e4SLinus Torvalds 11251da177e4SLinus Torvalds copy_to_user_policy(xp, p, dir); 11261da177e4SLinus Torvalds if (copy_to_user_tmpl(xp, skb) < 0) 11271da177e4SLinus Torvalds goto nlmsg_failure; 1128df71837dSTrent Jaeger if (copy_to_user_sec_ctx(xp, skb)) 1129df71837dSTrent Jaeger goto nlmsg_failure; 1130f7b6983fSMasahide NAKAMURA if (copy_to_user_policy_type(xp, skb) < 0) 1131f7b6983fSMasahide NAKAMURA goto nlmsg_failure; 11321da177e4SLinus Torvalds 11331da177e4SLinus Torvalds nlh->nlmsg_len = skb->tail - b; 11341da177e4SLinus Torvalds out: 11351da177e4SLinus Torvalds sp->this_idx++; 11361da177e4SLinus Torvalds return 0; 11371da177e4SLinus Torvalds 11381da177e4SLinus Torvalds nlmsg_failure: 11391da177e4SLinus Torvalds skb_trim(skb, b - skb->data); 11401da177e4SLinus Torvalds return -1; 11411da177e4SLinus Torvalds } 11421da177e4SLinus Torvalds 11431da177e4SLinus Torvalds static int xfrm_dump_policy(struct sk_buff *skb, struct netlink_callback *cb) 11441da177e4SLinus Torvalds { 11451da177e4SLinus Torvalds struct xfrm_dump_info info; 11461da177e4SLinus Torvalds 11471da177e4SLinus Torvalds info.in_skb = cb->skb; 11481da177e4SLinus Torvalds info.out_skb = skb; 11491da177e4SLinus Torvalds info.nlmsg_seq = cb->nlh->nlmsg_seq; 11501da177e4SLinus Torvalds info.nlmsg_flags = NLM_F_MULTI; 11511da177e4SLinus Torvalds info.this_idx = 0; 11521da177e4SLinus Torvalds info.start_idx = cb->args[0]; 1153f7b6983fSMasahide NAKAMURA (void) xfrm_policy_walk(XFRM_POLICY_TYPE_MAIN, dump_one_policy, &info); 1154f7b6983fSMasahide NAKAMURA #ifdef CONFIG_XFRM_SUB_POLICY 1155f7b6983fSMasahide NAKAMURA (void) xfrm_policy_walk(XFRM_POLICY_TYPE_SUB, dump_one_policy, &info); 1156f7b6983fSMasahide NAKAMURA #endif 11571da177e4SLinus Torvalds cb->args[0] = info.this_idx; 11581da177e4SLinus Torvalds 11591da177e4SLinus Torvalds return skb->len; 11601da177e4SLinus Torvalds } 11611da177e4SLinus Torvalds 11621da177e4SLinus Torvalds static struct sk_buff *xfrm_policy_netlink(struct sk_buff *in_skb, 11631da177e4SLinus Torvalds struct xfrm_policy *xp, 11641da177e4SLinus Torvalds int dir, u32 seq) 11651da177e4SLinus Torvalds { 11661da177e4SLinus Torvalds struct xfrm_dump_info info; 11671da177e4SLinus Torvalds struct sk_buff *skb; 11681da177e4SLinus Torvalds 11691da177e4SLinus Torvalds skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL); 11701da177e4SLinus Torvalds if (!skb) 11711da177e4SLinus Torvalds return ERR_PTR(-ENOMEM); 11721da177e4SLinus Torvalds 11731da177e4SLinus Torvalds NETLINK_CB(skb).dst_pid = NETLINK_CB(in_skb).pid; 11741da177e4SLinus Torvalds info.in_skb = in_skb; 11751da177e4SLinus Torvalds info.out_skb = skb; 11761da177e4SLinus Torvalds info.nlmsg_seq = seq; 11771da177e4SLinus Torvalds info.nlmsg_flags = 0; 11781da177e4SLinus Torvalds info.this_idx = info.start_idx = 0; 11791da177e4SLinus Torvalds 11801da177e4SLinus Torvalds if (dump_one_policy(xp, dir, 0, &info) < 0) { 11811da177e4SLinus Torvalds kfree_skb(skb); 11821da177e4SLinus Torvalds return NULL; 11831da177e4SLinus Torvalds } 11841da177e4SLinus Torvalds 11851da177e4SLinus Torvalds return skb; 11861da177e4SLinus Torvalds } 11871da177e4SLinus Torvalds 11881da177e4SLinus Torvalds static int xfrm_get_policy(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma) 11891da177e4SLinus Torvalds { 11901da177e4SLinus Torvalds struct xfrm_policy *xp; 11911da177e4SLinus Torvalds struct xfrm_userpolicy_id *p; 1192f7b6983fSMasahide NAKAMURA __u8 type = XFRM_POLICY_TYPE_MAIN; 11931da177e4SLinus Torvalds int err; 119426b15dadSJamal Hadi Salim struct km_event c; 11951da177e4SLinus Torvalds int delete; 11961da177e4SLinus Torvalds 11971da177e4SLinus Torvalds p = NLMSG_DATA(nlh); 11981da177e4SLinus Torvalds delete = nlh->nlmsg_type == XFRM_MSG_DELPOLICY; 11991da177e4SLinus Torvalds 1200f7b6983fSMasahide NAKAMURA err = copy_from_user_policy_type(&type, (struct rtattr **)xfrma); 1201f7b6983fSMasahide NAKAMURA if (err) 1202f7b6983fSMasahide NAKAMURA return err; 1203f7b6983fSMasahide NAKAMURA 12041da177e4SLinus Torvalds err = verify_policy_dir(p->dir); 12051da177e4SLinus Torvalds if (err) 12061da177e4SLinus Torvalds return err; 12071da177e4SLinus Torvalds 12081da177e4SLinus Torvalds if (p->index) 1209f7b6983fSMasahide NAKAMURA xp = xfrm_policy_byid(type, p->dir, p->index, delete); 1210df71837dSTrent Jaeger else { 1211df71837dSTrent Jaeger struct rtattr **rtattrs = (struct rtattr **)xfrma; 1212df71837dSTrent Jaeger struct rtattr *rt = rtattrs[XFRMA_SEC_CTX-1]; 1213df71837dSTrent Jaeger struct xfrm_policy tmp; 1214df71837dSTrent Jaeger 1215df71837dSTrent Jaeger err = verify_sec_ctx_len(rtattrs); 1216df71837dSTrent Jaeger if (err) 1217df71837dSTrent Jaeger return err; 1218df71837dSTrent Jaeger 1219df71837dSTrent Jaeger memset(&tmp, 0, sizeof(struct xfrm_policy)); 1220df71837dSTrent Jaeger if (rt) { 1221df71837dSTrent Jaeger struct xfrm_user_sec_ctx *uctx = RTA_DATA(rt); 1222df71837dSTrent Jaeger 1223df71837dSTrent Jaeger if ((err = security_xfrm_policy_alloc(&tmp, uctx))) 1224df71837dSTrent Jaeger return err; 1225df71837dSTrent Jaeger } 1226f7b6983fSMasahide NAKAMURA xp = xfrm_policy_bysel_ctx(type, p->dir, &p->sel, tmp.security, delete); 1227df71837dSTrent Jaeger security_xfrm_policy_free(&tmp); 1228df71837dSTrent Jaeger } 12291da177e4SLinus Torvalds if (xp == NULL) 12301da177e4SLinus Torvalds return -ENOENT; 12311da177e4SLinus Torvalds 12321da177e4SLinus Torvalds if (!delete) { 12331da177e4SLinus Torvalds struct sk_buff *resp_skb; 12341da177e4SLinus Torvalds 12351da177e4SLinus Torvalds resp_skb = xfrm_policy_netlink(skb, xp, p->dir, nlh->nlmsg_seq); 12361da177e4SLinus Torvalds if (IS_ERR(resp_skb)) { 12371da177e4SLinus Torvalds err = PTR_ERR(resp_skb); 12381da177e4SLinus Torvalds } else { 12391da177e4SLinus Torvalds err = netlink_unicast(xfrm_nl, resp_skb, 12401da177e4SLinus Torvalds NETLINK_CB(skb).pid, 12411da177e4SLinus Torvalds MSG_DONTWAIT); 12421da177e4SLinus Torvalds } 124326b15dadSJamal Hadi Salim } else { 12446f68dc37SDavid S. Miller if ((err = security_xfrm_policy_delete(xp)) != 0) 1245c8c05a8eSCatherine Zhang goto out; 1246e7443892SHerbert Xu c.data.byid = p->index; 1247f60f6b8fSHerbert Xu c.event = nlh->nlmsg_type; 124826b15dadSJamal Hadi Salim c.seq = nlh->nlmsg_seq; 124926b15dadSJamal Hadi Salim c.pid = nlh->nlmsg_pid; 125026b15dadSJamal Hadi Salim km_policy_notify(xp, p->dir, &c); 12511da177e4SLinus Torvalds } 12521da177e4SLinus Torvalds 12531da177e4SLinus Torvalds xfrm_pol_put(xp); 12541da177e4SLinus Torvalds 1255c8c05a8eSCatherine Zhang out: 12561da177e4SLinus Torvalds return err; 12571da177e4SLinus Torvalds } 12581da177e4SLinus Torvalds 12591da177e4SLinus Torvalds static int xfrm_flush_sa(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma) 12601da177e4SLinus Torvalds { 126126b15dadSJamal Hadi Salim struct km_event c; 12621da177e4SLinus Torvalds struct xfrm_usersa_flush *p = NLMSG_DATA(nlh); 12631da177e4SLinus Torvalds 12641da177e4SLinus Torvalds xfrm_state_flush(p->proto); 1265bf08867fSHerbert Xu c.data.proto = p->proto; 1266f60f6b8fSHerbert Xu c.event = nlh->nlmsg_type; 126726b15dadSJamal Hadi Salim c.seq = nlh->nlmsg_seq; 126826b15dadSJamal Hadi Salim c.pid = nlh->nlmsg_pid; 126926b15dadSJamal Hadi Salim km_state_notify(NULL, &c); 127026b15dadSJamal Hadi Salim 12711da177e4SLinus Torvalds return 0; 12721da177e4SLinus Torvalds } 12731da177e4SLinus Torvalds 1274d51d081dSJamal Hadi Salim 1275d51d081dSJamal Hadi Salim static int build_aevent(struct sk_buff *skb, struct xfrm_state *x, struct km_event *c) 1276d51d081dSJamal Hadi Salim { 1277d51d081dSJamal Hadi Salim struct xfrm_aevent_id *id; 1278d51d081dSJamal Hadi Salim struct nlmsghdr *nlh; 1279d51d081dSJamal Hadi Salim struct xfrm_lifetime_cur ltime; 1280d51d081dSJamal Hadi Salim unsigned char *b = skb->tail; 1281d51d081dSJamal Hadi Salim 1282d51d081dSJamal Hadi Salim nlh = NLMSG_PUT(skb, c->pid, c->seq, XFRM_MSG_NEWAE, sizeof(*id)); 1283d51d081dSJamal Hadi Salim id = NLMSG_DATA(nlh); 1284d51d081dSJamal Hadi Salim nlh->nlmsg_flags = 0; 1285d51d081dSJamal Hadi Salim 1286d51d081dSJamal Hadi Salim id->sa_id.daddr = x->id.daddr; 1287d51d081dSJamal Hadi Salim id->sa_id.spi = x->id.spi; 1288d51d081dSJamal Hadi Salim id->sa_id.family = x->props.family; 1289d51d081dSJamal Hadi Salim id->sa_id.proto = x->id.proto; 1290d51d081dSJamal Hadi Salim id->flags = c->data.aevent; 1291d51d081dSJamal Hadi Salim 1292d51d081dSJamal Hadi Salim RTA_PUT(skb, XFRMA_REPLAY_VAL, sizeof(x->replay), &x->replay); 1293d51d081dSJamal Hadi Salim 1294d51d081dSJamal Hadi Salim ltime.bytes = x->curlft.bytes; 1295d51d081dSJamal Hadi Salim ltime.packets = x->curlft.packets; 1296d51d081dSJamal Hadi Salim ltime.add_time = x->curlft.add_time; 1297d51d081dSJamal Hadi Salim ltime.use_time = x->curlft.use_time; 1298d51d081dSJamal Hadi Salim 1299d51d081dSJamal Hadi Salim RTA_PUT(skb, XFRMA_LTIME_VAL, sizeof(struct xfrm_lifetime_cur), <ime); 1300d51d081dSJamal Hadi Salim 1301d51d081dSJamal Hadi Salim if (id->flags&XFRM_AE_RTHR) { 1302d51d081dSJamal Hadi Salim RTA_PUT(skb,XFRMA_REPLAY_THRESH,sizeof(u32),&x->replay_maxdiff); 1303d51d081dSJamal Hadi Salim } 1304d51d081dSJamal Hadi Salim 1305d51d081dSJamal Hadi Salim if (id->flags&XFRM_AE_ETHR) { 1306d51d081dSJamal Hadi Salim u32 etimer = x->replay_maxage*10/HZ; 1307d51d081dSJamal Hadi Salim RTA_PUT(skb,XFRMA_ETIMER_THRESH,sizeof(u32),&etimer); 1308d51d081dSJamal Hadi Salim } 1309d51d081dSJamal Hadi Salim 1310d51d081dSJamal Hadi Salim nlh->nlmsg_len = skb->tail - b; 1311d51d081dSJamal Hadi Salim return skb->len; 1312d51d081dSJamal Hadi Salim 1313d51d081dSJamal Hadi Salim rtattr_failure: 1314d51d081dSJamal Hadi Salim nlmsg_failure: 1315d51d081dSJamal Hadi Salim skb_trim(skb, b - skb->data); 1316d51d081dSJamal Hadi Salim return -1; 1317d51d081dSJamal Hadi Salim } 1318d51d081dSJamal Hadi Salim 1319d51d081dSJamal Hadi Salim static int xfrm_get_ae(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma) 1320d51d081dSJamal Hadi Salim { 1321d51d081dSJamal Hadi Salim struct xfrm_state *x; 1322d51d081dSJamal Hadi Salim struct sk_buff *r_skb; 1323d51d081dSJamal Hadi Salim int err; 1324d51d081dSJamal Hadi Salim struct km_event c; 1325d51d081dSJamal Hadi Salim struct xfrm_aevent_id *p = NLMSG_DATA(nlh); 1326d51d081dSJamal Hadi Salim int len = NLMSG_LENGTH(sizeof(struct xfrm_aevent_id)); 1327d51d081dSJamal Hadi Salim struct xfrm_usersa_id *id = &p->sa_id; 1328d51d081dSJamal Hadi Salim 1329d51d081dSJamal Hadi Salim len += RTA_SPACE(sizeof(struct xfrm_replay_state)); 1330d51d081dSJamal Hadi Salim len += RTA_SPACE(sizeof(struct xfrm_lifetime_cur)); 1331d51d081dSJamal Hadi Salim 1332d51d081dSJamal Hadi Salim if (p->flags&XFRM_AE_RTHR) 1333d51d081dSJamal Hadi Salim len+=RTA_SPACE(sizeof(u32)); 1334d51d081dSJamal Hadi Salim 1335d51d081dSJamal Hadi Salim if (p->flags&XFRM_AE_ETHR) 1336d51d081dSJamal Hadi Salim len+=RTA_SPACE(sizeof(u32)); 1337d51d081dSJamal Hadi Salim 1338d51d081dSJamal Hadi Salim r_skb = alloc_skb(len, GFP_ATOMIC); 1339d51d081dSJamal Hadi Salim if (r_skb == NULL) 1340d51d081dSJamal Hadi Salim return -ENOMEM; 1341d51d081dSJamal Hadi Salim 1342d51d081dSJamal Hadi Salim x = xfrm_state_lookup(&id->daddr, id->spi, id->proto, id->family); 1343d51d081dSJamal Hadi Salim if (x == NULL) { 1344d51d081dSJamal Hadi Salim kfree(r_skb); 1345d51d081dSJamal Hadi Salim return -ESRCH; 1346d51d081dSJamal Hadi Salim } 1347d51d081dSJamal Hadi Salim 1348d51d081dSJamal Hadi Salim /* 1349d51d081dSJamal Hadi Salim * XXX: is this lock really needed - none of the other 1350d51d081dSJamal Hadi Salim * gets lock (the concern is things getting updated 1351d51d081dSJamal Hadi Salim * while we are still reading) - jhs 1352d51d081dSJamal Hadi Salim */ 1353d51d081dSJamal Hadi Salim spin_lock_bh(&x->lock); 1354d51d081dSJamal Hadi Salim c.data.aevent = p->flags; 1355d51d081dSJamal Hadi Salim c.seq = nlh->nlmsg_seq; 1356d51d081dSJamal Hadi Salim c.pid = nlh->nlmsg_pid; 1357d51d081dSJamal Hadi Salim 1358d51d081dSJamal Hadi Salim if (build_aevent(r_skb, x, &c) < 0) 1359d51d081dSJamal Hadi Salim BUG(); 1360d51d081dSJamal Hadi Salim err = netlink_unicast(xfrm_nl, r_skb, 1361d51d081dSJamal Hadi Salim NETLINK_CB(skb).pid, MSG_DONTWAIT); 1362d51d081dSJamal Hadi Salim spin_unlock_bh(&x->lock); 1363d51d081dSJamal Hadi Salim xfrm_state_put(x); 1364d51d081dSJamal Hadi Salim return err; 1365d51d081dSJamal Hadi Salim } 1366d51d081dSJamal Hadi Salim 1367d51d081dSJamal Hadi Salim static int xfrm_new_ae(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma) 1368d51d081dSJamal Hadi Salim { 1369d51d081dSJamal Hadi Salim struct xfrm_state *x; 1370d51d081dSJamal Hadi Salim struct km_event c; 1371d51d081dSJamal Hadi Salim int err = - EINVAL; 1372d51d081dSJamal Hadi Salim struct xfrm_aevent_id *p = NLMSG_DATA(nlh); 1373d51d081dSJamal Hadi Salim struct rtattr *rp = xfrma[XFRMA_REPLAY_VAL-1]; 1374d51d081dSJamal Hadi Salim struct rtattr *lt = xfrma[XFRMA_LTIME_VAL-1]; 1375d51d081dSJamal Hadi Salim 1376d51d081dSJamal Hadi Salim if (!lt && !rp) 1377d51d081dSJamal Hadi Salim return err; 1378d51d081dSJamal Hadi Salim 1379d51d081dSJamal Hadi Salim /* pedantic mode - thou shalt sayeth replaceth */ 1380d51d081dSJamal Hadi Salim if (!(nlh->nlmsg_flags&NLM_F_REPLACE)) 1381d51d081dSJamal Hadi Salim return err; 1382d51d081dSJamal Hadi Salim 1383d51d081dSJamal Hadi Salim x = xfrm_state_lookup(&p->sa_id.daddr, p->sa_id.spi, p->sa_id.proto, p->sa_id.family); 1384d51d081dSJamal Hadi Salim if (x == NULL) 1385d51d081dSJamal Hadi Salim return -ESRCH; 1386d51d081dSJamal Hadi Salim 1387d51d081dSJamal Hadi Salim if (x->km.state != XFRM_STATE_VALID) 1388d51d081dSJamal Hadi Salim goto out; 1389d51d081dSJamal Hadi Salim 1390d51d081dSJamal Hadi Salim spin_lock_bh(&x->lock); 1391d51d081dSJamal Hadi Salim err = xfrm_update_ae_params(x,(struct rtattr **)xfrma); 1392d51d081dSJamal Hadi Salim spin_unlock_bh(&x->lock); 1393d51d081dSJamal Hadi Salim if (err < 0) 1394d51d081dSJamal Hadi Salim goto out; 1395d51d081dSJamal Hadi Salim 1396d51d081dSJamal Hadi Salim c.event = nlh->nlmsg_type; 1397d51d081dSJamal Hadi Salim c.seq = nlh->nlmsg_seq; 1398d51d081dSJamal Hadi Salim c.pid = nlh->nlmsg_pid; 1399d51d081dSJamal Hadi Salim c.data.aevent = XFRM_AE_CU; 1400d51d081dSJamal Hadi Salim km_state_notify(x, &c); 1401d51d081dSJamal Hadi Salim err = 0; 1402d51d081dSJamal Hadi Salim out: 1403d51d081dSJamal Hadi Salim xfrm_state_put(x); 1404d51d081dSJamal Hadi Salim return err; 1405d51d081dSJamal Hadi Salim } 1406d51d081dSJamal Hadi Salim 14071da177e4SLinus Torvalds static int xfrm_flush_policy(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma) 14081da177e4SLinus Torvalds { 140926b15dadSJamal Hadi Salim struct km_event c; 1410f7b6983fSMasahide NAKAMURA __u8 type = XFRM_POLICY_TYPE_MAIN; 1411f7b6983fSMasahide NAKAMURA int err; 141226b15dadSJamal Hadi Salim 1413f7b6983fSMasahide NAKAMURA err = copy_from_user_policy_type(&type, (struct rtattr **)xfrma); 1414f7b6983fSMasahide NAKAMURA if (err) 1415f7b6983fSMasahide NAKAMURA return err; 1416f7b6983fSMasahide NAKAMURA 1417f7b6983fSMasahide NAKAMURA xfrm_policy_flush(type); 1418f7b6983fSMasahide NAKAMURA c.data.type = type; 1419f60f6b8fSHerbert Xu c.event = nlh->nlmsg_type; 142026b15dadSJamal Hadi Salim c.seq = nlh->nlmsg_seq; 142126b15dadSJamal Hadi Salim c.pid = nlh->nlmsg_pid; 142226b15dadSJamal Hadi Salim km_policy_notify(NULL, 0, &c); 14231da177e4SLinus Torvalds return 0; 14241da177e4SLinus Torvalds } 14251da177e4SLinus Torvalds 14266c5c8ca7SJamal Hadi Salim static int xfrm_add_pol_expire(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma) 14276c5c8ca7SJamal Hadi Salim { 14286c5c8ca7SJamal Hadi Salim struct xfrm_policy *xp; 14296c5c8ca7SJamal Hadi Salim struct xfrm_user_polexpire *up = NLMSG_DATA(nlh); 14306c5c8ca7SJamal Hadi Salim struct xfrm_userpolicy_info *p = &up->pol; 1431f7b6983fSMasahide NAKAMURA __u8 type = XFRM_POLICY_TYPE_MAIN; 14326c5c8ca7SJamal Hadi Salim int err = -ENOENT; 14336c5c8ca7SJamal Hadi Salim 1434f7b6983fSMasahide NAKAMURA err = copy_from_user_policy_type(&type, (struct rtattr **)xfrma); 1435f7b6983fSMasahide NAKAMURA if (err) 1436f7b6983fSMasahide NAKAMURA return err; 1437f7b6983fSMasahide NAKAMURA 14386c5c8ca7SJamal Hadi Salim if (p->index) 1439f7b6983fSMasahide NAKAMURA xp = xfrm_policy_byid(type, p->dir, p->index, 0); 14406c5c8ca7SJamal Hadi Salim else { 14416c5c8ca7SJamal Hadi Salim struct rtattr **rtattrs = (struct rtattr **)xfrma; 14426c5c8ca7SJamal Hadi Salim struct rtattr *rt = rtattrs[XFRMA_SEC_CTX-1]; 14436c5c8ca7SJamal Hadi Salim struct xfrm_policy tmp; 14446c5c8ca7SJamal Hadi Salim 14456c5c8ca7SJamal Hadi Salim err = verify_sec_ctx_len(rtattrs); 14466c5c8ca7SJamal Hadi Salim if (err) 14476c5c8ca7SJamal Hadi Salim return err; 14486c5c8ca7SJamal Hadi Salim 14496c5c8ca7SJamal Hadi Salim memset(&tmp, 0, sizeof(struct xfrm_policy)); 14506c5c8ca7SJamal Hadi Salim if (rt) { 14516c5c8ca7SJamal Hadi Salim struct xfrm_user_sec_ctx *uctx = RTA_DATA(rt); 14526c5c8ca7SJamal Hadi Salim 14536c5c8ca7SJamal Hadi Salim if ((err = security_xfrm_policy_alloc(&tmp, uctx))) 14546c5c8ca7SJamal Hadi Salim return err; 14556c5c8ca7SJamal Hadi Salim } 1456f7b6983fSMasahide NAKAMURA xp = xfrm_policy_bysel_ctx(type, p->dir, &p->sel, tmp.security, 0); 14576c5c8ca7SJamal Hadi Salim security_xfrm_policy_free(&tmp); 14586c5c8ca7SJamal Hadi Salim } 14596c5c8ca7SJamal Hadi Salim 14606c5c8ca7SJamal Hadi Salim if (xp == NULL) 14616c5c8ca7SJamal Hadi Salim return err; 14626c5c8ca7SJamal Hadi Salim read_lock(&xp->lock); 14636c5c8ca7SJamal Hadi Salim if (xp->dead) { 14646c5c8ca7SJamal Hadi Salim read_unlock(&xp->lock); 14656c5c8ca7SJamal Hadi Salim goto out; 14666c5c8ca7SJamal Hadi Salim } 14676c5c8ca7SJamal Hadi Salim 14686c5c8ca7SJamal Hadi Salim read_unlock(&xp->lock); 14696c5c8ca7SJamal Hadi Salim err = 0; 14706c5c8ca7SJamal Hadi Salim if (up->hard) { 14716c5c8ca7SJamal Hadi Salim xfrm_policy_delete(xp, p->dir); 14726c5c8ca7SJamal Hadi Salim } else { 14736c5c8ca7SJamal Hadi Salim // reset the timers here? 14746c5c8ca7SJamal Hadi Salim printk("Dont know what to do with soft policy expire\n"); 14756c5c8ca7SJamal Hadi Salim } 14766c5c8ca7SJamal Hadi Salim km_policy_expired(xp, p->dir, up->hard, current->pid); 14776c5c8ca7SJamal Hadi Salim 14786c5c8ca7SJamal Hadi Salim out: 14796c5c8ca7SJamal Hadi Salim xfrm_pol_put(xp); 14806c5c8ca7SJamal Hadi Salim return err; 14816c5c8ca7SJamal Hadi Salim } 14826c5c8ca7SJamal Hadi Salim 148353bc6b4dSJamal Hadi Salim static int xfrm_add_sa_expire(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma) 148453bc6b4dSJamal Hadi Salim { 148553bc6b4dSJamal Hadi Salim struct xfrm_state *x; 148653bc6b4dSJamal Hadi Salim int err; 148753bc6b4dSJamal Hadi Salim struct xfrm_user_expire *ue = NLMSG_DATA(nlh); 148853bc6b4dSJamal Hadi Salim struct xfrm_usersa_info *p = &ue->state; 148953bc6b4dSJamal Hadi Salim 149053bc6b4dSJamal Hadi Salim x = xfrm_state_lookup(&p->id.daddr, p->id.spi, p->id.proto, p->family); 149153bc6b4dSJamal Hadi Salim err = -ENOENT; 149253bc6b4dSJamal Hadi Salim 149353bc6b4dSJamal Hadi Salim if (x == NULL) 149453bc6b4dSJamal Hadi Salim return err; 149553bc6b4dSJamal Hadi Salim 149653bc6b4dSJamal Hadi Salim err = -EINVAL; 149753bc6b4dSJamal Hadi Salim 149853bc6b4dSJamal Hadi Salim spin_lock_bh(&x->lock); 149953bc6b4dSJamal Hadi Salim if (x->km.state != XFRM_STATE_VALID) 150053bc6b4dSJamal Hadi Salim goto out; 150153bc6b4dSJamal Hadi Salim km_state_expired(x, ue->hard, current->pid); 150253bc6b4dSJamal Hadi Salim 150353bc6b4dSJamal Hadi Salim if (ue->hard) 150453bc6b4dSJamal Hadi Salim __xfrm_state_delete(x); 150553bc6b4dSJamal Hadi Salim out: 150653bc6b4dSJamal Hadi Salim spin_unlock_bh(&x->lock); 150753bc6b4dSJamal Hadi Salim xfrm_state_put(x); 150853bc6b4dSJamal Hadi Salim return err; 150953bc6b4dSJamal Hadi Salim } 151053bc6b4dSJamal Hadi Salim 1511980ebd25SJamal Hadi Salim static int xfrm_add_acquire(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma) 1512980ebd25SJamal Hadi Salim { 1513980ebd25SJamal Hadi Salim struct xfrm_policy *xp; 1514980ebd25SJamal Hadi Salim struct xfrm_user_tmpl *ut; 1515980ebd25SJamal Hadi Salim int i; 1516980ebd25SJamal Hadi Salim struct rtattr *rt = xfrma[XFRMA_TMPL-1]; 1517980ebd25SJamal Hadi Salim 1518980ebd25SJamal Hadi Salim struct xfrm_user_acquire *ua = NLMSG_DATA(nlh); 1519980ebd25SJamal Hadi Salim struct xfrm_state *x = xfrm_state_alloc(); 1520980ebd25SJamal Hadi Salim int err = -ENOMEM; 1521980ebd25SJamal Hadi Salim 1522980ebd25SJamal Hadi Salim if (!x) 1523980ebd25SJamal Hadi Salim return err; 1524980ebd25SJamal Hadi Salim 1525980ebd25SJamal Hadi Salim err = verify_newpolicy_info(&ua->policy); 1526980ebd25SJamal Hadi Salim if (err) { 1527980ebd25SJamal Hadi Salim printk("BAD policy passed\n"); 1528980ebd25SJamal Hadi Salim kfree(x); 1529980ebd25SJamal Hadi Salim return err; 1530980ebd25SJamal Hadi Salim } 1531980ebd25SJamal Hadi Salim 1532980ebd25SJamal Hadi Salim /* build an XP */ 1533980ebd25SJamal Hadi Salim xp = xfrm_policy_construct(&ua->policy, (struct rtattr **) xfrma, &err); if (!xp) { 1534980ebd25SJamal Hadi Salim kfree(x); 1535980ebd25SJamal Hadi Salim return err; 1536980ebd25SJamal Hadi Salim } 1537980ebd25SJamal Hadi Salim 1538980ebd25SJamal Hadi Salim memcpy(&x->id, &ua->id, sizeof(ua->id)); 1539980ebd25SJamal Hadi Salim memcpy(&x->props.saddr, &ua->saddr, sizeof(ua->saddr)); 1540980ebd25SJamal Hadi Salim memcpy(&x->sel, &ua->sel, sizeof(ua->sel)); 1541980ebd25SJamal Hadi Salim 1542980ebd25SJamal Hadi Salim ut = RTA_DATA(rt); 1543980ebd25SJamal Hadi Salim /* extract the templates and for each call km_key */ 1544980ebd25SJamal Hadi Salim for (i = 0; i < xp->xfrm_nr; i++, ut++) { 1545980ebd25SJamal Hadi Salim struct xfrm_tmpl *t = &xp->xfrm_vec[i]; 1546980ebd25SJamal Hadi Salim memcpy(&x->id, &t->id, sizeof(x->id)); 1547980ebd25SJamal Hadi Salim x->props.mode = t->mode; 1548980ebd25SJamal Hadi Salim x->props.reqid = t->reqid; 1549980ebd25SJamal Hadi Salim x->props.family = ut->family; 1550980ebd25SJamal Hadi Salim t->aalgos = ua->aalgos; 1551980ebd25SJamal Hadi Salim t->ealgos = ua->ealgos; 1552980ebd25SJamal Hadi Salim t->calgos = ua->calgos; 1553980ebd25SJamal Hadi Salim err = km_query(x, t, xp); 1554980ebd25SJamal Hadi Salim 1555980ebd25SJamal Hadi Salim } 1556980ebd25SJamal Hadi Salim 1557980ebd25SJamal Hadi Salim kfree(x); 1558980ebd25SJamal Hadi Salim kfree(xp); 1559980ebd25SJamal Hadi Salim 1560980ebd25SJamal Hadi Salim return 0; 1561980ebd25SJamal Hadi Salim } 1562980ebd25SJamal Hadi Salim 1563d51d081dSJamal Hadi Salim 1564492b558bSThomas Graf #define XMSGSIZE(type) NLMSG_LENGTH(sizeof(struct type)) 1565492b558bSThomas Graf 1566492b558bSThomas Graf static const int xfrm_msg_min[XFRM_NR_MSGTYPES] = { 1567492b558bSThomas Graf [XFRM_MSG_NEWSA - XFRM_MSG_BASE] = XMSGSIZE(xfrm_usersa_info), 1568492b558bSThomas Graf [XFRM_MSG_DELSA - XFRM_MSG_BASE] = XMSGSIZE(xfrm_usersa_id), 1569492b558bSThomas Graf [XFRM_MSG_GETSA - XFRM_MSG_BASE] = XMSGSIZE(xfrm_usersa_id), 1570492b558bSThomas Graf [XFRM_MSG_NEWPOLICY - XFRM_MSG_BASE] = XMSGSIZE(xfrm_userpolicy_info), 1571492b558bSThomas Graf [XFRM_MSG_DELPOLICY - XFRM_MSG_BASE] = XMSGSIZE(xfrm_userpolicy_id), 1572492b558bSThomas Graf [XFRM_MSG_GETPOLICY - XFRM_MSG_BASE] = XMSGSIZE(xfrm_userpolicy_id), 1573492b558bSThomas Graf [XFRM_MSG_ALLOCSPI - XFRM_MSG_BASE] = XMSGSIZE(xfrm_userspi_info), 1574980ebd25SJamal Hadi Salim [XFRM_MSG_ACQUIRE - XFRM_MSG_BASE] = XMSGSIZE(xfrm_user_acquire), 157553bc6b4dSJamal Hadi Salim [XFRM_MSG_EXPIRE - XFRM_MSG_BASE] = XMSGSIZE(xfrm_user_expire), 1576492b558bSThomas Graf [XFRM_MSG_UPDPOLICY - XFRM_MSG_BASE] = XMSGSIZE(xfrm_userpolicy_info), 1577492b558bSThomas Graf [XFRM_MSG_UPDSA - XFRM_MSG_BASE] = XMSGSIZE(xfrm_usersa_info), 15786c5c8ca7SJamal Hadi Salim [XFRM_MSG_POLEXPIRE - XFRM_MSG_BASE] = XMSGSIZE(xfrm_user_polexpire), 1579492b558bSThomas Graf [XFRM_MSG_FLUSHSA - XFRM_MSG_BASE] = XMSGSIZE(xfrm_usersa_flush), 1580492b558bSThomas Graf [XFRM_MSG_FLUSHPOLICY - XFRM_MSG_BASE] = NLMSG_LENGTH(0), 1581d51d081dSJamal Hadi Salim [XFRM_MSG_NEWAE - XFRM_MSG_BASE] = XMSGSIZE(xfrm_aevent_id), 1582d51d081dSJamal Hadi Salim [XFRM_MSG_GETAE - XFRM_MSG_BASE] = XMSGSIZE(xfrm_aevent_id), 158397a64b45SMasahide NAKAMURA [XFRM_MSG_REPORT - XFRM_MSG_BASE] = XMSGSIZE(xfrm_user_report), 15841da177e4SLinus Torvalds }; 15851da177e4SLinus Torvalds 1586492b558bSThomas Graf #undef XMSGSIZE 1587492b558bSThomas Graf 15881da177e4SLinus Torvalds static struct xfrm_link { 15891da177e4SLinus Torvalds int (*doit)(struct sk_buff *, struct nlmsghdr *, void **); 15901da177e4SLinus Torvalds int (*dump)(struct sk_buff *, struct netlink_callback *); 1591492b558bSThomas Graf } xfrm_dispatch[XFRM_NR_MSGTYPES] = { 1592492b558bSThomas Graf [XFRM_MSG_NEWSA - XFRM_MSG_BASE] = { .doit = xfrm_add_sa }, 1593492b558bSThomas Graf [XFRM_MSG_DELSA - XFRM_MSG_BASE] = { .doit = xfrm_del_sa }, 1594492b558bSThomas Graf [XFRM_MSG_GETSA - XFRM_MSG_BASE] = { .doit = xfrm_get_sa, 1595492b558bSThomas Graf .dump = xfrm_dump_sa }, 1596492b558bSThomas Graf [XFRM_MSG_NEWPOLICY - XFRM_MSG_BASE] = { .doit = xfrm_add_policy }, 1597492b558bSThomas Graf [XFRM_MSG_DELPOLICY - XFRM_MSG_BASE] = { .doit = xfrm_get_policy }, 1598492b558bSThomas Graf [XFRM_MSG_GETPOLICY - XFRM_MSG_BASE] = { .doit = xfrm_get_policy, 1599492b558bSThomas Graf .dump = xfrm_dump_policy }, 1600492b558bSThomas Graf [XFRM_MSG_ALLOCSPI - XFRM_MSG_BASE] = { .doit = xfrm_alloc_userspi }, 1601980ebd25SJamal Hadi Salim [XFRM_MSG_ACQUIRE - XFRM_MSG_BASE] = { .doit = xfrm_add_acquire }, 160253bc6b4dSJamal Hadi Salim [XFRM_MSG_EXPIRE - XFRM_MSG_BASE] = { .doit = xfrm_add_sa_expire }, 1603492b558bSThomas Graf [XFRM_MSG_UPDPOLICY - XFRM_MSG_BASE] = { .doit = xfrm_add_policy }, 1604492b558bSThomas Graf [XFRM_MSG_UPDSA - XFRM_MSG_BASE] = { .doit = xfrm_add_sa }, 16056c5c8ca7SJamal Hadi Salim [XFRM_MSG_POLEXPIRE - XFRM_MSG_BASE] = { .doit = xfrm_add_pol_expire}, 1606492b558bSThomas Graf [XFRM_MSG_FLUSHSA - XFRM_MSG_BASE] = { .doit = xfrm_flush_sa }, 1607492b558bSThomas Graf [XFRM_MSG_FLUSHPOLICY - XFRM_MSG_BASE] = { .doit = xfrm_flush_policy }, 1608d51d081dSJamal Hadi Salim [XFRM_MSG_NEWAE - XFRM_MSG_BASE] = { .doit = xfrm_new_ae }, 1609d51d081dSJamal Hadi Salim [XFRM_MSG_GETAE - XFRM_MSG_BASE] = { .doit = xfrm_get_ae }, 16101da177e4SLinus Torvalds }; 16111da177e4SLinus Torvalds 16121da177e4SLinus Torvalds static int xfrm_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, int *errp) 16131da177e4SLinus Torvalds { 16141da177e4SLinus Torvalds struct rtattr *xfrma[XFRMA_MAX]; 16151da177e4SLinus Torvalds struct xfrm_link *link; 16161da177e4SLinus Torvalds int type, min_len; 16171da177e4SLinus Torvalds 16181da177e4SLinus Torvalds if (!(nlh->nlmsg_flags & NLM_F_REQUEST)) 16191da177e4SLinus Torvalds return 0; 16201da177e4SLinus Torvalds 16211da177e4SLinus Torvalds type = nlh->nlmsg_type; 16221da177e4SLinus Torvalds 16231da177e4SLinus Torvalds /* A control message: ignore them */ 16241da177e4SLinus Torvalds if (type < XFRM_MSG_BASE) 16251da177e4SLinus Torvalds return 0; 16261da177e4SLinus Torvalds 16271da177e4SLinus Torvalds /* Unknown message: reply with EINVAL */ 16281da177e4SLinus Torvalds if (type > XFRM_MSG_MAX) 16291da177e4SLinus Torvalds goto err_einval; 16301da177e4SLinus Torvalds 16311da177e4SLinus Torvalds type -= XFRM_MSG_BASE; 16321da177e4SLinus Torvalds link = &xfrm_dispatch[type]; 16331da177e4SLinus Torvalds 16341da177e4SLinus Torvalds /* All operations require privileges, even GET */ 1635c7bdb545SDarrel Goeddel if (security_netlink_recv(skb, CAP_NET_ADMIN)) { 16361da177e4SLinus Torvalds *errp = -EPERM; 16371da177e4SLinus Torvalds return -1; 16381da177e4SLinus Torvalds } 16391da177e4SLinus Torvalds 1640492b558bSThomas Graf if ((type == (XFRM_MSG_GETSA - XFRM_MSG_BASE) || 1641492b558bSThomas Graf type == (XFRM_MSG_GETPOLICY - XFRM_MSG_BASE)) && 1642492b558bSThomas Graf (nlh->nlmsg_flags & NLM_F_DUMP)) { 16431da177e4SLinus Torvalds if (link->dump == NULL) 16441da177e4SLinus Torvalds goto err_einval; 16451da177e4SLinus Torvalds 16461da177e4SLinus Torvalds if ((*errp = netlink_dump_start(xfrm_nl, skb, nlh, 1647a8f74b22SThomas Graf link->dump, NULL)) != 0) { 16481da177e4SLinus Torvalds return -1; 16491da177e4SLinus Torvalds } 165088fc2c84SThomas Graf 165188fc2c84SThomas Graf netlink_queue_skip(nlh, skb); 16521da177e4SLinus Torvalds return -1; 16531da177e4SLinus Torvalds } 16541da177e4SLinus Torvalds 16551da177e4SLinus Torvalds memset(xfrma, 0, sizeof(xfrma)); 16561da177e4SLinus Torvalds 16571da177e4SLinus Torvalds if (nlh->nlmsg_len < (min_len = xfrm_msg_min[type])) 16581da177e4SLinus Torvalds goto err_einval; 16591da177e4SLinus Torvalds 16601da177e4SLinus Torvalds if (nlh->nlmsg_len > min_len) { 16611da177e4SLinus Torvalds int attrlen = nlh->nlmsg_len - NLMSG_ALIGN(min_len); 16621da177e4SLinus Torvalds struct rtattr *attr = (void *) nlh + NLMSG_ALIGN(min_len); 16631da177e4SLinus Torvalds 16641da177e4SLinus Torvalds while (RTA_OK(attr, attrlen)) { 16651da177e4SLinus Torvalds unsigned short flavor = attr->rta_type; 16661da177e4SLinus Torvalds if (flavor) { 16671da177e4SLinus Torvalds if (flavor > XFRMA_MAX) 16681da177e4SLinus Torvalds goto err_einval; 16691da177e4SLinus Torvalds xfrma[flavor - 1] = attr; 16701da177e4SLinus Torvalds } 16711da177e4SLinus Torvalds attr = RTA_NEXT(attr, attrlen); 16721da177e4SLinus Torvalds } 16731da177e4SLinus Torvalds } 16741da177e4SLinus Torvalds 16751da177e4SLinus Torvalds if (link->doit == NULL) 16761da177e4SLinus Torvalds goto err_einval; 16771da177e4SLinus Torvalds *errp = link->doit(skb, nlh, (void **) &xfrma); 16781da177e4SLinus Torvalds 16791da177e4SLinus Torvalds return *errp; 16801da177e4SLinus Torvalds 16811da177e4SLinus Torvalds err_einval: 16821da177e4SLinus Torvalds *errp = -EINVAL; 16831da177e4SLinus Torvalds return -1; 16841da177e4SLinus Torvalds } 16851da177e4SLinus Torvalds 16861da177e4SLinus Torvalds static void xfrm_netlink_rcv(struct sock *sk, int len) 16871da177e4SLinus Torvalds { 168888fc2c84SThomas Graf unsigned int qlen = 0; 16892a0a6ebeSHerbert Xu 16901da177e4SLinus Torvalds do { 16914a3e2f71SArjan van de Ven mutex_lock(&xfrm_cfg_mutex); 169288fc2c84SThomas Graf netlink_run_queue(sk, &qlen, &xfrm_user_rcv_msg); 16934a3e2f71SArjan van de Ven mutex_unlock(&xfrm_cfg_mutex); 16941da177e4SLinus Torvalds 16952a0a6ebeSHerbert Xu } while (qlen); 16961da177e4SLinus Torvalds } 16971da177e4SLinus Torvalds 1698d51d081dSJamal Hadi Salim static int build_expire(struct sk_buff *skb, struct xfrm_state *x, struct km_event *c) 16991da177e4SLinus Torvalds { 17001da177e4SLinus Torvalds struct xfrm_user_expire *ue; 17011da177e4SLinus Torvalds struct nlmsghdr *nlh; 17021da177e4SLinus Torvalds unsigned char *b = skb->tail; 17031da177e4SLinus Torvalds 1704d51d081dSJamal Hadi Salim nlh = NLMSG_PUT(skb, c->pid, 0, XFRM_MSG_EXPIRE, 17051da177e4SLinus Torvalds sizeof(*ue)); 17061da177e4SLinus Torvalds ue = NLMSG_DATA(nlh); 17071da177e4SLinus Torvalds nlh->nlmsg_flags = 0; 17081da177e4SLinus Torvalds 17091da177e4SLinus Torvalds copy_to_user_state(x, &ue->state); 1710d51d081dSJamal Hadi Salim ue->hard = (c->data.hard != 0) ? 1 : 0; 17111da177e4SLinus Torvalds 17121da177e4SLinus Torvalds nlh->nlmsg_len = skb->tail - b; 17131da177e4SLinus Torvalds return skb->len; 17141da177e4SLinus Torvalds 17151da177e4SLinus Torvalds nlmsg_failure: 17161da177e4SLinus Torvalds skb_trim(skb, b - skb->data); 17171da177e4SLinus Torvalds return -1; 17181da177e4SLinus Torvalds } 17191da177e4SLinus Torvalds 172026b15dadSJamal Hadi Salim static int xfrm_exp_state_notify(struct xfrm_state *x, struct km_event *c) 17211da177e4SLinus Torvalds { 17221da177e4SLinus Torvalds struct sk_buff *skb; 1723ee57eef9SJamal Hadi Salim int len = NLMSG_LENGTH(sizeof(struct xfrm_user_expire)); 17241da177e4SLinus Torvalds 1725ee57eef9SJamal Hadi Salim skb = alloc_skb(len, GFP_ATOMIC); 17261da177e4SLinus Torvalds if (skb == NULL) 17271da177e4SLinus Torvalds return -ENOMEM; 17281da177e4SLinus Torvalds 1729d51d081dSJamal Hadi Salim if (build_expire(skb, x, c) < 0) 17301da177e4SLinus Torvalds BUG(); 17311da177e4SLinus Torvalds 1732ac6d439dSPatrick McHardy NETLINK_CB(skb).dst_group = XFRMNLGRP_EXPIRE; 1733ac6d439dSPatrick McHardy return netlink_broadcast(xfrm_nl, skb, 0, XFRMNLGRP_EXPIRE, GFP_ATOMIC); 17341da177e4SLinus Torvalds } 17351da177e4SLinus Torvalds 1736d51d081dSJamal Hadi Salim static int xfrm_aevent_state_notify(struct xfrm_state *x, struct km_event *c) 1737d51d081dSJamal Hadi Salim { 1738d51d081dSJamal Hadi Salim struct sk_buff *skb; 1739d51d081dSJamal Hadi Salim int len = NLMSG_LENGTH(sizeof(struct xfrm_aevent_id)); 1740d51d081dSJamal Hadi Salim 1741d51d081dSJamal Hadi Salim len += RTA_SPACE(sizeof(struct xfrm_replay_state)); 1742d51d081dSJamal Hadi Salim len += RTA_SPACE(sizeof(struct xfrm_lifetime_cur)); 1743d51d081dSJamal Hadi Salim skb = alloc_skb(len, GFP_ATOMIC); 1744d51d081dSJamal Hadi Salim if (skb == NULL) 1745d51d081dSJamal Hadi Salim return -ENOMEM; 1746d51d081dSJamal Hadi Salim 1747d51d081dSJamal Hadi Salim if (build_aevent(skb, x, c) < 0) 1748d51d081dSJamal Hadi Salim BUG(); 1749d51d081dSJamal Hadi Salim 1750d51d081dSJamal Hadi Salim NETLINK_CB(skb).dst_group = XFRMNLGRP_AEVENTS; 1751d51d081dSJamal Hadi Salim return netlink_broadcast(xfrm_nl, skb, 0, XFRMNLGRP_AEVENTS, GFP_ATOMIC); 1752d51d081dSJamal Hadi Salim } 1753d51d081dSJamal Hadi Salim 175426b15dadSJamal Hadi Salim static int xfrm_notify_sa_flush(struct km_event *c) 175526b15dadSJamal Hadi Salim { 175626b15dadSJamal Hadi Salim struct xfrm_usersa_flush *p; 175726b15dadSJamal Hadi Salim struct nlmsghdr *nlh; 175826b15dadSJamal Hadi Salim struct sk_buff *skb; 175926b15dadSJamal Hadi Salim unsigned char *b; 176026b15dadSJamal Hadi Salim int len = NLMSG_LENGTH(sizeof(struct xfrm_usersa_flush)); 176126b15dadSJamal Hadi Salim 176226b15dadSJamal Hadi Salim skb = alloc_skb(len, GFP_ATOMIC); 176326b15dadSJamal Hadi Salim if (skb == NULL) 176426b15dadSJamal Hadi Salim return -ENOMEM; 176526b15dadSJamal Hadi Salim b = skb->tail; 176626b15dadSJamal Hadi Salim 176726b15dadSJamal Hadi Salim nlh = NLMSG_PUT(skb, c->pid, c->seq, 176826b15dadSJamal Hadi Salim XFRM_MSG_FLUSHSA, sizeof(*p)); 176926b15dadSJamal Hadi Salim nlh->nlmsg_flags = 0; 177026b15dadSJamal Hadi Salim 177126b15dadSJamal Hadi Salim p = NLMSG_DATA(nlh); 1772bf08867fSHerbert Xu p->proto = c->data.proto; 177326b15dadSJamal Hadi Salim 177426b15dadSJamal Hadi Salim nlh->nlmsg_len = skb->tail - b; 177526b15dadSJamal Hadi Salim 1776ac6d439dSPatrick McHardy NETLINK_CB(skb).dst_group = XFRMNLGRP_SA; 1777ac6d439dSPatrick McHardy return netlink_broadcast(xfrm_nl, skb, 0, XFRMNLGRP_SA, GFP_ATOMIC); 177826b15dadSJamal Hadi Salim 177926b15dadSJamal Hadi Salim nlmsg_failure: 178026b15dadSJamal Hadi Salim kfree_skb(skb); 178126b15dadSJamal Hadi Salim return -1; 178226b15dadSJamal Hadi Salim } 178326b15dadSJamal Hadi Salim 178426b15dadSJamal Hadi Salim static int inline xfrm_sa_len(struct xfrm_state *x) 178526b15dadSJamal Hadi Salim { 17860603eac0SHerbert Xu int l = 0; 178726b15dadSJamal Hadi Salim if (x->aalg) 178826b15dadSJamal Hadi Salim l += RTA_SPACE(sizeof(*x->aalg) + (x->aalg->alg_key_len+7)/8); 178926b15dadSJamal Hadi Salim if (x->ealg) 179026b15dadSJamal Hadi Salim l += RTA_SPACE(sizeof(*x->ealg) + (x->ealg->alg_key_len+7)/8); 179126b15dadSJamal Hadi Salim if (x->calg) 179226b15dadSJamal Hadi Salim l += RTA_SPACE(sizeof(*x->calg)); 179326b15dadSJamal Hadi Salim if (x->encap) 179426b15dadSJamal Hadi Salim l += RTA_SPACE(sizeof(*x->encap)); 179526b15dadSJamal Hadi Salim 179626b15dadSJamal Hadi Salim return l; 179726b15dadSJamal Hadi Salim } 179826b15dadSJamal Hadi Salim 179926b15dadSJamal Hadi Salim static int xfrm_notify_sa(struct xfrm_state *x, struct km_event *c) 180026b15dadSJamal Hadi Salim { 180126b15dadSJamal Hadi Salim struct xfrm_usersa_info *p; 18020603eac0SHerbert Xu struct xfrm_usersa_id *id; 180326b15dadSJamal Hadi Salim struct nlmsghdr *nlh; 180426b15dadSJamal Hadi Salim struct sk_buff *skb; 180526b15dadSJamal Hadi Salim unsigned char *b; 180626b15dadSJamal Hadi Salim int len = xfrm_sa_len(x); 18070603eac0SHerbert Xu int headlen; 18080603eac0SHerbert Xu 18090603eac0SHerbert Xu headlen = sizeof(*p); 18100603eac0SHerbert Xu if (c->event == XFRM_MSG_DELSA) { 18110603eac0SHerbert Xu len += RTA_SPACE(headlen); 18120603eac0SHerbert Xu headlen = sizeof(*id); 18130603eac0SHerbert Xu } 18140603eac0SHerbert Xu len += NLMSG_SPACE(headlen); 181526b15dadSJamal Hadi Salim 181626b15dadSJamal Hadi Salim skb = alloc_skb(len, GFP_ATOMIC); 181726b15dadSJamal Hadi Salim if (skb == NULL) 181826b15dadSJamal Hadi Salim return -ENOMEM; 181926b15dadSJamal Hadi Salim b = skb->tail; 182026b15dadSJamal Hadi Salim 18210603eac0SHerbert Xu nlh = NLMSG_PUT(skb, c->pid, c->seq, c->event, headlen); 182226b15dadSJamal Hadi Salim nlh->nlmsg_flags = 0; 182326b15dadSJamal Hadi Salim 182426b15dadSJamal Hadi Salim p = NLMSG_DATA(nlh); 18250603eac0SHerbert Xu if (c->event == XFRM_MSG_DELSA) { 18260603eac0SHerbert Xu id = NLMSG_DATA(nlh); 18270603eac0SHerbert Xu memcpy(&id->daddr, &x->id.daddr, sizeof(id->daddr)); 18280603eac0SHerbert Xu id->spi = x->id.spi; 18290603eac0SHerbert Xu id->family = x->props.family; 18300603eac0SHerbert Xu id->proto = x->id.proto; 18310603eac0SHerbert Xu 18320603eac0SHerbert Xu p = RTA_DATA(__RTA_PUT(skb, XFRMA_SA, sizeof(*p))); 18330603eac0SHerbert Xu } 18340603eac0SHerbert Xu 183526b15dadSJamal Hadi Salim copy_to_user_state(x, p); 183626b15dadSJamal Hadi Salim 183726b15dadSJamal Hadi Salim if (x->aalg) 183826b15dadSJamal Hadi Salim RTA_PUT(skb, XFRMA_ALG_AUTH, 183926b15dadSJamal Hadi Salim sizeof(*(x->aalg))+(x->aalg->alg_key_len+7)/8, x->aalg); 184026b15dadSJamal Hadi Salim if (x->ealg) 184126b15dadSJamal Hadi Salim RTA_PUT(skb, XFRMA_ALG_CRYPT, 184226b15dadSJamal Hadi Salim sizeof(*(x->ealg))+(x->ealg->alg_key_len+7)/8, x->ealg); 184326b15dadSJamal Hadi Salim if (x->calg) 184426b15dadSJamal Hadi Salim RTA_PUT(skb, XFRMA_ALG_COMP, sizeof(*(x->calg)), x->calg); 184526b15dadSJamal Hadi Salim 184626b15dadSJamal Hadi Salim if (x->encap) 184726b15dadSJamal Hadi Salim RTA_PUT(skb, XFRMA_ENCAP, sizeof(*x->encap), x->encap); 184826b15dadSJamal Hadi Salim 184926b15dadSJamal Hadi Salim nlh->nlmsg_len = skb->tail - b; 185026b15dadSJamal Hadi Salim 1851ac6d439dSPatrick McHardy NETLINK_CB(skb).dst_group = XFRMNLGRP_SA; 1852ac6d439dSPatrick McHardy return netlink_broadcast(xfrm_nl, skb, 0, XFRMNLGRP_SA, GFP_ATOMIC); 185326b15dadSJamal Hadi Salim 185426b15dadSJamal Hadi Salim nlmsg_failure: 185526b15dadSJamal Hadi Salim rtattr_failure: 185626b15dadSJamal Hadi Salim kfree_skb(skb); 185726b15dadSJamal Hadi Salim return -1; 185826b15dadSJamal Hadi Salim } 185926b15dadSJamal Hadi Salim 186026b15dadSJamal Hadi Salim static int xfrm_send_state_notify(struct xfrm_state *x, struct km_event *c) 186126b15dadSJamal Hadi Salim { 186226b15dadSJamal Hadi Salim 186326b15dadSJamal Hadi Salim switch (c->event) { 1864f60f6b8fSHerbert Xu case XFRM_MSG_EXPIRE: 186526b15dadSJamal Hadi Salim return xfrm_exp_state_notify(x, c); 1866d51d081dSJamal Hadi Salim case XFRM_MSG_NEWAE: 1867d51d081dSJamal Hadi Salim return xfrm_aevent_state_notify(x, c); 1868f60f6b8fSHerbert Xu case XFRM_MSG_DELSA: 1869f60f6b8fSHerbert Xu case XFRM_MSG_UPDSA: 1870f60f6b8fSHerbert Xu case XFRM_MSG_NEWSA: 187126b15dadSJamal Hadi Salim return xfrm_notify_sa(x, c); 1872f60f6b8fSHerbert Xu case XFRM_MSG_FLUSHSA: 187326b15dadSJamal Hadi Salim return xfrm_notify_sa_flush(c); 187426b15dadSJamal Hadi Salim default: 187526b15dadSJamal Hadi Salim printk("xfrm_user: Unknown SA event %d\n", c->event); 187626b15dadSJamal Hadi Salim break; 187726b15dadSJamal Hadi Salim } 187826b15dadSJamal Hadi Salim 187926b15dadSJamal Hadi Salim return 0; 188026b15dadSJamal Hadi Salim 188126b15dadSJamal Hadi Salim } 188226b15dadSJamal Hadi Salim 18831da177e4SLinus Torvalds static int build_acquire(struct sk_buff *skb, struct xfrm_state *x, 18841da177e4SLinus Torvalds struct xfrm_tmpl *xt, struct xfrm_policy *xp, 18851da177e4SLinus Torvalds int dir) 18861da177e4SLinus Torvalds { 18871da177e4SLinus Torvalds struct xfrm_user_acquire *ua; 18881da177e4SLinus Torvalds struct nlmsghdr *nlh; 18891da177e4SLinus Torvalds unsigned char *b = skb->tail; 18901da177e4SLinus Torvalds __u32 seq = xfrm_get_acqseq(); 18911da177e4SLinus Torvalds 18921da177e4SLinus Torvalds nlh = NLMSG_PUT(skb, 0, 0, XFRM_MSG_ACQUIRE, 18931da177e4SLinus Torvalds sizeof(*ua)); 18941da177e4SLinus Torvalds ua = NLMSG_DATA(nlh); 18951da177e4SLinus Torvalds nlh->nlmsg_flags = 0; 18961da177e4SLinus Torvalds 18971da177e4SLinus Torvalds memcpy(&ua->id, &x->id, sizeof(ua->id)); 18981da177e4SLinus Torvalds memcpy(&ua->saddr, &x->props.saddr, sizeof(ua->saddr)); 18991da177e4SLinus Torvalds memcpy(&ua->sel, &x->sel, sizeof(ua->sel)); 19001da177e4SLinus Torvalds copy_to_user_policy(xp, &ua->policy, dir); 19011da177e4SLinus Torvalds ua->aalgos = xt->aalgos; 19021da177e4SLinus Torvalds ua->ealgos = xt->ealgos; 19031da177e4SLinus Torvalds ua->calgos = xt->calgos; 19041da177e4SLinus Torvalds ua->seq = x->km.seq = seq; 19051da177e4SLinus Torvalds 19061da177e4SLinus Torvalds if (copy_to_user_tmpl(xp, skb) < 0) 19071da177e4SLinus Torvalds goto nlmsg_failure; 19080d681623SSerge Hallyn if (copy_to_user_state_sec_ctx(x, skb)) 1909df71837dSTrent Jaeger goto nlmsg_failure; 1910f7b6983fSMasahide NAKAMURA if (copy_to_user_policy_type(xp, skb) < 0) 1911f7b6983fSMasahide NAKAMURA goto nlmsg_failure; 19121da177e4SLinus Torvalds 19131da177e4SLinus Torvalds nlh->nlmsg_len = skb->tail - b; 19141da177e4SLinus Torvalds return skb->len; 19151da177e4SLinus Torvalds 19161da177e4SLinus Torvalds nlmsg_failure: 19171da177e4SLinus Torvalds skb_trim(skb, b - skb->data); 19181da177e4SLinus Torvalds return -1; 19191da177e4SLinus Torvalds } 19201da177e4SLinus Torvalds 19211da177e4SLinus Torvalds static int xfrm_send_acquire(struct xfrm_state *x, struct xfrm_tmpl *xt, 19221da177e4SLinus Torvalds struct xfrm_policy *xp, int dir) 19231da177e4SLinus Torvalds { 19241da177e4SLinus Torvalds struct sk_buff *skb; 19251da177e4SLinus Torvalds size_t len; 19261da177e4SLinus Torvalds 19271da177e4SLinus Torvalds len = RTA_SPACE(sizeof(struct xfrm_user_tmpl) * xp->xfrm_nr); 19281da177e4SLinus Torvalds len += NLMSG_SPACE(sizeof(struct xfrm_user_acquire)); 1929df71837dSTrent Jaeger len += RTA_SPACE(xfrm_user_sec_ctx_size(xp)); 19301da177e4SLinus Torvalds skb = alloc_skb(len, GFP_ATOMIC); 19311da177e4SLinus Torvalds if (skb == NULL) 19321da177e4SLinus Torvalds return -ENOMEM; 19331da177e4SLinus Torvalds 19341da177e4SLinus Torvalds if (build_acquire(skb, x, xt, xp, dir) < 0) 19351da177e4SLinus Torvalds BUG(); 19361da177e4SLinus Torvalds 1937ac6d439dSPatrick McHardy NETLINK_CB(skb).dst_group = XFRMNLGRP_ACQUIRE; 1938ac6d439dSPatrick McHardy return netlink_broadcast(xfrm_nl, skb, 0, XFRMNLGRP_ACQUIRE, GFP_ATOMIC); 19391da177e4SLinus Torvalds } 19401da177e4SLinus Torvalds 19411da177e4SLinus Torvalds /* User gives us xfrm_user_policy_info followed by an array of 0 19421da177e4SLinus Torvalds * or more templates. 19431da177e4SLinus Torvalds */ 1944cb969f07SVenkat Yekkirala static struct xfrm_policy *xfrm_compile_policy(struct sock *sk, int opt, 19451da177e4SLinus Torvalds u8 *data, int len, int *dir) 19461da177e4SLinus Torvalds { 19471da177e4SLinus Torvalds struct xfrm_userpolicy_info *p = (struct xfrm_userpolicy_info *)data; 19481da177e4SLinus Torvalds struct xfrm_user_tmpl *ut = (struct xfrm_user_tmpl *) (p + 1); 19491da177e4SLinus Torvalds struct xfrm_policy *xp; 19501da177e4SLinus Torvalds int nr; 19511da177e4SLinus Torvalds 1952cb969f07SVenkat Yekkirala switch (sk->sk_family) { 19531da177e4SLinus Torvalds case AF_INET: 19541da177e4SLinus Torvalds if (opt != IP_XFRM_POLICY) { 19551da177e4SLinus Torvalds *dir = -EOPNOTSUPP; 19561da177e4SLinus Torvalds return NULL; 19571da177e4SLinus Torvalds } 19581da177e4SLinus Torvalds break; 19591da177e4SLinus Torvalds #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 19601da177e4SLinus Torvalds case AF_INET6: 19611da177e4SLinus Torvalds if (opt != IPV6_XFRM_POLICY) { 19621da177e4SLinus Torvalds *dir = -EOPNOTSUPP; 19631da177e4SLinus Torvalds return NULL; 19641da177e4SLinus Torvalds } 19651da177e4SLinus Torvalds break; 19661da177e4SLinus Torvalds #endif 19671da177e4SLinus Torvalds default: 19681da177e4SLinus Torvalds *dir = -EINVAL; 19691da177e4SLinus Torvalds return NULL; 19701da177e4SLinus Torvalds } 19711da177e4SLinus Torvalds 19721da177e4SLinus Torvalds *dir = -EINVAL; 19731da177e4SLinus Torvalds 19741da177e4SLinus Torvalds if (len < sizeof(*p) || 19751da177e4SLinus Torvalds verify_newpolicy_info(p)) 19761da177e4SLinus Torvalds return NULL; 19771da177e4SLinus Torvalds 19781da177e4SLinus Torvalds nr = ((len - sizeof(*p)) / sizeof(*ut)); 19791da177e4SLinus Torvalds if (nr > XFRM_MAX_DEPTH) 19801da177e4SLinus Torvalds return NULL; 19811da177e4SLinus Torvalds 1982a4f1bac6SHerbert Xu if (p->dir > XFRM_POLICY_OUT) 1983a4f1bac6SHerbert Xu return NULL; 1984a4f1bac6SHerbert Xu 19851da177e4SLinus Torvalds xp = xfrm_policy_alloc(GFP_KERNEL); 19861da177e4SLinus Torvalds if (xp == NULL) { 19871da177e4SLinus Torvalds *dir = -ENOBUFS; 19881da177e4SLinus Torvalds return NULL; 19891da177e4SLinus Torvalds } 19901da177e4SLinus Torvalds 19911da177e4SLinus Torvalds copy_from_user_policy(xp, p); 1992f7b6983fSMasahide NAKAMURA xp->type = XFRM_POLICY_TYPE_MAIN; 19931da177e4SLinus Torvalds copy_templates(xp, ut, nr); 19941da177e4SLinus Torvalds 1995cb969f07SVenkat Yekkirala if (!xp->security) { 1996cb969f07SVenkat Yekkirala int err = security_xfrm_sock_policy_alloc(xp, sk); 1997cb969f07SVenkat Yekkirala if (err) { 1998cb969f07SVenkat Yekkirala kfree(xp); 1999cb969f07SVenkat Yekkirala *dir = err; 2000cb969f07SVenkat Yekkirala return NULL; 2001cb969f07SVenkat Yekkirala } 2002cb969f07SVenkat Yekkirala } 2003cb969f07SVenkat Yekkirala 20041da177e4SLinus Torvalds *dir = p->dir; 20051da177e4SLinus Torvalds 20061da177e4SLinus Torvalds return xp; 20071da177e4SLinus Torvalds } 20081da177e4SLinus Torvalds 20091da177e4SLinus Torvalds static int build_polexpire(struct sk_buff *skb, struct xfrm_policy *xp, 2010d51d081dSJamal Hadi Salim int dir, struct km_event *c) 20111da177e4SLinus Torvalds { 20121da177e4SLinus Torvalds struct xfrm_user_polexpire *upe; 20131da177e4SLinus Torvalds struct nlmsghdr *nlh; 2014d51d081dSJamal Hadi Salim int hard = c->data.hard; 20151da177e4SLinus Torvalds unsigned char *b = skb->tail; 20161da177e4SLinus Torvalds 2017d51d081dSJamal Hadi Salim nlh = NLMSG_PUT(skb, c->pid, 0, XFRM_MSG_POLEXPIRE, sizeof(*upe)); 20181da177e4SLinus Torvalds upe = NLMSG_DATA(nlh); 20191da177e4SLinus Torvalds nlh->nlmsg_flags = 0; 20201da177e4SLinus Torvalds 20211da177e4SLinus Torvalds copy_to_user_policy(xp, &upe->pol, dir); 20221da177e4SLinus Torvalds if (copy_to_user_tmpl(xp, skb) < 0) 20231da177e4SLinus Torvalds goto nlmsg_failure; 2024df71837dSTrent Jaeger if (copy_to_user_sec_ctx(xp, skb)) 2025df71837dSTrent Jaeger goto nlmsg_failure; 2026f7b6983fSMasahide NAKAMURA if (copy_to_user_policy_type(xp, skb) < 0) 2027f7b6983fSMasahide NAKAMURA goto nlmsg_failure; 20281da177e4SLinus Torvalds upe->hard = !!hard; 20291da177e4SLinus Torvalds 20301da177e4SLinus Torvalds nlh->nlmsg_len = skb->tail - b; 20311da177e4SLinus Torvalds return skb->len; 20321da177e4SLinus Torvalds 20331da177e4SLinus Torvalds nlmsg_failure: 20341da177e4SLinus Torvalds skb_trim(skb, b - skb->data); 20351da177e4SLinus Torvalds return -1; 20361da177e4SLinus Torvalds } 20371da177e4SLinus Torvalds 203826b15dadSJamal Hadi Salim static int xfrm_exp_policy_notify(struct xfrm_policy *xp, int dir, struct km_event *c) 20391da177e4SLinus Torvalds { 20401da177e4SLinus Torvalds struct sk_buff *skb; 20411da177e4SLinus Torvalds size_t len; 20421da177e4SLinus Torvalds 20431da177e4SLinus Torvalds len = RTA_SPACE(sizeof(struct xfrm_user_tmpl) * xp->xfrm_nr); 20441da177e4SLinus Torvalds len += NLMSG_SPACE(sizeof(struct xfrm_user_polexpire)); 2045df71837dSTrent Jaeger len += RTA_SPACE(xfrm_user_sec_ctx_size(xp)); 20461da177e4SLinus Torvalds skb = alloc_skb(len, GFP_ATOMIC); 20471da177e4SLinus Torvalds if (skb == NULL) 20481da177e4SLinus Torvalds return -ENOMEM; 20491da177e4SLinus Torvalds 2050d51d081dSJamal Hadi Salim if (build_polexpire(skb, xp, dir, c) < 0) 20511da177e4SLinus Torvalds BUG(); 20521da177e4SLinus Torvalds 2053ac6d439dSPatrick McHardy NETLINK_CB(skb).dst_group = XFRMNLGRP_EXPIRE; 2054ac6d439dSPatrick McHardy return netlink_broadcast(xfrm_nl, skb, 0, XFRMNLGRP_EXPIRE, GFP_ATOMIC); 20551da177e4SLinus Torvalds } 20561da177e4SLinus Torvalds 205726b15dadSJamal Hadi Salim static int xfrm_notify_policy(struct xfrm_policy *xp, int dir, struct km_event *c) 205826b15dadSJamal Hadi Salim { 205926b15dadSJamal Hadi Salim struct xfrm_userpolicy_info *p; 20600603eac0SHerbert Xu struct xfrm_userpolicy_id *id; 206126b15dadSJamal Hadi Salim struct nlmsghdr *nlh; 206226b15dadSJamal Hadi Salim struct sk_buff *skb; 206326b15dadSJamal Hadi Salim unsigned char *b; 206426b15dadSJamal Hadi Salim int len = RTA_SPACE(sizeof(struct xfrm_user_tmpl) * xp->xfrm_nr); 20650603eac0SHerbert Xu int headlen; 20660603eac0SHerbert Xu 20670603eac0SHerbert Xu headlen = sizeof(*p); 20680603eac0SHerbert Xu if (c->event == XFRM_MSG_DELPOLICY) { 20690603eac0SHerbert Xu len += RTA_SPACE(headlen); 20700603eac0SHerbert Xu headlen = sizeof(*id); 20710603eac0SHerbert Xu } 20720603eac0SHerbert Xu len += NLMSG_SPACE(headlen); 207326b15dadSJamal Hadi Salim 207426b15dadSJamal Hadi Salim skb = alloc_skb(len, GFP_ATOMIC); 207526b15dadSJamal Hadi Salim if (skb == NULL) 207626b15dadSJamal Hadi Salim return -ENOMEM; 207726b15dadSJamal Hadi Salim b = skb->tail; 207826b15dadSJamal Hadi Salim 20790603eac0SHerbert Xu nlh = NLMSG_PUT(skb, c->pid, c->seq, c->event, headlen); 208026b15dadSJamal Hadi Salim 208126b15dadSJamal Hadi Salim p = NLMSG_DATA(nlh); 20820603eac0SHerbert Xu if (c->event == XFRM_MSG_DELPOLICY) { 20830603eac0SHerbert Xu id = NLMSG_DATA(nlh); 20840603eac0SHerbert Xu memset(id, 0, sizeof(*id)); 20850603eac0SHerbert Xu id->dir = dir; 20860603eac0SHerbert Xu if (c->data.byid) 20870603eac0SHerbert Xu id->index = xp->index; 20880603eac0SHerbert Xu else 20890603eac0SHerbert Xu memcpy(&id->sel, &xp->selector, sizeof(id->sel)); 20900603eac0SHerbert Xu 20910603eac0SHerbert Xu p = RTA_DATA(__RTA_PUT(skb, XFRMA_POLICY, sizeof(*p))); 20920603eac0SHerbert Xu } 209326b15dadSJamal Hadi Salim 209426b15dadSJamal Hadi Salim nlh->nlmsg_flags = 0; 209526b15dadSJamal Hadi Salim 209626b15dadSJamal Hadi Salim copy_to_user_policy(xp, p, dir); 209726b15dadSJamal Hadi Salim if (copy_to_user_tmpl(xp, skb) < 0) 209826b15dadSJamal Hadi Salim goto nlmsg_failure; 2099f7b6983fSMasahide NAKAMURA if (copy_to_user_policy_type(xp, skb) < 0) 2100f7b6983fSMasahide NAKAMURA goto nlmsg_failure; 210126b15dadSJamal Hadi Salim 210226b15dadSJamal Hadi Salim nlh->nlmsg_len = skb->tail - b; 210326b15dadSJamal Hadi Salim 2104ac6d439dSPatrick McHardy NETLINK_CB(skb).dst_group = XFRMNLGRP_POLICY; 2105ac6d439dSPatrick McHardy return netlink_broadcast(xfrm_nl, skb, 0, XFRMNLGRP_POLICY, GFP_ATOMIC); 210626b15dadSJamal Hadi Salim 210726b15dadSJamal Hadi Salim nlmsg_failure: 21080603eac0SHerbert Xu rtattr_failure: 210926b15dadSJamal Hadi Salim kfree_skb(skb); 211026b15dadSJamal Hadi Salim return -1; 211126b15dadSJamal Hadi Salim } 211226b15dadSJamal Hadi Salim 211326b15dadSJamal Hadi Salim static int xfrm_notify_policy_flush(struct km_event *c) 211426b15dadSJamal Hadi Salim { 211526b15dadSJamal Hadi Salim struct nlmsghdr *nlh; 211626b15dadSJamal Hadi Salim struct sk_buff *skb; 211726b15dadSJamal Hadi Salim unsigned char *b; 2118f7b6983fSMasahide NAKAMURA #ifdef CONFIG_XFRM_SUB_POLICY 2119f7b6983fSMasahide NAKAMURA struct xfrm_userpolicy_type upt; 2120f7b6983fSMasahide NAKAMURA #endif 212126b15dadSJamal Hadi Salim int len = NLMSG_LENGTH(0); 212226b15dadSJamal Hadi Salim 212326b15dadSJamal Hadi Salim skb = alloc_skb(len, GFP_ATOMIC); 212426b15dadSJamal Hadi Salim if (skb == NULL) 212526b15dadSJamal Hadi Salim return -ENOMEM; 212626b15dadSJamal Hadi Salim b = skb->tail; 212726b15dadSJamal Hadi Salim 212826b15dadSJamal Hadi Salim 212926b15dadSJamal Hadi Salim nlh = NLMSG_PUT(skb, c->pid, c->seq, XFRM_MSG_FLUSHPOLICY, 0); 2130f7b6983fSMasahide NAKAMURA nlh->nlmsg_flags = 0; 2131f7b6983fSMasahide NAKAMURA 2132f7b6983fSMasahide NAKAMURA #ifdef CONFIG_XFRM_SUB_POLICY 2133f7b6983fSMasahide NAKAMURA memset(&upt, 0, sizeof(upt)); 2134f7b6983fSMasahide NAKAMURA upt.type = c->data.type; 2135f7b6983fSMasahide NAKAMURA RTA_PUT(skb, XFRMA_POLICY_TYPE, sizeof(upt), &upt); 2136f7b6983fSMasahide NAKAMURA #endif 213726b15dadSJamal Hadi Salim 213826b15dadSJamal Hadi Salim nlh->nlmsg_len = skb->tail - b; 213926b15dadSJamal Hadi Salim 2140ac6d439dSPatrick McHardy NETLINK_CB(skb).dst_group = XFRMNLGRP_POLICY; 2141ac6d439dSPatrick McHardy return netlink_broadcast(xfrm_nl, skb, 0, XFRMNLGRP_POLICY, GFP_ATOMIC); 214226b15dadSJamal Hadi Salim 214326b15dadSJamal Hadi Salim nlmsg_failure: 2144f7b6983fSMasahide NAKAMURA #ifdef CONFIG_XFRM_SUB_POLICY 2145f7b6983fSMasahide NAKAMURA rtattr_failure: 2146f7b6983fSMasahide NAKAMURA #endif 214726b15dadSJamal Hadi Salim kfree_skb(skb); 214826b15dadSJamal Hadi Salim return -1; 214926b15dadSJamal Hadi Salim } 215026b15dadSJamal Hadi Salim 215126b15dadSJamal Hadi Salim static int xfrm_send_policy_notify(struct xfrm_policy *xp, int dir, struct km_event *c) 215226b15dadSJamal Hadi Salim { 215326b15dadSJamal Hadi Salim 215426b15dadSJamal Hadi Salim switch (c->event) { 2155f60f6b8fSHerbert Xu case XFRM_MSG_NEWPOLICY: 2156f60f6b8fSHerbert Xu case XFRM_MSG_UPDPOLICY: 2157f60f6b8fSHerbert Xu case XFRM_MSG_DELPOLICY: 215826b15dadSJamal Hadi Salim return xfrm_notify_policy(xp, dir, c); 2159f60f6b8fSHerbert Xu case XFRM_MSG_FLUSHPOLICY: 216026b15dadSJamal Hadi Salim return xfrm_notify_policy_flush(c); 2161f60f6b8fSHerbert Xu case XFRM_MSG_POLEXPIRE: 216226b15dadSJamal Hadi Salim return xfrm_exp_policy_notify(xp, dir, c); 216326b15dadSJamal Hadi Salim default: 216426b15dadSJamal Hadi Salim printk("xfrm_user: Unknown Policy event %d\n", c->event); 216526b15dadSJamal Hadi Salim } 216626b15dadSJamal Hadi Salim 216726b15dadSJamal Hadi Salim return 0; 216826b15dadSJamal Hadi Salim 216926b15dadSJamal Hadi Salim } 217026b15dadSJamal Hadi Salim 217197a64b45SMasahide NAKAMURA static int build_report(struct sk_buff *skb, u8 proto, 217297a64b45SMasahide NAKAMURA struct xfrm_selector *sel, xfrm_address_t *addr) 217397a64b45SMasahide NAKAMURA { 217497a64b45SMasahide NAKAMURA struct xfrm_user_report *ur; 217597a64b45SMasahide NAKAMURA struct nlmsghdr *nlh; 217697a64b45SMasahide NAKAMURA unsigned char *b = skb->tail; 217797a64b45SMasahide NAKAMURA 217897a64b45SMasahide NAKAMURA nlh = NLMSG_PUT(skb, 0, 0, XFRM_MSG_REPORT, sizeof(*ur)); 217997a64b45SMasahide NAKAMURA ur = NLMSG_DATA(nlh); 218097a64b45SMasahide NAKAMURA nlh->nlmsg_flags = 0; 218197a64b45SMasahide NAKAMURA 218297a64b45SMasahide NAKAMURA ur->proto = proto; 218397a64b45SMasahide NAKAMURA memcpy(&ur->sel, sel, sizeof(ur->sel)); 218497a64b45SMasahide NAKAMURA 218597a64b45SMasahide NAKAMURA if (addr) 218697a64b45SMasahide NAKAMURA RTA_PUT(skb, XFRMA_COADDR, sizeof(*addr), addr); 218797a64b45SMasahide NAKAMURA 218897a64b45SMasahide NAKAMURA nlh->nlmsg_len = skb->tail - b; 218997a64b45SMasahide NAKAMURA return skb->len; 219097a64b45SMasahide NAKAMURA 219197a64b45SMasahide NAKAMURA nlmsg_failure: 219297a64b45SMasahide NAKAMURA rtattr_failure: 219397a64b45SMasahide NAKAMURA skb_trim(skb, b - skb->data); 219497a64b45SMasahide NAKAMURA return -1; 219597a64b45SMasahide NAKAMURA } 219697a64b45SMasahide NAKAMURA 219797a64b45SMasahide NAKAMURA static int xfrm_send_report(u8 proto, struct xfrm_selector *sel, 219897a64b45SMasahide NAKAMURA xfrm_address_t *addr) 219997a64b45SMasahide NAKAMURA { 220097a64b45SMasahide NAKAMURA struct sk_buff *skb; 220197a64b45SMasahide NAKAMURA size_t len; 220297a64b45SMasahide NAKAMURA 220397a64b45SMasahide NAKAMURA len = NLMSG_ALIGN(NLMSG_LENGTH(sizeof(struct xfrm_user_report))); 220497a64b45SMasahide NAKAMURA skb = alloc_skb(len, GFP_ATOMIC); 220597a64b45SMasahide NAKAMURA if (skb == NULL) 220697a64b45SMasahide NAKAMURA return -ENOMEM; 220797a64b45SMasahide NAKAMURA 220897a64b45SMasahide NAKAMURA if (build_report(skb, proto, sel, addr) < 0) 220997a64b45SMasahide NAKAMURA BUG(); 221097a64b45SMasahide NAKAMURA 221197a64b45SMasahide NAKAMURA NETLINK_CB(skb).dst_group = XFRMNLGRP_REPORT; 221297a64b45SMasahide NAKAMURA return netlink_broadcast(xfrm_nl, skb, 0, XFRMNLGRP_REPORT, GFP_ATOMIC); 221397a64b45SMasahide NAKAMURA } 221497a64b45SMasahide NAKAMURA 22151da177e4SLinus Torvalds static struct xfrm_mgr netlink_mgr = { 22161da177e4SLinus Torvalds .id = "netlink", 22171da177e4SLinus Torvalds .notify = xfrm_send_state_notify, 22181da177e4SLinus Torvalds .acquire = xfrm_send_acquire, 22191da177e4SLinus Torvalds .compile_policy = xfrm_compile_policy, 22201da177e4SLinus Torvalds .notify_policy = xfrm_send_policy_notify, 222197a64b45SMasahide NAKAMURA .report = xfrm_send_report, 22221da177e4SLinus Torvalds }; 22231da177e4SLinus Torvalds 22241da177e4SLinus Torvalds static int __init xfrm_user_init(void) 22251da177e4SLinus Torvalds { 2226be33690dSPatrick McHardy struct sock *nlsk; 2227be33690dSPatrick McHardy 2228654b32c6SMasahide NAKAMURA printk(KERN_INFO "Initializing XFRM netlink socket\n"); 22291da177e4SLinus Torvalds 2230be33690dSPatrick McHardy nlsk = netlink_kernel_create(NETLINK_XFRM, XFRMNLGRP_MAX, 223106628607SPatrick McHardy xfrm_netlink_rcv, THIS_MODULE); 2232be33690dSPatrick McHardy if (nlsk == NULL) 22331da177e4SLinus Torvalds return -ENOMEM; 2234be33690dSPatrick McHardy rcu_assign_pointer(xfrm_nl, nlsk); 22351da177e4SLinus Torvalds 22361da177e4SLinus Torvalds xfrm_register_km(&netlink_mgr); 22371da177e4SLinus Torvalds 22381da177e4SLinus Torvalds return 0; 22391da177e4SLinus Torvalds } 22401da177e4SLinus Torvalds 22411da177e4SLinus Torvalds static void __exit xfrm_user_exit(void) 22421da177e4SLinus Torvalds { 2243be33690dSPatrick McHardy struct sock *nlsk = xfrm_nl; 2244be33690dSPatrick McHardy 22451da177e4SLinus Torvalds xfrm_unregister_km(&netlink_mgr); 2246be33690dSPatrick McHardy rcu_assign_pointer(xfrm_nl, NULL); 2247be33690dSPatrick McHardy synchronize_rcu(); 2248be33690dSPatrick McHardy sock_release(nlsk->sk_socket); 22491da177e4SLinus Torvalds } 22501da177e4SLinus Torvalds 22511da177e4SLinus Torvalds module_init(xfrm_user_init); 22521da177e4SLinus Torvalds module_exit(xfrm_user_exit); 22531da177e4SLinus Torvalds MODULE_LICENSE("GPL"); 22544fdb3bb7SHarald Welte MODULE_ALIAS_NET_PF_PROTO(PF_NETLINK, NETLINK_XFRM); 2255f8cd5488SJamal Hadi Salim 2256